init: 验证robust算法

This commit is contained in:
mayge
2025-09-15 11:41:55 -04:00
commit dbf0b1ddb4
14 changed files with 14258 additions and 0 deletions

125
test/lazy_evaulation.py Normal file
View 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}")