scipy.signal.

place_poles#

scipy.signal.place_poles(A, B, poles, method='YT', rtol=0.001, maxiter=30)[source]#

计算 K 使得特征值 (A - dot(B, K))=poles。

K 是增益矩阵,如由线性系统 AX+BU 描述的工厂将具有其闭环极点,即特征值 A - B*K,尽可能接近 poles 中要求的极点。

支持 SISO、MISO 和 MIMO 系统。

参数:
A, Bndarray

线性系统 AX + BU 的状态空间表示。

polesarray_like

期望的实极点和/或共轭复极点。仅在 method="YT"(默认)时支持复极点。

method: {‘YT’, ‘KNV0’}, 可选

选择哪种方法来查找增益矩阵 K。其中之一

  • ‘YT’:杨提茨

  • ‘KNV0’:Kautsky、Nichols、Van Dooren 更新方法 0

有关算法的详细信息,请参阅参考资料和注释。

rtol: float, 可选

每次迭代后,都会将特征向量的行列式 A - B*K 与它上一次的值进行比较,当这两个值之间的相对误差小于 rtol 时,算法将停止。默认值为 1e-3。

maxiter:int,可选

计算增益矩阵的最大迭代次数。默认值为 30。

返回:
full_state_feedbackBunch 对象
full_state_feedback 由以下部分组成
gain_matrix1 维 ndarray

闭环矩阵 K,它尽可能接近于请求的极点,如同 A-BK 的特征值。

computed_poles1 维 ndarray

对应于 A-BK 的极点按以下方式排序:首先是增序的实数极点,然后再是按字母顺序排列的复数共轭极点。

requested_poles1 维 ndarray

算法尝试放置的极点按上述方式排序,它们可能与达到的极点有所不同。

X2 维 ndarray

传递矩阵,如 X * diag(poles) = (A - B*K)*X(参见注解)

rtolfloat

det(X) 上达到的相对容差(参见注解)。如果系统 diag(poles) = (A - B*K) 能够求解,则 rtol 将为 NaN,或者当优化算法没有任何作用(即当 B.shape[1] == 1)时为 0。

nb_iterint

在收敛之前执行的迭代次数。如果系统 diag(poles) = (A - B*K) 能够求解,则 nb_iter 将为 NaN,或者当优化算法没有任何作用(即当 B.shape[1] == 1)时为 0。

注解

Tits 和 Yang (YT) 的 [2] 论文是原始 Kautsky 等人 (KNV) 论文 [1] 的更新。KNV 依赖于秩 1 更新来查找转移矩阵 X 使得 X * diag(poles) = (A - B*K)*X,而 YT 使用秩 2 更新。平均而言,这会产生更稳健的解决方案(参见 [2] 第 21-22 页),此外 YT 算法支持复极,而 KNV 在其原始版本中不支持。这里只实现了 KNV 提出的更新方法 0,因此得名 'KNV0'

在 Matlab 的 place 函数中使用了扩展到复极的 KNV,YT 由 Slicot 以 robpole 的名称在非免费许可证下分发。目前还不清楚并且没有记录如何将 KNV0 扩展到复极(Tits 和 Yang 在他们论文的第 14 页声称他们的方法不能用于将 KNV 扩展到复极),因此在此实现中只有 YT 支持它们。

由于极点放置问题的解决方案对于 MIMO 系统而言并非唯一,因此两种方法都从一个试验转移矩阵开始,该转移矩阵以各种方式进行修改以增加其行列式。两种方法已被证明会收敛到一个稳定的解决方案,但是根据选择初始传递矩阵的方式,它们将收敛到不同的解决方案,因此绝对不能保证使用 'KNV0' 会产生与 Matlab 或任何其他实现类似的结果这些算法。

在大多数情况下使用默认方法 'YT' 应该没有问题;提供 'KNV0' 只是因为 'YT' 在某些特定情况下需要它。此外,当 abs(det(X)) 用作稳健性指标时,'YT' 给出的平均结果比 'KNV0' 更稳健。

[2] 可作为技术报告在以下 URL 上获得:https://hdl.handle.net/1903/5598

参考文献

[1] (1,2)

J. Kautsky、N.K. Nichols 和 P. van Dooren,“线性状态反馈中的稳健极点分配”,控制国际期刊,第 41 卷,第 1129-1155 页,1985 年。

[2] (1,2,3)

A.L. Tits 和 Y. Yang,“通过状态反馈进行稳健极点分配的全局收敛算法”,IEEE 自动控制学报,第 41 卷,第 1432-1452 页,1996 年。

示例

使用 KNV 和 YT 算法展示实际极点配置的简单示例。这是参考 KNV 刊物第 4 部分中的示例 1 ([1])

>>> import numpy as np
>>> from scipy import signal
>>> import matplotlib.pyplot as plt
>>> A = np.array([[ 1.380,  -0.2077,  6.715, -5.676  ],
...               [-0.5814, -4.290,   0,      0.6750 ],
...               [ 1.067,   4.273,  -6.654,  5.893  ],
...               [ 0.0480,  4.273,   1.343, -2.104  ]])
>>> B = np.array([[ 0,      5.679 ],
...               [ 1.136,  1.136 ],
...               [ 0,      0,    ],
...               [-3.146,  0     ]])
>>> P = np.array([-0.2, -0.5, -5.0566, -8.6659])

现在,使用 KNV 方法 0、使用默认 YT 方法以及使用 YT 方法计算 K,同时强制算法迭代 100 次,并在每次调用后打印一些结果。

>>> fsf1 = signal.place_poles(A, B, P, method='KNV0')
>>> fsf1.gain_matrix
array([[ 0.20071427, -0.96665799,  0.24066128, -0.10279785],
       [ 0.50587268,  0.57779091,  0.51795763, -0.41991442]])
>>> fsf2 = signal.place_poles(A, B, P)  # uses YT method
>>> fsf2.computed_poles
array([-8.6659, -5.0566, -0.5   , -0.2   ])
>>> fsf3 = signal.place_poles(A, B, P, rtol=-1, maxiter=100)
>>> fsf3.X
array([[ 0.52072442+0.j, -0.08409372+0.j, -0.56847937+0.j,  0.74823657+0.j],
       [-0.04977751+0.j, -0.80872954+0.j,  0.13566234+0.j, -0.29322906+0.j],
       [-0.82266932+0.j, -0.19168026+0.j, -0.56348322+0.j, -0.43815060+0.j],
       [ 0.22267347+0.j,  0.54967577+0.j, -0.58387806+0.j, -0.40271926+0.j]])

X 行列式绝对值是一个很好的指标,可用来检查结果的稳健性,'KNV0''YT'都旨在最大化它。下面是上述结果稳健性的对比

>>> abs(np.linalg.det(fsf1.X)) < abs(np.linalg.det(fsf2.X))
True
>>> abs(np.linalg.det(fsf2.X)) < abs(np.linalg.det(fsf3.X))
True

现在是一个复杂极点的简单示例

>>> A = np.array([[ 0,  7/3.,  0,   0   ],
...               [ 0,   0,    0,  7/9. ],
...               [ 0,   0,    0,   0   ],
...               [ 0,   0,    0,   0   ]])
>>> B = np.array([[ 0,  0 ],
...               [ 0,  0 ],
...               [ 1,  0 ],
...               [ 0,  1 ]])
>>> P = np.array([-3, -1, -2-1j, -2+1j]) / 3.
>>> fsf = signal.place_poles(A, B, P, method='YT')

我们可以在复平面上绘制所需的极点和计算出的极点

>>> t = np.linspace(0, 2*np.pi, 401)
>>> plt.plot(np.cos(t), np.sin(t), 'k--')  # unit circle
>>> plt.plot(fsf.requested_poles.real, fsf.requested_poles.imag,
...          'wo', label='Desired')
>>> plt.plot(fsf.computed_poles.real, fsf.computed_poles.imag, 'bx',
...          label='Placed')
>>> plt.grid()
>>> plt.axis('image')
>>> plt.axis([-1.1, 1.1, -1.1, 1.1])
>>> plt.legend(bbox_to_anchor=(1.05, 1), loc=2, numpoints=1)
../../_images/scipy-signal-place_poles-1.png