资讯中心

离散控制系统状态转移矩阵:从定义到工程实践

📅 2026/9/29 19:30:46
离散控制系统状态转移矩阵:从定义到工程实践
事情还得从去年帮朋友调一套电机位置伺服系统说起。那套系统是典型的离散控制控制器跑在DSP里采样周期1ms速度环、位置环全部写成差分方程。模型建好后理论上一通推导就该能算出系统的阶跃响应可仿真的结果和手算老是对不上。折腾了两三天我才反应过来问题出在状态转移矩阵上——离散系统里那个看似简单的 A^k在不同边界条件下对应的形态完全不一样我算法里用错了形式导致零输入响应和零状态响应全都偏移了。这个经历让我特别想把这篇文章写出来。只要接触过离散控制系统状态转移矩阵就一定绕不开状态反馈、状态观测器、模型预测控制、卡尔曼滤波底层全是它在支撑。它的本质就是一个从初始状态映射到任意时刻状态的线性变换把差分方程的解写得干干净净x(k)Φ(k)x(0) 这一条式子就能回答系统自由响应、稳定性判断、预测控制里一大堆核心问题。这篇文章会把状态转移矩阵在离散控制系统中的定义、四种计算方法、典型应用和实现步骤完整拆开适合刚入门的控制专业学生也适合做嵌入式控制却一直“会用不会算”的工程师。1. 为什么离散控制系统离不开状态转移矩阵1.1 从连续系统到离散系统的“换挡”连续时间系统里我们熟悉的状态方程为ẋ(t) A_c x(t) B_c u(t)解的形式是 x(t) e^{A_c(t-t0)} x(t0)那里的状态转移矩阵是矩阵指数 e^{A_c t}物理含义非常直观状态从 t0 时刻经过 (t-t0) 的演化变成了 t 时刻的状态。在离散控制系统里时间被采样切成了 kT 的等距点经典离散状态方程写作x(k1) A x(k) B u(k)这里的 A 是系统矩阵B 是输入矩阵。绝大多数教材会直接告诉你离散状态转移矩阵定义为Φ(k) A^k第一次看到这个定义时我其实困惑了很久A^k 不就是矩阵自己乘自己吗怎么就成了“转移矩阵”后来我才真正理解这里的 A 已经不是连续系统那个抽象的微分关系系数而是描述“一个采样周期内状态如何从 k 时刻映射到 k1 时刻”的映射矩阵。所以 A^k 就是连续做 k 次映射等于从当前时刻跳到了 k 个周期之后。如果把 A 想象成一架“手机切屏”每次切屏状态都按同一张地图移动一格那么切 k 次屏后你在哪个位置就是初始位置乘以 A^k 的结果。这个类比虽然粗糙但对理解零输入响应已经足够没有外部输入时状态无非是按这张“地图”一格一格走下去。1.2 状态转移矩阵照顾着三件大事离散系统的行为分析本质上都绕回到状态转移矩阵的三种使用场景第一自由响应预测。给定初始状态 x(0)在没有任何输入的情况下状态序列为 x(1)Ax(0)x(2)A²x(0)第 k 步就是 x(k)A^k x(0)。只要 A^k 能算出来无输入条件下的系统轨迹就完全确定了。第二稳定性分析。离散系统的稳定性由系统矩阵 A 的特征值决定要求所有特征值严格落在单位圆内即 |λ_i|1。这个结论可以从状态转移矩阵的极限行为理解如果 A^k 在 k 趋于无穷时收敛到零矩阵那么任何初始状态的自由响应都会衰减到零而 A^k 的收敛性又由特征值模长决定。特征值模长小于 1A^k 就指数衰减大于 1输出就膨胀等于 1 且存在重根时可能出现多项式增长。所以判断稳定性本质上就是在判断状态转移矩阵的极限趋势。第三控制器与观测器设计。极点配置、LQR、状态观测器的反馈增益计算都建立在闭环系统矩阵 A-BK 的基础上。设计完成后验算闭环响应还是回到 (A-BK)^k 的现象评估。可以说状态转移矩阵是贯穿分析、设计、验证全流程的“同一张底牌”。1.3 与连续系统状态转移矩阵的区别很多刚入门的读者会把 e^{A_c T} 和 A^k 搞混。连续系统的状态转移矩阵是矩阵的指数函数而离散系统的状态转移矩阵是矩阵的整数次幂二者通过采样周期 T 联系在一起。在数字控制系统中如果连续对象以零阶保持器方式离散化那么离散系统矩阵为A_d e^{A_c T}这个式子经常让人疑惑为什么离散后的系统矩阵是矩阵指数而不是一个简单的近似因为零阶保持器意味着整个采样周期内输入保持恒定状态在 T 时间内的演化完全由连续动态决定所以必须用连续状态转移矩阵在 T 时刻的取值作为离散系统矩阵。换句话说连续系统状态转移矩阵“负责一个采样间隔内的演化”离散系统矩阵恰恰是它的一个快照。这一段内容很多人写代码时会忽略等到发现离散化后的矩阵特征根不对才会回头检查是采样时间 T 取错了还是离散化公式用错了。后面第 3.4 节我会具体展开这个应用。2. 离散状态转移矩阵的四种计算方法2.1 直接矩阵幂法简单但别硬算最直接的方法就是反复做矩阵乘法A² A·AA³ A²·A以此类推。比如系统矩阵A [0.8 0.1; -0.2 0.6]手算几步就能看出趋势A² [0.8×0.8 0.1×(-0.2), 0.8×0.1 0.1×0.6; -0.2×0.8 0.6×(-0.2), -0.2×0.1 0.6×0.6] [0.62 0.14; -0.28 0.34]A³ [0.8×0.620.1×(-0.28), 0.8×0.140.1×0.34; -0.2×0.620.6×(-0.28), -0.2×0.140.6×0.34] [0.468 0.146; -0.292 0.176]可以看到元素的绝对值在逐渐变小说明这个矩阵的特征值都在单位圆内。但如果矩阵阶数高、幂次大直接连乘的计算量会暴涨而且浮点误差逐次累积算到 A^100 时结果可能已经偏离真实值不少。另外一个容易踩的坑是在代码里用循环连乘去算状态转移矩阵虽然方便但当系统矩阵本身就是病态矩阵、或者说矩阵元素量级差异很大的时候连乘很容易损失精度。更稳妥的方案是用矩阵指数函数或者特征值分解下面讲。2.2 特征值分解法最常用的数值路径线性代数里有一组经典关系如果矩阵 A 可以对角化即存在可逆矩阵 V使得 A VΛV⁻¹其中 Λ 是对角矩阵对角线元素是特征值 λ1, λ2, ..., λn那么A^k V Λ^k V⁻¹这个式子像开挂一样把矩阵幂变成标量幂。Λ^k 就是对每个特征值单独做 λ_i^k计算量从 O(n³k) 直接降到 O(n³ nk)。举个例子给定矩阵A [0.9 0.1; 0 0.7]它的特征值显然是 λ10.9、λ20.7特征向量分别对应 [1,0]ᵀ 和某个非零向量。直接计算 A^10 也可以用特征值公式快速得到趋势对角线元素变成 0.9^10≈0.349、0.7^10≈0.028而非对角元素需要通过 V 的逆去耦合。不过要注意特征值分解法只在 A 有 n 个线性无关特征向量时有效。如果系统矩阵有约当块重特征值且特征向量不足就不能直接用 VΛ^k V⁻¹必须升级成约当标准型 JA^k P J^k P⁻¹而 J^k 中约当块部分会带出多项式项。这个细节我们在数值实现时会遇到后面第 4 节专门说。2.3 Cayley-Hamilton 定理法手算推导的利器Cayley-Hamilton 定理说任何方阵满足自己的特征多项式。设特征多项式为φ(λ) det(λI - A) λ^n a_{n-1}λ^{n-1} ... a_1λ a_0那么 A^n a_{n-1}A^{n-1} ... a_0I 0由此可以把 A^n 表示为 I, A, ..., A^{n-1} 的线性组合。更一般地任何 A^kk≥n都能通过递推化简成 A^{n-1} 以下幂次的组合A^k α_{n-1}(k)A^{n-1} α_{n-2}(k)A^{n-2} ... α_0(k)I这个方法的优点是完全不依赖矩阵对角化条件对约当块也适用非常适合二阶、三阶系统的手工推导。例如二阶系统的特征多项式 λ² a1λ a0 0那么任意 A^k 都可以写成 α1(k)A α0(k)I。系数求法可以通过把特征值代回同一个多项式关系来解。但这个方法在阶数较高时符号计算会非常繁琐实用性主要停留在教学和理论推导上。我在实际工程里很少用它直接算大矩阵更多是用它来检查约当块响应里“多项式增长”项的来源。2.4 Z 变换法和差分方程无缝衔接学过信号与系统的读者都知道Z 变换是求解线性常系数差分方程的利器。把离散状态方程 x(k1)Ax(k)Bu(k) 两边做 Z 变换zX(z) - zx(0) AX(z) BU(z)整理得(zI - A)X(z) zx(0) BU(z)于是X(z) z(zI-A)⁻¹ x(0) (zI-A)⁻¹ B U(z)做逆 Z 变换后第一项的时域形式就是 A^k x(0)所以状态转移矩阵的 Z 变换表达式为Φ(k) Z⁻¹[ z(zI-A)⁻¹ ]这里有一个细节经常让人转不过弯为什么会多乘一个 z因为 x(k1) 的 Z 变换是 zX(z)-zx(0)单边 Z 变换的移位性质要求把初始位移项 zx(0) 剥离出来矩阵 zI-A 求逆后分子上那个 z 就来自初始条件。如果直接对 (zI-A)⁻¹ 做逆变换得到的是另一种序列很多人就在这里出错。我们后面实践部分会写一个二元一次矩阵的例子用 Z 变换法手推一遍 A^k再和特征值法结果对比两者一致才算真正理解。3. 状态转移矩阵在系统分析与设计中的典型应用3.1 完整状态响应的求解零输入加零状态离散系统状态方程的全响应可以拆成两部分。先看零输入响应即没有输入作用x(k1)Ax(k)很容易得到:x_zi(k) A^k x(0)再看零状态响应初始状态为零但输入 u 一直作用。从 x(1)Bu(0)x(2)ABu(0)Bu(1)依次递推可以得到卷积和形式x_zs(k) Σ_{i0}^{k-1} A^{k-1-i} B u(i)把两部分叠加得到完整响应x(k) A^k x(0) Σ_{i0}^{k-1} A^{k-1-i} B u(i)这里的 A^{k-1-i} 依然是状态转移矩阵只不过转移的起点不是 0而是输入施加的那个时刻 i。换句话说每一个历史输入先把自己的作用“带入系统”然后状态转移矩阵再把它传递到当前时刻 k。理解了这个结构你去写迭代仿真代码时就会清楚不需要每步都从初始状态重新乘矩阵只要按差分方程一步步推结果和用卷积和公式算出来的完全一致。我在给学生讲这一部分时经常说状态转移矩阵是“传送带”输入是“货物”货物在传送带上每经过一个采样周期就被挪动一格公式里的 A^{k-1-i} 就是在算“从装货点 i 到当前点 k 的距离”。这个类比虽然朴素但可以让初学者少走很多弯路。3.2 离散系统稳定性判定看特征值不如看状态转移矩阵的极限离散系统稳定的充分必要条件是系统矩阵 A 的所有特征值都在单位圆内。工程上判断这个一般直接用eig(A)看模长。但如果想理解稳定性为什么由特征值决定可以从状态转移矩阵的极限入手系统渐近稳定等价于对任意初始状态 x(0)x(k)A^k x(0) 都趋于零。也就是说A^k 随着 k 增大而趋于零矩阵。如果 A 可以对角化A^k VΛ^k V⁻¹那么 A^k 趋近于零就要求每一个 λ_i^k 趋近于零也就是所有 |λ_i|1。如果特征值恰好等于 1对应状态分量不会衰减但也不会发散这是临界稳定如果模大于 1会指数发散。至于单位圆上的复数特征值且无重根系统会出现持续等幅振荡这种临界情况在实际工程中一般也要避免因为参数漂移很容易让它变成发散。还有一个不那么直观的情况特征值模都小于 1但系统矩阵有较大的约当块那么状态转移矩阵中会出现 k^m λ_i^{k-m} 这样的项其中 m 与约当块阶数有关。虽然 |λ_i|1 时这些项最终也会衰减但暂态过程可能很长表现在控制系统中就是“慢悠悠地稳定”。这一点在做控制器设计时容易被忽略只看到特征值模长小于 1 就以为没问题结果实际系统调整时间长得离谱。3.3 在 MPC 预测模型中的角色模型预测控制MPC的核心是“滚动优化”而预测模型正是靠状态转移矩阵把未来的状态推出来。在 LTI 离散系统中如果当前时刻为 k未来第 j 步的状态预测写为x(kj|k) A^j x(k|k) Σ_{i0}^{j-1} A^{j-1-i} B u(ki|k)可以看到预测器里反复出现的 A^j 就是状态转移矩阵。为了在一个优化周期内同时考虑未来 N 步通常会把 N 步状态预测全部展开成一组关于当前状态和未来输入序列的线性方程组然后用二次规划求解。其中需要构建的预测矩阵里底部全是 A^j 的组合X F x(k) G UF 的第 j 行是 A^jG 的元素涉及 A^{j-1-i}B。这个矩阵的数值质量直接影响 MPC 求解器的稳定性和速度尤其是 A 有接近单位圆的特征值时A^j 在 j 较大时仍不衰减预测矩阵的条件数会变差优化问题变得病态。所以做嵌入式 MPC 时我通常会先计算 A^N看看 N 步之后状态转移矩阵的范数是否还很大。如果还很大要么增大预测时域 N要么重新考虑采样周期。3.4 连续对象离散化中的“隐藏关卡”工程上最常见的场景是拿连续模型做离散化。使用零阶保持器对连续状态方程进行精确离散结果如下A_d e^{A_c T}B_d ∫_0^T e^{A_c τ} dτ · B_c很多人在这一步直接调用c2d()函数就完事了完全没意识到 A_d 和 B_d 的计算本身就是状态转移矩阵的应用连续系统状态转移矩阵在区间 [0, T] 上的端点值就是离散系统矩阵它对时间积分后再乘以输入矩阵才是离散输入矩阵。所以一个采样周期内连续状态从 x(kT) 演化到 x(kTT) 的完整信息就压缩进了 A_d 和 B_d 两个矩阵。这里的 T 选择也有讲究。T 取得太大A_d 的特征值会靠近单位圆甚至出现非最小相位效应离散模型失真T 取得太小A_d 非常接近单位矩阵系统几乎“一步只动一点”控制增益会非常大数值上容易放大噪声。一般经验是采样频率取系统闭环带宽的 10~20 倍这是后话了但你要知道离散模型的“质量”很大程度上由这个隐藏的矩阵指数计算决定。4. 从零手写一个状态转移矩阵计算模块4.1 准备工作与整体流程为了彻底理解原理我建议别急着调scipy.signal.dlti先自己用 Python 实现一个小工具能算 A^k、能输出特征值、能对比两种方法的结果。环境只需要numpy和scipy.linalg这是控制仿真的老搭档。整体流程分五步定义系统矩阵 A确认维度 n。计算特征值和特征向量判断矩阵是否可对角化。根据情况选择合适的 A^k 计算方式特征值分解、约当块处理或直接数值方法。用 Z 变换法做交叉验证。把结果放到具体仿真里验证状态响应是否符合物理直觉。4.2 完整代码示例与输出验证拿下面这个二阶矩阵做例子它有实数特征值系统稳定A [0.9 0.1; 0 0.7]先算特征值和特征向量再算 A^5 和 A^10。import numpy as np from scipy.linalg import eig, inv A np.array([[0.9, 0.1], [0.0, 0.7]]) # 特征值分解 eigvals, eigvecs eig(A) print(特征值:, eigvals) print(特征向量矩阵:\n, eigvecs) for k in [2, 5, 10]: # 直接矩阵幂法 Ak_direct np.linalg.matrix_power(A, k) # 特征值分解法 Lambda np.diag(eigvals ** k) Ak_eig eigvecs Lambda inv(eigvecs) print(fA^{k}:\n, Ak_direct) print(f特征值分解结果:\n, Ak_eig) print(最大误差:, np.max(np.abs(Ak_direct - Ak_eig)))运行后会看到这样一组关键结果A^5 的对角元素分别变成 0.59049、0.16807非对角元素大约在 0.23 左右A^10 的对角元素变成 0.3487、0.02825。误差在 1e-15 量级说明两种方法完全一致。这个例子虽然简单但能让你建立起“特征值分解法确实等价于直接矩阵幂”的直觉。如果矩阵有复数特征值特征值分解法同样适用只是特征向量矩阵和 Λ 中包含复数运算时保持复数类型即可。需要留意的是在最后输出状态响应时如果系统矩阵是实矩阵A^k 也应是实矩阵但由于浮点误差可能带有微小虚部可以取实部np.real(...)来消除数值噪声。4.3 数值稳定性与约当块的坑当你真正处理一个维度大于 3 的系统时最常遇到的问题不是原理不懂而是数值计算翻车。第一个坑是特征值特别接近导致特征向量矩阵接近奇异。这种情况下用eigvecs Lambda inv(eigvecs)会放大误差因为inv对近奇异矩阵非常敏感。建议改用scipy.linalg.solve或直接使用scipy.linalg.expm、scipy.linalg.fractional_matrix_power等更稳定的算法。第二个坑是非对角化矩阵约当块。比如J [0.8 1; 0 0.8]这个矩阵特征值为 0.8二重但特征向量只有一个不能对角化。此时 A^k 中会出现一个系数乘以零元素非对角元素会变成 k·0.8^{k-1}。如果还是硬用特征向量矩阵求逆结果会直接报错或给出荒谬结果。处理办法是识别约当块使用 J^k 的解析形式。Python 里可以借助scipy.linalg.jordan_form查看约当结构但我个人更推荐在工程应用中直接用expm系函数处理离散化的矩阵指数而不是手动算约当块。因为手动算约当块非常容易出错而expm是经过算法优化的数值稳定性高一个量级。第三个坑是矩阵幂次太大导致的溢出。A 的特征值如果大于 1A^k 在 k 很大时会变成巨大数值浮点溢出后全是 inf 或 nan。这不见得是代码写错而是系统本身不稳定。做仿真时如果看到这一点反而可以反过来提醒自己这个离散系统可能是开环不稳定的需要先加反馈闭环再做计算。5. 常见问题与排查技巧实录5.1 特征值分解结果和直接矩阵幂对不上这种情况我遇到过很多次。第一个排查点特征向量矩阵是否正确求逆。inv在矩阵接近奇异时会产生很大的误差结果一对比误差不是 1e-15 而是 1e-2甚至出现 NaN。解决办法是改用numpy.linalg.solve(eigvecs, Ak_eig_left)这种解线性方程组的方式或者直接用matrix_power作为基准不要再自己造轮子。第二个排查点矩阵是可对角化的吗如果特征值有重根且几何重数小于代数重数特征向量矩阵不可逆inv自然会报错或输出垃圾。这时就要回到约当块方法或者直接用expm处理。5.2 Z 变换法求出的 A^k 和数值结果不一致这个问题的根源多半是公式里的 z 丢了。前面说过离散状态方程做 Z 变换后X(z) 表达式里第一项是 z(zI-A)⁻¹不是 (zI-A)⁻¹。如果忘了乘 z逆 Z 变换出来的序列就会差一个移位表现是“结果像是对的但整体延迟了一拍”。怎么迅速判断看 k0 时的结果真正的状态转移矩阵 A^0IZ 变换法逆变换后第一步必须得到单位矩阵。如果 k0 时得到零矩阵那一定少乘了 z 或者初始条件处理错了。5.3 采样周期对状态转移矩阵影响极大我见过不少工程师把采样周期当作一个无关痛痒的参数随便填一个 1ms 或者 10ms结果系统发散或者响应很奇怪。实际上离散系统矩阵 A_d e^{A_c T} 是采样周期的非线性函数不同 T 对应的状态转移矩阵差别巨大。假设连续系统极点是 -1±2jT0.1s 时e^{A_c T} 的特征值模长大约是 e^{-0.1}≈0.905T0.5s 时模长变成 e^{-0.5}≈0.607。看起来 T 越大越稳定但注意 T 过大时模型可能丢失高频动态实际系统的连续振荡在采样点之间完全无法体现控制律就会“盲人摸象”。我个人的建议是调完采样周期后顺手打印一次 A_d 的特征值模长确认没有出现接近单位圆或单位圆外的特征值再继续做控制器设计。5.4 用状态转移矩阵做长时域预测时结果发散在做 MPC 或者长时间轨迹预测时有时会发现预测误差越来越大状态转移矩阵本身也没有算错但结果就是不对。这里要区分两种情况如果是系统不稳定A^k 发散是正常的问题出在你要预测的对象本身需要闭环稳定化如果是系统稳定但预测结果在几十步之后明显偏离物理规律多半是数值精度问题。比如 A 的特征值非常接近 1导致 A^k 衰减极慢此时不如改用增量形式的状态方程或者用双线性变换重新建模也可以把系统矩阵重新归一化减少条件数。还有一个小技巧在仿真阶段把 A^k 的范数随着 k 的变化画出来。如果发现曲线单调不明显或者出现锯齿大概率是采样周期和动态不匹配这个检查比直接看响应曲线更早暴露问题。写在最后的一个经验回到开头那套电机伺服系统最后我把状态转移矩阵的计算方式从直接连乘改成了基于expm和特征值分解混合处理再把 Z 变换交叉验证跑了一遍响应才完全对上。后来每次做离散控制系统我都保持一个习惯先算特征值再算 A^k 的范数曲线最后看状态响应。这三步看起来繁琐但能提前挡掉七八成的低级错误。如果你现在正被某个离散系统仿真结果折磨不妨也按这个顺序自查一遍。状态转移矩阵只是一个数学工具但它承载着离散系统最本质的动态信息值得多花一点时间把它彻底吃透。

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案