init: 验证robust算法
This commit is contained in:
125
test/lazy_evaulation.py
Normal file
125
test/lazy_evaulation.py
Normal file
@@ -0,0 +1,125 @@
|
||||
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}")
|
||||
Reference in New Issue
Block a user