LLRFLibsPy库中iden_impulse函数解读

source code: Github

这个函数 iden_impulse 用于通过输入输出数据识别系统的脉冲响应。脉冲响应是线性时不变系统的特性函数,描述了系统对脉冲输入的响应。函数通过最小二乘法拟合得到脉冲响应。以下是详细解读:

函数参数

  • U:复数类型的输入波形数组,维度为 (n_wf, N),其中 n_wf 是波形的数量,N 是每个波形的采样点数。
  • Y:复数类型的输出波形数组,维度与 U 相同。
  • order:脉冲响应的阶数,即要识别的脉冲响应的长度。

返回值

  • status:布尔值,表示成功(True)或失败(False)。
  • h:复数类型的脉冲响应数组。

函数逻辑

  1. 输入验证

    • 检查 UY 的形状是否相同,以及 order 是否大于等于 2。如果任意一个条件不满足,返回失败状态和空值。
  2. 获取维度

    • 获取波形的数量 n_wf 和每个波形的采样点数 N
    • 如果 order 大于 N,将 order 设置为 N - 1,因为脉冲响应的阶数不能超过波形的采样点数。
  3. 构造线性方程

    • 初始化矩阵 A 和向量 B,用于最小二乘拟合。A 的维度为 ((N - order) * n_wf, order),B 的维度为 ((N - order) * n_wf)。
    • 通过遍历每个波形,将输入数据 U 和输出数据 Y 填充到矩阵 A 和向量 B 中。
  4. 最小二乘拟合

    • 使用 np.linalg.lstsq 进行最小二乘拟合,求解线性方程 A * h = B,得到脉冲响应 X
  5. 返回结果

    • 返回成功状态和识别出的脉冲响应 X,并将 X 反转顺序。

代码解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def iden_impulse(U, Y, order = 20):
# 检查输入参数的有效性
if (not U.shape == Y.shape) or (order < 2):
return False, None

# 获取波形的数量和每个波形的采样点数
n_wf = U.shape[0]
N = U.shape[1]

# 如果阶数超过采样点数,将阶数设为 N - 1
if order > N:
order = N - 1

# 初始化用于最小二乘拟合的矩阵 A 和向量 B
A = np.zeros(((N - order) * n_wf, order), dtype = complex)
B = np.zeros((N - order) * n_wf, dtype = complex)

# 填充矩阵 A 和向量 B
for k in range(n_wf):
for i in range(N - order):
A[k * (N - order) + i, :] = U[k][i : i + order]
B[k * (N - order) + i] = Y[k][i + order]

# 最小二乘拟合
X = np.linalg.lstsq(A, B, rcond = None)

# 返回识别出的脉冲响应,并将顺序反转
return True, X[0][::-1]

函数用途

这个函数的主要用途是通过实验或仿真的输入输出数据,识别线性系统的脉冲响应。脉冲响应在系统辨识、控制设计和信号处理等领域具有广泛的应用。例如,可以用于射频腔体的脉冲响应识别,以优化控制系统的设计。

示例:脉冲响应识别

假设我们有一个简单的一阶低通滤波器,其脉冲响应为 h[n] = (0.5)^n,我们希望通过输入输出数据来识别出该脉冲响应。

1. 生成输入输出数据

我们使用随机输入信号通过滤波器生成输出信号,来模拟真实的输入输出数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import numpy as np
import matplotlib.pyplot as plt

# 参数设置
order = 20 # 要识别的脉冲响应的阶数
n_wf = 100 # 波形数量
N = 1000 # 每个波形的采样点数

# 生成脉冲响应 h[n] = (0.5)^n
true_h = (0.5) ** np.arange(order)

# 生成输入和输出数据
U = np.random.randn(n_wf, N) + 1j * np.random.randn(n_wf, N)
Y = np.zeros((n_wf, N), dtype=complex)

# 通过滤波器生成输出数据
for i in range(n_wf):
Y[i] = np.convolve(U[i], true_h, mode='same')

# 使用 iden_impulse 函数识别脉冲响应
status, identified_h = iden_impulse(U, Y, order)

# 检查结果并绘制对比图
if status:
plt.figure()
plt.stem(np.abs(true_h), label='True Impulse Response', use_line_collection=True)
plt.stem(np.abs(identified_h), linefmt='r--', markerfmt='ro', label='Identified Impulse Response', use_line_collection=True)
plt.xlabel('Sample')
plt.ylabel('Magnitude')
plt.legend()
plt.grid()
plt.show()
else:
print("Impulse response identification failed.")

example-iden-impulse.png

结果分析

运行上述代码后,你应该会看到一个图表,对比真实的脉冲响应和识别出的脉冲响应。这将验证 iden_impulse 函数是否正确识别出系统的脉冲响应。

解释

  1. 参数设置

    • 设置要识别的脉冲响应的阶数 order
    • 生成 n_wf 个波形,每个波形的采样点数为 N
  2. 生成脉冲响应

    • 生成目标脉冲响应 h[n] = (0.5)^n
  3. 生成输入输出数据

    • 生成随机的复数输入信号 U
    • 使用 np.convolve 函数将输入信号通过目标滤波器,生成输出信号 Y
  4. 使用 iden_impulse 识别脉冲响应

    • 调用 iden_impulse 函数,使用生成的输入输出数据识别脉冲响应。
  5. 结果对比

    • 检查识别是否成功,如果成功,则绘制真实脉冲响应和识别脉冲响应的对比图。

通过这个示例,你可以直观地看到 iden_impulse 函数的工作效果,并了解如何在实际应用中使用该函数来识别系统的脉冲响应。