Appearance
状态空间分析
概念
前六章走的都是同一条路:把系统看成一个"输入进去、输出出来"的黑箱,用传递函数 G(s) 描述它。这条路很成功,但它有三处硬伤:
| 硬伤 | 具体表现 |
|---|---|
| 只认单入单出 | 多输入多输出(比如四旋翼的四个电机、三个姿态角)根本没有"一个"传递函数 |
| 看不到内部 | 传递函数里极点可能对消,对消掉的内部模态在输出上完全看不见——那部分未必是稳定的 |
| 初始条件被抹掉 | 传递函数是在零初始条件下定义的,系统"从什么状态出发"这件事被丢掉了 |
状态空间法把这三条一起解决:不再只看一个输入一个输出,而是把系统的全部内部状态写成一组一阶微分方程。
一句话说清它是什么:状态空间法把 n 阶系统拆成 n 个一阶方程,用矩阵把"状态怎么变"和"能测到什么"分别写出来。
| 量 | 名字 | 维度 | 含义 |
|---|---|---|---|
x | 状态向量 | n 维 | 一组能完全决定系统未来行为的最小变量集合 |
u | 输入向量 | m 维 | 可控的外部作用 |
y | 输出向量 | p 维 | 能测量到的量 |
A | 状态矩阵 | n×n | 系统自身的动力学 |
B | 输入矩阵 | n×m | 输入怎么影响状态 |
C | 输出矩阵 | p×n | 哪些状态的组合能被测到 |
D | 直通矩阵 | p×m | 输入直接透传到输出的部分 |
n 就是系统的阶数——这一点必须记牢:一个 n 阶系统恰好有 n 个状态变量,多一个总有冗余、少一个就描述不全。
这一层回答了上一层什么问题:上一章用 PID 把"一个回路"调好了,但 PID 处理的始终是"一路进、一路出"。换个问题——如果我要同时管四个电机、还要保证某些内部量不发散呢? 这就需要一个能描述"内部"的语言。而状态空间给出的两个新概念——能控性与能观性——在传递函数里根本问不出来。
状态空间法和经典控制的关系不是替代,而是扩展:经典法擅长"调一个回路",状态空间法擅长"管多个回路、看内部结构、做最优设计"。同一个系统,两套语言可以互相翻译(见第一节末尾的公式)。
原理
一、状态变量与状态方程
"状态"的精确定义:一组最小数量的变量,只要知道它们在某个时刻的取值,加上这之后的所有输入,就能完全确定系统这之后的全部行为。
这个定义里两个词是关键:"最小"(不能多,多了有冗余)和**"完全确定"**(不能少,少了信息不够)。对 n 阶系统,状态变量的个数恰好是 n。
写状态方程的过程,其实就是把高阶微分方程降成一阶方程组。以二阶为例,y'' + a1 y' + a0 y = b u:
令 x1 = y,x2 = y'
则 x1' = x2
x2' = -a0 x1 - a1 x2 + b u写成矩阵形式:
这个形式叫"能控标准型",它的特点是结构极其规整,看一眼矩阵就知道原传递函数的系数:
| 矩阵 | 元素规律 |
|---|---|
A | 最后一行是特征多项式系数取负、倒序(-a0、-a1……);上三角是单位阵错位 |
B | 只有一个 1,在最后一行 |
C | 只有第一个元素非零,等于传递函数的分子系数 |
为什么叫"能控标准型":这个形式下系统一定是能控的(第三节会验证),而且极点配置的求解特别简单(第四节)。
从状态空间回到传递函数:
这个公式是两套语言的翻译官。它说明了一件重要的事:状态空间的表示不是唯一的(同一系统的 A、B、C 可以有无数种等价写法,只要用相似变换 T 转一下:A' = TAT⁻¹、B' = TB、C' = CT⁻¹),但它们给出的 G(s) 完全相同,特征值也完全相同——这就是"内部结构可变、外部行为不变"的正式表达。
G(s) 的极点就是 A 的特征值(除非发生零极点对消)。而对消掉的那部分,正是状态空间法能看到、传递函数法看不到的东西。
二、状态转移矩阵:解的核心
齐次方程 x' = Ax 的解是
e^{At} 叫状态转移矩阵(常记作 Φ(t)),它承担的任务就一句话:把初始状态"搬运"到 t 时刻的状态。
四条必须记住的性质:
| 性质 | 表达式 | 意义 |
|---|---|---|
| 零时刻是单位阵 | e^{A·0} = I | 状态不经过时间就不改变 |
| 求导自洽 | d/dt (e^{At}) = A·e^{At} | 代入方程就验证了 |
| 可逆 | (e^{At})⁻¹ = e^{-At} | 状态转移可以倒着走(这也是它比一般矩阵函数特殊的地方) |
| 半群性质 | e^{A(t1+t2)} = e^{At1}·e^{At2} | 同一系统两段时间的转移可以相乘——A 只有一个时成立 |
计算 e^{At} 有两条正路:
| 路径 | 做法 | 适用 |
|---|---|---|
| 级数展开 | e^{At} = I + At + (At)²/2! + (At)³/3! + … | 通用,适合数值计算(有限项截断) |
| Cayley-Hamilton | 用特征多项式把 A^n 降阶,得 e^{At} = α0(t)I + α1(t)A + … | 适合手算低阶,得到闭式解 |
Cayley-Hamilton 定理说的是"矩阵满足自己的特征方程":若 A 的特征多项式是 λ² + p1 λ + p0,则 A² + p1 A + p0 I = 0。所以任何 A 的高次幂都能降到一次,e^{At} 这个无穷级数就被压成了 α0(t)I + α1(t)A 的形式,其中 α0、α1 由特征值决定。这就是"二阶系统的矩阵指数总能写成两个标量函数的组合"的根据。
非齐次方程的全解是两块之和:
左半块是零输入响应(只有初始状态、没有输入),右半块是零状态响应(只有输入、初始状态为零)。
这个结构和平常解微分方程完全一样(齐次解 + 特解),只是标量换成了矩阵。"零输入响应"与"零状态响应"这两块在经典控制里叫"自由响应"与"强迫响应",是同一个东西的两种叫法。
三、能控性与能观性
这是状态空间法带来的两个全新概念,在传递函数里根本无从问起。
| 概念 | 定义 | 判据(n 阶系统) |
|---|---|---|
| 能控性 | 存在一个输入 u(t),能在有限时间内把状态从任意初值推到任意目标值 | rank[B, AB, A²B, …, A^{n-1}B] = n |
| 能观性 | 由有限时间内的输出观测值,能唯一确定初始状态 | rank[C; CA; CA²; …; CA^{n-1}] = n |
两句话理解它们的物理意义:
- 能控 = 输入有没有"够到"每个状态的能力。若某个状态方向输入怎么推都推不动,那个方向上的问题就永远无法用反馈修正。
- 能观 = 输出有没有"暴露"每个状态的信息。若某个状态的初值对输出毫无影响,那它就没法被估计——即使它发散了,你也看不见。
判据用"秩"而不是"行列式":对 n×n 方阵两者等价(秩满 ⟺ 行列式非零),但多输入多输出时矩阵是长方形的,只有秩判据才通用。所以标准写法是 rank(·) = n,二阶单入单出时可以退化成"行列式非零"。
对偶性(这是这套理论最漂亮的地方):
原系统 (A, B, C) | 对偶系统 (Aᵀ, Cᵀ, Bᵀ) |
|---|---|
能控性矩阵 [B AB …] | 对偶系统的能观性矩阵 [Bᵀ; AᵀBᵀ; …] |
| 能控 ⟺ 对偶系统能观 | 能观 ⟺ 对偶系统能控 |
对偶性不只是数学巧合,它有工程含义:控制器设计(极点配置)与观测器设计(状态估计)在数学上是同一个问题,只是一个用 (A, B)、一个用 (Aᵀ, Cᵀ)。所有给控制器写的算法,把 (A,B) 换成 (Aᵀ,Cᵀ) 就自动变成观测器算法——这就是"分离原理"能成立的深层原因。
四、状态反馈与极点任意配置
状态反馈是指"直接把全部状态拿回来做线性组合,去补偿输入":
闭环系统的动力学矩阵从 A 变成 A - BK,所以闭环极点是 A - BK 的特征值。于是问题变成:能不能选一个 K,让 A - BK 的特征值落在任意指定位置?
能任意配置极点,当且仅当系统能控。
这条定理是状态空间法的核心结论:能控性是"能不能设计控制器"的资格线。不能控的系统,某些极点你无论怎么选 K 都动不了——《自动控制原理》里那些"某个极点无法配置"的怪题,根源都是不可控模态。
求 K 的方法:
| 阶数 | 方法 |
|---|---|
| 二阶 | 直接写出 A - BK 的特征多项式,与目标多项式对比系数(最省事) |
| 高阶 | Ackermann 公式(用能控性矩阵、特征多项式代入,套公式即可) |
| 任意阶 | 把系统化为能控标准型后再配——标准型下 K 的系数与目标多项式系数一一对应 |
一个必须知道的局限:状态反馈改变不了零点,因而消不掉静差。
u = -Kx 只动极点,G(s) 的分子(零点)不变。所以把极点全放到很漂亮的负实轴上之后,阶跃响应的稳态值往往不是 1——这不是设计错了,而是状态反馈本身只管"动态形状",不管"静态大小"。要修,就在前面串一个常数增益 N,让总直流增益变成 1。
这条与 PID 的对应关系很有意思:PID 里的 I 项相当于"内置积分器消差",而状态反馈的解法是"外部前置增益定量补差"。前者鲁棒但吃裕度,后者精确但依赖模型准。
五、状态观测器
现实问题是:状态往往测不全——能测的只有输出 y(几种传感器),而状态有 n 个。"用能测的量去估计不能测的量"就是观测器的任务。
全维状态观测器(估计全部 n 个状态)的构造是:
它的结构可以拆成两半来看:
A x̂ + B u:用模型自己"预测"状态怎么变——这是模型在跑;L(y − C x̂):用"实测输出与预测输出之差"来修正预测——这是反馈在纠偏。
误差方程是关键:令 e = x − x̂,两式相减得
误差的动力学只由 A − LC 决定,与 u 和 x 完全无关——这是一个完全自主的方程。于是观测器设计就变成"选 L 让 A − LC 的特征值尽可能负"(误差衰减得越快越好)。
分离原理:
状态反馈增益
K与观测器增益L可以各自独立设计,互不影响;由两者组成的闭环系统,其极点恰好是A − BK的极点与A − LC的极点之并。
这条原理之所以成立,正是因为第三节的对偶性:K 的问题(配置 A − BK)与 L 的问题(配置 A − LC)在数学上是对偶的同一个问题,所以可以分开算、直接拼。工程上的意义是巨大的:原本要同时解一个 2n 阶的耦合设计问题,现在拆成两个 n 阶的独立问题。
一条实践经验:观测器的极点通常取得比控制器极点更快(比如快 2~5 倍)。理由很直白——估计得不准,控制就没意义;让估计误差先衰减掉,控制才建立在可靠的信息上。代价是 L 变大会放大测量噪声,所以又不能取太快。
六、和前面五章的关系
| 前面的方法 | 状态空间里的对应 | 位置 |
|---|---|---|
传递函数 G(s) | C(sI−A)⁻¹B + D | 外部行为,内部结构可对消 |
| 极点 | A 的特征值 | 传递函数只看得到能控且能观的那部分极点 |
| 劳斯判据 | A 的特征值实部是否为负 | 状态空间下直接算特征值 |
PID 的 I 项 | 需要前置增益 N 或加积分状态 | 消差的两条不同思路 |
根轨迹的 K | 静态输出反馈(只用一个量) | 状态反馈是更一般的"全信息"反馈 |
最后一行值得强调:根轨迹调的是"输出反馈增益 K"(只用 y 这一个量),而状态反馈用的是全部 n 个状态。信息多了,能力就强了——这正是"能控就能任意配置极点"的直觉来源。
示例
例 1:系统矩阵、特征值与传递函数
取二阶系统 G(s) = 1/(s² + 3s + 2),按能控标准型写出来:
text
A = [[0, 1], [-2, -3]],B = [[0], [1]],C = [[1, 0]]
迹 = -3.0,det = 2.0
特征方程 s^2 - 迹*s + det = s^2 + 3.0 s + 2.0 -> 特征值 -1、-2
传递函数 G(s) = C(sI-A)^-1 B = 1/(s^2 + 3s + 2)两处核对:
- 特征值
-1、-2与s² + 3s + 2 = (s+1)(s+2)的根一致。这不是巧合:A的特征多项式就是传递函数的分母(这正是能控标准型的构造目的)。 - 从
A、B、C反推出的G(s)与题目给的完全一致——这条"绕一圈再回来"的核对,验证的是整条链路(标准型构造 + 矩阵求逆)没有写错。手算时检查这一步,比重新算一遍矩阵还有效。
例 2:状态转移矩阵的两条计算路径
e^{At} 用**级数展开(40 项)**计算,并与 Cayley-Hamilton 闭式解对照:
text
t e^(At) 闭式解(行优先展开) 与级数(40项)的逐元素最大差
0.00 [+1.000000 +0.000000; +0.000000 +1.000000] 0.000e+00
0.50 [+0.845182 +0.238651; -0.477302 +0.129228] 1.110e-16
1.00 [+0.600424 +0.232544; -0.465088 -0.097209] 3.331e-16
2.00 [+0.252355 +0.117020; -0.234039 -0.098704] 1.887e-15闭式解的具体形式(由特征值 -1、-2 定出 α0 = 2e^{-t} − e^{-2t}、α1 = e^{-t} − e^{-2t}):
这张表的用法:
t = 0那一行必须是单位阵,最大差0.000e+00——这是e^{At}的基本性质,也是最快的"程序有没有写错"的自检。如果t = 0不是单位阵,后面全不用看了。- 两条路径的差异在
10⁻¹⁶~10⁻¹⁵量级,并且随t增大而变大:t = 0.5时1.110e-16,t = 2.0时1.887e-15。这是级数截断在"矩阵元素量级变化更大"时误差放大的正常表现——40 项对应t = 2时最大项约2⁴⁰/40!,本来就在机器精度附近。
"两条路径互相印证"是本节最有价值的做法:闭式解可能推错、级数可能截断不足,但两者同时错到同一个值上的概率极低。 这与 06-pid 里"位置式与增量式互为对照"是同一种思路——不依赖参考答案,让两条独立路径互证。
例 3:能控性与能观性
text
能控性矩阵 Mc = [B AB] = [[0, 1], [1, -3]],det = -1.0
能观性矩阵 Mo = [C; CA] = [[1, 0], [0, 1]],det = 1.0
两个行列式都非零 -> 既完全能控、又完全能观AB 的算法:A·B = [[0,1],[-2,-3]]·[[0],[1]] = [[1],[-3]],所以 [B AB] = [[0,1],[1,-3]]。
两处要点:
- 能控性矩阵的行列式是
-1(不是1)——判据只关心"是不是零",不关心具体数值。负值完全正常。 - 能观性矩阵恰好是单位阵,这是能控标准型的附带好处:
C = [1, 0]直接测第一个状态x1 = y,而CA = [0, 1]正好测到x2。所以"能控标准型"的信息是"摊开"的,每个状态都被C或CA抓到。
这也是为什么能控标准型一定能控:它的能控性矩阵按构造就是一个"下三角带单位置换"的结构,必满秩。"能控标准型"这个名字本身就是结论。
例 4:极点配置与静差的补法
目标是把两个闭环极点都放到 -5:
text
目标特征多项式 (s+5)^2 = s^2 + 10s + 25
A - BK = [[0, 1], [-2-k1, -3-k2]],其特征多项式为 s^2 + (3+k2)s + (2+k1)
对照系数:3 + k2 = 10 -> k2 = 7.0;2 + k1 = 25 -> k1 = 23.0
故反馈增益 K = [23.0, 7.0]
核对:A - BK = [[0.0, 1.0], [-25.0, -10.0]],迹 = -10.0(应为 -10),det = 25.0(应为 25)对比系数这一步是全部的计算——二阶问题在能控标准型下就是两个一元一次方程,不需要算矩阵求逆、也不需要 Ackermann 公式。
核对用两个数就够:迹 = -10(对应 -5 + (-5))与 det = 25(对应 (-5)×(-5))。这两个数决定了特征多项式,也就决定了特征值——二次方程"和与积定根"的常识,在这里变成了最省事的验算手段。
但极点漂亮了,静差出来了:
text
闭环传递函数 1/(s^2+10s+25),直流增益 = 1/25 = 0.040000
要消除静差需前置增益 N = 25(否则 e_ss = 1 - 0.04 = 0.96)阶跃输入的稳态输出只有 0.04,稳态误差 0.96——96% 的误差! 这看起来很荒谬(极点明明在 -5,动态好得很),但完全合理:状态反馈不改变直流增益,只改变动态。
补法很简单:在参考输入前串一个 N = 1/0.04 = 25。但要清楚 N 的性质:它是按模型精确算出来的,如果模型不准(A、B 有误差),N 就不再精确,静差会重新出现。这正是"状态反馈不如 PID 的 I 项鲁棒"的具体体现——I 项不需要知道模型,靠"误差不清零就不停"的机制硬把静差压掉。
两句话对比这两种消差思路:
状态反馈 + 前置增益 N | PID 的积分项 | |
|---|---|---|
| 原理 | 按模型算出需要放大多少倍 | 误差不为零就持续累加 |
| 优点 | 精确、直接、不影响动态 | 不依赖模型、鲁棒 |
| 缺点 | 模型不准就失准 | 吃相位裕度、可能积分饱和 |
例 5:全维状态观测器
把观测器极点放到 -10、-10(比控制器极点 -5 快一倍):
text
A - LC = [[-l1, 1], [-2-l2, -3]],特征多项式 s^2 + (3+l1)s + (3*l1 + 2 + l2)
3 + l1 = 20 -> l1 = 17.0;3*17.0 + 2 + l2 = 100 -> l2 = 47.0
故观测器增益 L = [17.0, 47.0]
核对:特征值 = -10.0 与 -10.0
分离原理:状态反馈增益 K 与观测器增益 L 可以各自独立设计,互不影响注意 L = [17, 47] 比 K = [23, 7] 里那个 47 大得多,这正是"观测器要更快"的代价:增益越大,对测量噪声越敏感。工程上取观测器极点的经验法则是比控制器极点快 2 到 5 倍——这个例子里取的是 2 倍(-10 对 -5)。再快就要开始考虑噪声放大的问题了。
分离原理的验证:把 A − BK 与 A − LC 的特征值拼起来,就是整个闭环系统的 2n 个极点。这个例子里 K 与 L 各自都是二阶问题、各算各的,互不干扰——如果没有分离原理,就得去解一个耦合的 4 阶问题。
例 6:C 实现——矩阵运算与三条判据
/* statespace.c —— 状态空间:能控能观判据、状态转移矩阵、极点配置 */
#include <stdio.h>
#include <math.h>
/* 2x2 矩阵按行存:M[2][2] */
static void mmul(const double A[2][2], const double B[2][2], double R[2][2])
{
int i, j, k;
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++) {
R[i][j] = 0.0;
for (k = 0; k < 2; k++)
R[i][j] += A[i][k] * B[k][j];
}
}
static double det2(const double M[2][2])
{
return M[0][0] * M[1][1] - M[0][1] * M[1][0];
}
/* e^(At) 的级数展开:sum_{k=0}^{n-1} (At)^k / k! */
static void expm_series(const double A[2][2], double t, int n, double R[2][2])
{
double term[2][2] = { {1.0, 0.0}, {0.0, 1.0} };
double At[2][2], tmp[2][2];
int k, i, j;
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++) {
R[i][j] = (i == j) ? 1.0 : 0.0;
At[i][j] = A[i][j] * t;
}
for (k = 1; k < n; k++) {
mmul(term, At, tmp);
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++) {
term[i][j] = tmp[i][j] / k;
R[i][j] += term[i][j];
}
}
}
int main(void)
{
const double A[2][2] = { {0.0, 1.0}, {-2.0, -3.0} };
const double B[2][2] = { {0.0, 0.0}, {1.0, 0.0} }; /* 第 1 列是 B 向量 */
const double C[2][2] = { {1.0, 0.0}, {0.0, 0.0} }; /* 第 1 行是 C 向量 */
double AB[2][2], Mc[2][2], CA[2][2], Mo[2][2];
double Acl[2][2], BK[2][2], K[2][2], M[2][2];
const double ts[] = { 0.0, 0.5, 1.0, 2.0 };
int i, j;
printf("=== 一、系统矩阵与特征方程 ===\n");
printf(" A = [[0, 1], [-2, -3]],B = [[0], [1]],C = [[1, 0]]\n");
printf(" 迹 = %.1f,det = %.1f\n", A[0][0] + A[1][1], det2(A));
printf(" 特征方程 s^2 - 迹*s + det = s^2 + %.1f s + %.1f -> 特征值 -1、-2\n",
-(A[0][0] + A[1][1]), det2(A));
printf("\n=== 二、状态转移矩阵 e^(At)(级数 40 项)===\n");
for (i = 0; i < 4; i++) {
expm_series(A, ts[i], 40, M);
printf(" t = %4.2f e^At = [%+.6f %+.6f; %+.6f %+.6f]\n",
ts[i], M[0][0], M[0][1], M[1][0], M[1][1]);
}
printf("\n=== 三、能控性与能观性 ===\n");
mmul(A, B, AB);
for (i = 0; i < 2; i++) {
Mc[i][0] = B[i][0];
Mc[i][1] = AB[i][0];
}
printf(" Mc = [B AB] = [[%.0f, %.0f], [%.0f, %.0f]],det = %.1f\n",
Mc[0][0], Mc[0][1], Mc[1][0], Mc[1][1], det2(Mc));
mmul(C, A, CA);
for (j = 0; j < 2; j++) {
Mo[0][j] = C[0][j];
Mo[1][j] = CA[0][j];
}
printf(" Mo = [C; CA] = [[%.0f, %.0f], [%.0f, %.0f]],det = %.1f\n",
Mo[0][0], Mo[0][1], Mo[1][0], Mo[1][1], det2(Mo));
printf(" 两个行列式都非零 -> 既完全能控、又完全能观\n");
printf("\n=== 四、极点配置:K = [23, 7],目标极点 -5、-5 ===\n");
K[0][0] = 23.0;
K[0][1] = 7.0;
mmul(B, K, BK);
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++)
Acl[i][j] = A[i][j] - BK[i][j];
printf(" A - BK = [[%.1f, %.1f], [%.1f, %.1f]]\n",
Acl[0][0], Acl[0][1], Acl[1][0], Acl[1][1]);
printf(" 迹 = %.1f(应为 -10),det = %.1f(应为 25)\n",
Acl[0][0] + Acl[1][1], det2(Acl));
printf(" 闭环传递函数 1/(s^2+10s+25),直流增益 = 1/25 = %.6f\n", 1.0 / 25.0);
printf(" 要消除静差需前置增益 N = 25(否则 e_ss = 1 - 0.04 = 0.96)\n");
printf("\n=== 五、状态观测器:L = [17, 47],目标极点 -10、-10 ===\n");
{
double l1 = 17.0, l2 = 47.0;
double b = 3.0 + l1, c = 3.0 * l1 + 2.0 + l2;
double disc = b * b - 4.0 * c;
printf(" A - LC = [[-%.0f, 1], [%.0f, -3]]\n", l1, -2.0 - l2);
printf(" 特征多项式 s^2 + %.0f s + %.0f\n", b, c);
printf(" 特征值 = %.1f 与 %.1f\n",
(-b + sqrt(disc)) / 2.0, (-b - sqrt(disc)) / 2.0);
}
printf(" 分离原理:K 与 L 可各自独立设计,互不影响\n");
return 0;
}
c 本站为静态站,不提供在线运行;可复制到本地用 gcc / python 执行
预期输出:
=== 一、系统矩阵与特征方程 ===
A = [[0, 1], [-2, -3]],B = [[0], [1]],C = [[1, 0]]
迹 = -3.0,det = 2.0
特征方程 s^2 - 迹*s + det = s^2 + 3.0 s + 2.0 -> 特征值 -1、-2
=== 二、状态转移矩阵 e^(At)(级数 40 项)===
t = 0.00 e^At = [+1.000000 +0.000000; +0.000000 +1.000000]
t = 0.50 e^At = [+0.845182 +0.238651; -0.477302 +0.129228]
t = 1.00 e^At = [+0.600424 +0.232544; -0.465088 -0.097209]
t = 2.00 e^At = [+0.252355 +0.117020; -0.234039 -0.098704]
=== 三、能控性与能观性 ===
Mc = [B AB] = [[0, 1], [1, -3]],det = -1.0
Mo = [C; CA] = [[1, 0], [0, 1]],det = 1.0
两个行列式都非零 -> 既完全能控、又完全能观
=== 四、极点配置:K = [23, 7],目标极点 -5、-5 ===
A - BK = [[0.0, 1.0], [-25.0, -10.0]]
迹 = -10.0(应为 -10),det = 25.0(应为 25)
闭环传递函数 1/(s^2+10s+25),直流增益 = 1/25 = 0.040000
要消除静差需前置增益 N = 25(否则 e_ss = 1 - 0.04 = 0.96)
=== 五、状态观测器:L = [17, 47],目标极点 -10、-10 ===
A - LC = [[-17, 1], [-49, -3]]
特征多项式 s^2 + 20 s + 100
特征值 = -10.0 与 -10.0
分离原理:K 与 L 可各自独立设计,互不影响这段代码里有一个值得注意的"工程折中":B 与 C 都被写成了 2×2 矩阵(真正的向量只占其中一列/一行),而不是用紧凑的一维数组。
c
const double B[2][2] = { {0.0, 0.0}, {1.0, 0.0} }; /* 第 1 列是 B 向量 */
const double C[2][2] = { {1.0, 0.0}, {0.0, 0.0} }; /* 第 1 行是 C 向量 */好处是 mmul 这一个函数就能同时处理 AB、CA、BK 三种乘法(都是"2×2 乘 2×2"),代价是浪费一半存储、并且要靠注释说清"哪一列是真数据"。 对这个规模的问题,这个折中划算;如果状态维数上到几十,就该换成通用维数的矩阵库了。"用最简单的方式凑到能跑,并在注释里说明哪个维度是哑的",是嵌入式数值代码里的常见做法。
例 7:Python——能控能观、e^{At} 双路径、两个增益设计
# 状态空间:能控能观判据、状态转移矩阵、极点配置
import math
def mmul(A, B):
return [[sum(A[i][k] * B[k][j] for k in range(len(B))) for j in range(len(B[0]))]
for i in range(len(A))]
def madd(A, B):
return [[A[i][j] + B[i][j] for j in range(len(A[0]))] for i in range(len(A))]
def mscale(A, s):
return [[A[i][j] * s for j in range(len(A[0]))] for i in range(len(A))]
def hstack(A, B):
return [A[i] + B[i] for i in range(len(A))]
def vstack(A, B):
return A + B
def det2(M):
return M[0][0] * M[1][1] - M[0][1] * M[1][0]
print("=== 一、系统矩阵与特征值 ===")
A = [[0.0, 1.0], [-2.0, -3.0]]
B = [[0.0], [1.0]]
C = [[1.0, 0.0]]
print(" A = [[0, 1], [-2, -3]],B = [[0], [1]],C = [[1, 0]]")
a1, a0 = A[1][1] + A[0][0], det2(A)
print(f" 特征方程 s^2 - (迹)s + det = s^2 + {-(a1):.1f}s + {a0:.1f}"
f" -> 特征值 s = -1, -2")
print(" 传递函数 G(s) = C(sI-A)^-1 B = 1/(s^2 + 3s + 2)")
print("\n=== 二、状态转移矩阵 e^(At):解析式与级数两条路径 ===")
def eAt_closed(t):
e1, e2 = math.exp(-t), math.exp(-2 * t) # Cayley-Hamilton 闭式解
return [[2 * e1 - e2, e1 - e2], [-2 * e1 + 2 * e2, -e1 + 2 * e2]]
def eAt_series(t, n=40):
M = [[1.0, 0.0], [0.0, 1.0]]
term = [[1.0, 0.0], [0.0, 1.0]]
for k in range(1, n):
term = mscale(mmul(term, A), t / k)
M = madd(M, term)
return M
print(" t e^(At) 闭式解(行优先展开) 与级数(40项)的逐元素最大差")
for t in (0.0, 0.5, 1.0, 2.0):
m1, m2 = eAt_closed(t), eAt_series(t)
d = max(abs(m1[i][j] - m2[i][j]) for i in range(2) for j in range(2))
f1 = f"[{m1[0][0]:+.6f} {m1[0][1]:+.6f}; {m1[1][0]:+.6f} {m1[1][1]:+.6f}]"
print(f" {t:5.2f} {f1} {d:.3e}")
print("\n=== 三、能控性与能观性 ===")
Mc = hstack(B, mmul(A, B))
Mo = vstack(C, mmul(C, A))
print(f" 能控性矩阵 Mc = [B AB] = [[{Mc[0][0]:.0f}, {Mc[0][1]:.0f}], "
f"[{Mc[1][0]:.0f}, {Mc[1][1]:.0f}]],det = {det2(Mc):.1f}")
print(f" 能观性矩阵 Mo = [C; CA] = [[{Mo[0][0]:.0f}, {Mo[0][1]:.0f}], "
f"[{Mo[1][0]:.0f}, {Mo[1][1]:.0f}]],det = {det2(Mo):.1f}")
print(" 两个行列式都非零 -> 既完全能控、又完全能观")
print("\n=== 四、极点配置:把闭环极点放到 -5、-5 ===")
print(" 目标特征多项式 (s+5)^2 = s^2 + 10s + 25")
print(" A - BK = [[0, 1], [-2-k1, -3-k2]],其特征多项式为 s^2 + (3+k2)s + (2+k1)")
k1, k2 = 25.0 - 2.0, 10.0 - 3.0
print(f" 对照系数:3 + k2 = 10 -> k2 = {k2:.1f};2 + k1 = 25 -> k1 = {k1:.1f}")
print(f" 故反馈增益 K = [{k1:.1f}, {k2:.1f}]")
Acl = madd(A, mscale(mmul(B, [[k1, k2]]), -1.0))
print(f" 核对:A - BK = [[{Acl[0][0]:.1f}, {Acl[0][1]:.1f}], "
f"[{Acl[1][0]:.1f}, {Acl[1][1]:.1f}]],"
f"迹 = {Acl[0][0] + Acl[1][1]:.1f}(应为 -10),det = {det2(Acl):.1f}(应为 25)")
print("\n=== 五、状态反馈后的稳态误差与前置增益 ===")
print(" 闭环传递函数 G_cl(s) = 1/(s^2 + 10s + 25),直流增益 = 1/25 = 0.040000")
N = 25.0
print(f" 要让阶跃输入的稳态输出为 1,需串入前置增益 N = {N:.1f}")
print(f" 换算成稳态误差:无 N 时 e_ss = 1 - 0.04 = 0.96;加 N 后 e_ss = 0")
print("\n=== 六、全维状态观测器:把观测器极点放到 -10、-10 ===")
print(" A - LC = [[-l1, 1], [-2-l2, -3]],特征多项式 s^2 + (3+l1)s + (3*l1 + 2 + l2)")
l1 = 20.0 - 3.0
l2 = 100.0 - 3.0 * l1 - 2.0
print(f" 3 + l1 = 20 -> l1 = {l1:.1f};3*{l1:.1f} + 2 + l2 = 100 -> l2 = {l2:.1f}")
print(f" 故观测器增益 L = [{l1:.1f}, {l2:.1f}]")
bb = 3.0 + l1
de = 3.0 * l1 + 2.0 + l2
disc = bb * bb - 4.0 * de
r1 = (-bb + math.sqrt(disc)) / 2.0
r2 = (-bb - math.sqrt(disc)) / 2.0
print(f" 核对:特征值 = {r1:.1f} 与 {r2:.1f}")
print(" 分离原理:状态反馈增益 K 与观测器增益 L 可以各自独立设计,互不影响")
python 本站为静态站,不提供在线运行;可复制到本地用 gcc / python 执行
预期输出:
=== 一、系统矩阵与特征值 ===
A = [[0, 1], [-2, -3]],B = [[0], [1]],C = [[1, 0]]
特征方程 s^2 - (迹)s + det = s^2 + 3.0s + 2.0 -> 特征值 s = -1, -2
传递函数 G(s) = C(sI-A)^-1 B = 1/(s^2 + 3s + 2)
=== 二、状态转移矩阵 e^(At):解析式与级数两条路径 ===
t e^(At) 闭式解(行优先展开) 与级数(40项)的逐元素最大差
0.00 [+1.000000 +0.000000; +0.000000 +1.000000] 0.000e+00
0.50 [+0.845182 +0.238651; -0.477302 +0.129228] 1.110e-16
1.00 [+0.600424 +0.232544; -0.465088 -0.097209] 3.331e-16
2.00 [+0.252355 +0.117020; -0.234039 -0.098704] 1.887e-15
=== 三、能控性与能观性 ===
能控性矩阵 Mc = [B AB] = [[0, 1], [1, -3]],det = -1.0
能观性矩阵 Mo = [C; CA] = [[1, 0], [0, 1]],det = 1.0
两个行列式都非零 -> 既完全能控、又完全能观
=== 四、极点配置:把闭环极点放到 -5、-5 ===
目标特征多项式 (s+5)^2 = s^2 + 10s + 25
A - BK = [[0, 1], [-2-k1, -3-k2]],其特征多项式为 s^2 + (3+k2)s + (2+k1)
对照系数:3 + k2 = 10 -> k2 = 7.0;2 + k1 = 25 -> k1 = 23.0
故反馈增益 K = [23.0, 7.0]
核对:A - BK = [[0.0, 1.0], [-25.0, -10.0]],迹 = -10.0(应为 -10),det = 25.0(应为 25)
=== 五、状态反馈后的稳态误差与前置增益 ===
闭环传递函数 G_cl(s) = 1/(s^2 + 10s + 25),直流增益 = 1/25 = 0.040000
要让阶跃输入的稳态输出为 1,需串入前置增益 N = 25.0
换算成稳态误差:无 N 时 e_ss = 1 - 0.04 = 0.96;加 N 后 e_ss = 0
=== 六、全维状态观测器:把观测器极点放到 -10、-10 ===
A - LC = [[-l1, 1], [-2-l2, -3]],特征多项式 s^2 + (3+l1)s + (3*l1 + 2 + l2)
3 + l1 = 20 -> l1 = 17.0;3*17.0 + 2 + l2 = 100 -> l2 = 47.0
故观测器增益 L = [17.0, 47.0]
核对:特征值 = -10.0 与 -10.0
分离原理:状态反馈增益 K 与观测器增益 L 可以各自独立设计,互不影响第六段那句"分离原理"是这一章最实用的结论:它意味着两个 n 阶问题可以分开解,而不是去啃一个 2n 阶耦合问题。在工程上,这是"把大问题拆小"的典范——和 软工的模块化 是同一种思维方式:先找到可以让两块互不干扰的条件,然后在条件成立时把问题切开。
考点
- 状态变量的个数恰好是系统阶数
n:多一个冗余、少一个描述不全。 - 能控标准型的元素规律:
A最后一行是特征多项式系数取负倒序,上三角错位单位阵;B最后一个元素为 1;C第一个元素为分子系数。 G(s) = C(sI−A)⁻¹B + D;G(s)的极点就是A的特征值(无零极点对消时)。- 相似变换不改变
G(s)与特征值:A' = TAT⁻¹、B' = TB、C' = CT⁻¹——内部表示不唯一,外部行为唯一。 - 状态转移矩阵四条性质:
e^{A·0} = I、d/dt e^{At} = A e^{At}、(e^{At})⁻¹ = e^{-At}、e^{A(t1+t2)} = e^{At1}e^{At2}。 e^{At}两条计算路径:级数Σ(At)^k/k!(数值)与 Cayley-Hamilton 降阶后α0I + α1A(手算闭式解)。手算时用t = 0是否为I做快速自检。- 全解 = 零输入响应 + 零状态响应:
x(t) = e^{At}x(0) + ∫₀ᵗ e^{A(t−τ)}Bu(τ)dτ。 - 能控判据
rank[B AB … A^{n−1}B] = n;能观判据rank[C; CA; …; CA^{n−1}] = n。判据用秩,不用行列式(多入多出时矩阵不是方的)。 - 对偶性:
(A,B,C)的能控 ⟺(Aᵀ,Cᵀ,Bᵀ)的能观;这是分离原理的数学根据。 - 能任意配置极点 ⟺ 系统能控——能控性是"能不能设计控制器"的资格线。
- 状态反馈不改变零点,因此消不掉静差;要消差需加前置增益
N(按模型算,模型不准就失准)或加积分器。 - 观测器误差方程
ė = (A − LC)e完全自主(与u、x无关);观测器极点通常比控制器极点快 2~5 倍(否则估计误差拖累控制;再快则放大噪声)。 - 易错:把能控性矩阵写成
[AB B]顺序颠倒;把K的符号搞反(u = −Kx才有A − BK);以为状态反馈能改善静差;把"传递函数极点"当成"系统全部极点"(被对消的不可控/不可观模态在传递函数里消失了);用行列式判据处理多输入系统。
小结
- 状态空间把
n阶系统拆成n个一阶方程:x' = Ax + Bu、y = Cx + Du。 - 能控标准型元素规整,看一眼矩阵就知道原传递函数系数;
A的特征值就是G(s)的极点。 - 状态转移矩阵
e^{At}是解的核心,四条性质必背;计算有级数与 Cayley-Hamilton 两条路,两条路互证是可靠的验证方式。 - 能控性与能观性是状态空间法独有的两个概念,判据都是秩等于
n,且互为对偶。 - 能控 ⟺ 能任意配置极点(
u = −Kx,闭环为A − BK);二阶用对比系数求K最省事。 - 状态反馈不改零点、消不掉静差:本例题里直流增益只有
0.04,需前置增益N = 25;这不如 PID 的I项鲁棒。 - 观测器误差方程
ė = (A − LC)e自主,故L可独立设计;分离原理让控制器与观测器分开算。 - 观测器极点要快于控制器极点(2~5 倍),但受噪声限制。
回到主线:这一章把系统换成了"内部状态"的语言,得到了能控、能观、极点任意配置三条硬结论,也看到了状态反馈比 PID 精确但更依赖模型的取舍。但"极点放在哪最好"这个问题,本章是用经验回答的(比如"放到 -5")。
下一章给出一个不是经验的答案:不指定极点,而是指定"什么该省、什么该罚",让数学自己算出最优解——这就是最优控制与 LQR。
下一篇:现代控制理论基础
评论(0)
当前浏览器不允许本地存储,评论无法保存。
还没有评论,来说两句。