Files
ovf/test/lazy_evaulation.py
2025-09-15 11:41:55 -04:00

125 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import numpy as np
class PhiBasisIterator:
"""
逐步生成有理正交 (类 Muntz-Laguerre) 基函数 φ_p(s) / (或复对产生两列) 的迭代器。
给定:
s: 标量或数组 (复频率采样点) s = j*2*pi*f
poles: 极点序列 (允许包含复共轭对). 约定:
- 纯实极点按自身顺序出现: a = -alpha (alpha>0)
- 复极点以正虚部在前, 紧跟其共轭: a = -σ + jω, a* = -σ - jω
迭代:
每次 __next__ 返回一个 list:
- 实极点 -> [φ_p(s)]
- 复成对 -> [φ_p^(1)(s), φ_p^(2)(s)]
使用时可把返回列表中函数 append 到总基函数数组中。
说明:
这里实现的公式与用户原始代码意图相同, 但修正了:
1) 原代码 sqrt(2*Re(a)) 在 Re(a)<0 (典型稳定极点) 下产生 NaN, 改为 alpha=-Re(a) >0.
2) 原来在 __next__ 中使用 yield (非法); 改为标准迭代协议返回 list。
3) 复极点的乘积与后续迭代用的累计乘积 product 分开维护。
若需严格匹配论文中“多变量正交化”可再加数值正交 (QR) 步骤。
注意:
本实现假设 poles 已排序; 若不确定, 可预处理把正虚部极点放在其共轭之前。
"""
def __init__(self, s, poles):
self.s = np.asarray(s, dtype=complex) # (Nf,) 或标量
self.poles = list(poles)
self.k = 0 # 当前处理到第 k 个极点(或复对的首元素)
self.N = len(self.poles)
# 累计乘积 Π_{已完成的块} ( (s - a_i*)/(s + a_i) ) (复对时使用 (s - a)(s - a*) / (s + a)(s + a*))
self.product = np.ones_like(self.s, dtype=complex)
def __iter__(self):
return self
def __next__(self):
if self.k >= self.N:
raise StopIteration
a = self.poles[self.k]
# 复对: 需要检查正虚部并且下一个是共轭
if np.iscomplex(a) and np.imag(a) > 0:
if self.k + 1 >= self.N or not np.isclose(self.poles[self.k + 1], np.conj(a)):
raise ValueError(f"极点序列中复极点 {a} 未紧跟其共轭, 请排序.")
a_conj = self.poles[self.k + 1]
sigma = -np.real(a) # >0
alpha = sigma
# (s + a)(s + a*) = (s + a)(s + conj(a))
denom = (self.s + a) * (self.s + a_conj)
# |a| 用于生成两组分子 (参考原代码的构造方式)
r = np.abs(a)
scale = np.sqrt(2 * alpha)
numerator1 = scale * (self.s - r)
numerator2 = scale * (self.s + r)
phi1 = numerator1 / denom * self.product
phi2 = numerator2 / denom * self.product
# 更新累计乘积用于后续阶次:
# 对复对的“整体”传统一致写成 ((s - a)(s - a*) / (s + a)(s + a*))
self.product = self.product * ((self.s - a) * (self.s - a_conj)) / denom
self.k += 2
return [phi1, phi2]
else:
# 实极点 (允许传入 float 或实部为负的 complex(实数))
a_real = np.real(a)
# 稳定极点: a_real < 0, 令 alpha = -a_real > 0
if a_real >= 0:
raise ValueError(f"实极点需要在左半平面 (负实部), 得到 {a_real}")
alpha = -a_real
scale = np.sqrt(2 * alpha)
# Laguerre 风格: (s - alpha)/(s + alpha)
numerator = scale * (self.s - alpha)
denom = (self.s + alpha)
phi = numerator / denom * self.product
# 更新累计乘积
self.product = self.product * (self.s - alpha) / (self.s + alpha)
self.k += 1
return [phi]
# ------------------ 辅助函数: 批量生成全部基函数 ------------------
def generate_phi_basis(s, poles):
"""
返回一个 list, 其中包含依次生成的所有基函数 (按 real → 1 函数, complex pair → 2 函数).
"""
basis = []
it = PhiBasisIterator(s, poles)
for block in it:
basis.extend(block)
return basis
# ------------------ 示例与自测 ------------------
if __name__ == "__main__":
# 示例极点: 1 个实极点 (-1), 一个复对 (-2+0.5j, -2-0.5j), 再一个复对 (-3+1.2j, -3-1.2j)
poles = [-0.005+500j, -0.005-500j, -0.012+1200j, -0.012-1200j]
f = np.linspace(1e9, 1e11, 200) # 频率 (Hz)
s = 1j * 2 * np.pi * f
basis_funcs = generate_phi_basis(s, poles)
print(f"生成基函数数量 = {len(basis_funcs)}") # 实极点 1 →1, 两个复对 →2+2 共 5 个
# 简单数值检查 (避免 NaN/Inf)
for i, bf in enumerate(basis_funcs):
if not np.all(np.isfinite(bf)):
print(f"{i} 个基函数存在非有限值")
else:
# print(f"phi[{i}] max|.|={np.max(np.abs(bf)):.3e}, min|.|={np.min(np.abs(bf)):.3e}")
print(f"phi[{i}] = {bf}")
# 验证是否为正交基
for i, bf in enumerate(basis_funcs):
print(f"phi[{i}]*phi[{i}] = {np.vdot(bf, bf)}") # 自身内积
for j in range(i+1, len(basis_funcs)):
bf2 = basis_funcs[j]
ip = np.vdot(bf, bf2)
print(f"phi[{i}] 与 phi[{j}] 内积 = {ip}")
if np.abs(ip) > 1e-6:
print(f"phi[{i}] 与 phi[{j}] 非正交, 内积={ip}")