控制理论基础

1.1 控制理论基础

控制系统理论是人工智能医疗设备的核心数学基础之一。从胰岛素泵的自动血糖调节到呼吸机的通气控制,从心脏起搏器的频率自适应到手术机器人的精准定位,控制系统无处不在。本节将系统介绍控制理论基础,并通过胰岛素泵闭环控制的医疗案例,展示理论如何指导实践。

1.1.1 控制系统基本概念

开环控制与闭环控制

定义1.1(开环控制系统) 开环控制系统是指控制器的输出只依赖于输入信号,而不依赖于系统输出的控制系统。其结构可表示为:

输入→控制器→被控对象→输出 \text{输入} \rightarrow \text{控制器} \rightarrow \text{被控对象} \rightarrow \text{输出} 输入→控制器→被控对象→输出

定义1.2(闭环控制系统) 闭环控制系统是指控制器的输出不仅依赖于输入信号,还依赖于系统输出的控制系统。通过反馈机制,系统可以自动调节以减小误差。其结构可表示为:

输入→+误差→控制器→被控对象→−输出 \text{输入} \xrightarrow{+} \text{误差} \rightarrow \text{控制器} \rightarrow \text{被控对象} \xrightarrow{-} \text{输出} 输入+ 误差→控制器→被控对象− 输出

数学描述:

设参考输入为 r(t)r(t)r(t),系统输出为 y(t)y(t)y(t),则误差信号定义为:

e(t)=r(t)−y(t) e(t) = r(t) - y(t) e(t)=r(t)−y(t)

控制器的输出 u(t)u(t)u(t) 是误差信号的函数:

u(t)=f(e(t)) u(t) = f(e(t)) u(t)=f(e(t))

其中 f(⋅)f(\cdot)f(⋅) 是控制律,决定了控制系统的性能。

控制系统性能指标

控制系统的主要性能指标包括:

1. 稳定性: 系统在有界输入下产生有界输出(BIBO稳定性)。

2. 稳态误差: 系统稳态时输出与期望值的偏差:

ess=lim⁡t→∞e(t)=lim⁡t→∞[r(t)−y(t)] e_{ss} = \lim_{t \to \infty} e(t) = \lim_{t \to \infty} [r(t) - y(t)] ess=t→∞lime(t)=t→∞lim[r(t)−y(t)]

3. 上升时间 : 系统输出从稳态值的10%上升到90%所需的时间 trt_rtr。

4. 超调量: 系统输出最大值与稳态值之差占稳态值的百分比:

Mp=ymax⁡−yssyss×100% M_p = \frac{y_{\max} - y_{ss}}{y_{ss}} \times 100\% Mp=yssymax−yss×100%

5. 调节时间 : 系统输出进入并保持在稳态值附近±5%\pm 5\%±5%(或±2%\pm 2\%±2%)误差带内所需的时间 tst_sts。

传递函数

定义1.3(传递函数) 线性时不变系统在零初始条件下,输出的拉普拉斯变换与输入的拉普拉斯变换之比称为传递函数。

设系统的输入为 u(t)u(t)u(t),输出为 y(t)y(t)y(t),则传递函数定义为:

G(s)=Y(s)U(s)=L[y(t)]L[u(t)] G(s) = \frac{Y(s)}{U(s)} = \frac{\mathcal{L}[y(t)]}{\mathcal{L}[u(t)]} G(s)=U(s)Y(s)=L[u(t)]L[y(t)]

其中 L[⋅]\mathcal{L}[\cdot]L[⋅] 表示拉普拉斯变换。

典型环节的传递函数:

环节类型 传递函数 医疗应用示例
比例环节 G(s)=KG(s) = KG(s)=K 放大器、传感器
积分环节 G(s)=1TsG(s) = \frac{1}{Ts}G(s)=Ts1 药物累积效应
微分环节 G(s)=TsG(s) = TsG(s)=Ts 信号预处理
惯性环节 G(s)=KTs+1G(s) = \frac{K}{Ts+1}G(s)=Ts+1K 血糖响应
振荡环节 G(s)=Kωn2s2+2ζωns+ωn2G(s) = \frac{K\omega_n^2}{s^2 + 2\zeta\omega_n s + \omega_n^2}G(s)=s2+2ζωns+ωn2Kωn2 机械振动系统

典型系统的传递函数推导

例1.1(一阶系统) 考虑药物在体内的代谢过程。设血液中药物浓度为 c(t)c(t)c(t),药物注入速率为 u(t)u(t)u(t),消除速率常数为 kkk,则药物动力学方程为:

dc(t)dt=−kc(t)+u(t)Vd \frac{dc(t)}{dt} = -kc(t) + \frac{u(t)}{V_d} dtdc(t)=−kc(t)+Vdu(t)

其中 VdV_dVd 为分布容积。

对两边进行拉普拉斯变换(零初始条件):

sC(s)=−kC(s)+U(s)Vd sC(s) = -kC(s) + \frac{U(s)}{V_d} sC(s)=−kC(s)+VdU(s)

整理得传递函数:

G(s)=C(s)U(s)=1/Vds+k=KTs+1 G(s) = \frac{C(s)}{U(s)} = \frac{1/V_d}{s + k} = \frac{K}{Ts + 1} G(s)=U(s)C(s)=s+k1/Vd=Ts+1K

其中 K=1kVdK = \frac{1}{kV_d}K=kVd1 为稳态增益,T=1kT = \frac{1}{k}T=k1 为时间常数。

物理解释:

  • 时间常数 TTT 反映药物消除的快慢,TTT 越大,药物在体内停留时间越长
  • 稳态增益 KKK 反映稳态时药物浓度与注射速率的关系

1.1.2 状态空间模型

状态空间表示

对于复杂系统,传递函数方法可能不够直观。状态空间方法提供了一种更灵活的系统描述方式。

定义1.4(状态空间模型) 线性时不变系统的状态空间模型表示为:

x˙(t)=Ax(t)+Bu(t) \dot{\mathbf{x}}(t) = \mathbf{A}\mathbf{x}(t) + \mathbf{B}\mathbf{u}(t) x˙(t)=Ax(t)+Bu(t)

y(t)=Cx(t)+Du(t) \mathbf{y}(t) = \mathbf{C}\mathbf{x}(t) + \mathbf{D}\mathbf{u}(t) y(t)=Cx(t)+Du(t)

其中:

  • x(t)∈Rn\mathbf{x}(t) \in \mathbb{R}^nx(t)∈Rn: 状态向量
  • u(t)∈Rm\mathbf{u}(t) \in \mathbb{R}^mu(t)∈Rm: 输入向量
  • y(t)∈Rp\mathbf{y}(t) \in \mathbb{R}^py(t)∈Rp: 输出向量
  • A∈Rn×n\mathbf{A} \in \mathbb{R}^{n \times n}A∈Rn×n: 状态转移矩阵
  • B∈Rn×m\mathbf{B} \in \mathbb{R}^{n \times m}B∈Rn×m: 输入矩阵
  • C∈Rp×n\mathbf{C} \in \mathbb{R}^{p \times n}C∈Rp×n: 输出矩阵
  • D∈Rp×m\mathbf{D} \in \mathbb{R}^{p \times m}D∈Rp×m: 前馈矩阵

从传递函数到状态空间

给定传递函数:

G(s)=bn−1sn−1+⋯+b1s+b0sn+an−1sn−1+⋯+a1s+a0 G(s) = \frac{b_{n-1}s^{n-1} + \cdots + b_1s + b_0}{s^n + a_{n-1}s^{n-1} + \cdots + a_1s + a_0} G(s)=sn+an−1sn−1+⋯+a1s+a0bn−1sn−1+⋯+b1s+b0

可控标准型实现:

A=[010⋯0001⋯0⋮⋮⋮⋱⋮000⋯1−a0−a1−a2⋯−an−1],B=[00⋮01] \mathbf{A} = \begin{bmatrix} 0 & 1 & 0 & \cdots & 0 \\ 0 & 0 & 1 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & 1 \\ -a_0 & -a_1 & -a_2 & \cdots & -a_{n-1} \end{bmatrix}, \quad \mathbf{B} = \begin{bmatrix} 0 \\ 0 \\ \vdots \\ 0 \\ 1 \end{bmatrix} A= 00⋮0−a010⋮0−a101⋮0−a2⋯⋯⋱⋯⋯00⋮1−an−1 ,B= 00⋮01

C=[b0b1b2⋯bn−1],D=0 \mathbf{C} = \begin{bmatrix} b_0 & b_1 & b_2 & \cdots & b_{n-1} \end{bmatrix}, \quad \mathbf{D} = 0 C=[b0b1b2⋯bn−1],D=0

例1.2(二阶系统状态空间表示) 考虑血糖调节系统,传递函数为:

G(s)=1s2+2s+1 G(s) = \frac{1}{s^2 + 2s + 1} G(s)=s2+2s+11

可控标准型实现:

A=[01−1−2],B=[01] \mathbf{A} = \begin{bmatrix} 0 & 1 \\ -1 & -2 \end{bmatrix}, \quad \mathbf{B} = \begin{bmatrix} 0 \\ 1 \end{bmatrix} A=[0−11−2],B=[01]

C=[10],D=0 \mathbf{C} = \begin{bmatrix} 1 & 0 \end{bmatrix}, \quad \mathbf{D} = 0 C=[10],D=0

状态方程的解

定理1.1(状态方程的解) 齐次状态方程 x˙(t)=Ax(t)\dot{\mathbf{x}}(t) = \mathbf{A}\mathbf{x}(t)x˙(t)=Ax(t) 的解为:

x(t)=eAtx(0) \mathbf{x}(t) = e^{\mathbf{A}t}\mathbf{x}(0) x(t)=eAtx(0)

其中 eAte^{\mathbf{A}t}eAt 称为状态转移矩阵,定义为:

eAt=I+At+(At)22!+(At)33!+⋯=∑k=0∞(At)kk! e^{\mathbf{A}t} = \mathbf{I} + \mathbf{A}t + \frac{(\mathbf{A}t)^2}{2!} + \frac{(\mathbf{A}t)^3}{3!} + \cdots = \sum_{k=0}^{\infty} \frac{(\mathbf{A}t)^k}{k!} eAt=I+At+2!(At)2+3!(At)3+⋯=k=0∑∞k!(At)k

非齐次状态方程的解:

x(t)=eA(t−t0)x(t0)+∫t0teA(t−τ)Bu(τ)dτ \mathbf{x}(t) = e^{\mathbf{A}(t-t_0)}\mathbf{x}(t_0) + \int_{t_0}^{t} e^{\mathbf{A}(t-\tau)}\mathbf{B}\mathbf{u}(\tau)d\tau x(t)=eA(t−t0)x(t0)+∫t0teA(t−τ)Bu(τ)dτ

离散时间状态空间模型

在数字控制系统中,需要使用离散时间模型:

x[k+1]=Adx[k]+Bdu[k] \mathbf{x}[k+1] = \mathbf{A}_d\mathbf{x}[k] + \mathbf{B}_d\mathbf{u}[k] x[k+1]=Adx[k]+Bdu[k]

y[k]=Cx[k]+Du[k] \mathbf{y}[k] = \mathbf{C}\mathbf{x}[k] + \mathbf{D}\mathbf{u}[k] y[k]=Cx[k]+Du[k]

其中离散化公式为:

Ad=eATs,Bd=∫0TseAτdτ⋅B \mathbf{A}_d = e^{\mathbf{A}T_s}, \quad \mathbf{B}_d = \int_0^{T_s} e^{\mathbf{A}\tau}d\tau \cdot \mathbf{B} Ad=eATs,Bd=∫0TseAτdτ⋅B

TsT_sTs 为采样周期。

可控性与可观测性

在医疗设备控制中,可控性和可观测性是评估系统是否能被有效控制的两个基本概念。这两个概念对于胰岛素泵、麻醉深度控制等医疗系统的设计至关重要。

可控性

定义1.5(可控性) 对于线性时不变系统,如果存在一个控制输入,能够在有限时间内将系统从任意初始状态转移到任意目标状态,则称系统是完全可控的。

可控性判据: 系统可控的充要条件是可控性矩阵满秩,即:

rank(C)=n \text{rank}(\mathcal{C}) = n rank(C)=n

其中可控性矩阵定义为:

C=[BABA2B⋯An−1B] \mathcal{C} = \begin{bmatrix} \mathbf{B} & \mathbf{A}\mathbf{B} & \mathbf{A}^2\mathbf{B} & \cdots & \mathbf{A}^{n-1}\mathbf{B} \end{bmatrix} C=[BABA2B⋯An−1B]

医疗应用示例: 考虑输液泵系统,其状态空间模型为:

$$

\begin{bmatrix}
\dot{c}_1 \
\dot{c}_2
\end{bmatrix}

\begin{bmatrix}

-k_1 & 0 \

k_1 & -k_2

\end{bmatrix}

\begin{bmatrix}

c_1 \

c_2

\end{bmatrix}

\begin{bmatrix}

1/V_1 \

0

\end{bmatrix}

u

其中c1c_1c1为中央室药物浓度,c2c_2c2为周边室浓度,uuu为输液速率。 可控性矩阵为: C=\[1V1−k1V10k1V2\] \\mathcal{C} = \\begin{bmatrix} \\frac{1}{V_1} \& -\\frac{k_1}{V_1} \\\\ 0 \& \\frac{k_1}{V_2} \\end{bmatrix} C=\[V110−V1k1V2k1\] 当k1≠0k_1 \\neq 0k1=0时,det⁡(C)=k1V1V2≠0\\det(\\mathcal{C}) = \\frac{k_1}{V_1 V_2} \\neq 0det(C)=V1V2k1=0,系统可控。这表明通过调节输液速率,可以控制中央室和周边室的药物浓度,这对于药物剂量调节具有重要意义。 **不可控系统的医疗意义**: 若系统不可控,意味着存在某些状态无法通过控制输入来改变。在医疗系统中,这可能提示: * 某些生理参数无法通过当前控制手段调节 * 需要增加控制输入或改变给药方式 ##### 可观测性 **定义1.6(可观测性)** 对于线性时不变系统,如果能够通过有限时间内的输出测量值,唯一确定系统的初始状态,则称系统是完全可观测的。 **可观测性判据**: 系统可观测的充要条件是可观测性矩阵满秩,即: rank(O)=n \\text{rank}(\\mathcal{O}) = n rank(O)=n 其中可观测性矩阵定义为: O=\[CCACA2⋮CAn−1\] \\mathcal{O} = \\begin{bmatrix} \\mathbf{C} \\\\ \\mathbf{C}\\mathbf{A} \\\\ \\mathbf{C}\\mathbf{A}\^2 \\\\ \\vdots \\\\ \\mathbf{C}\\mathbf{A}\^{n-1} \\end{bmatrix} O= CCACA2⋮CAn−1 **医疗应用示例** : 在血糖监测系统中,状态变量包括血糖浓度和胰岛素作用量,但通常只能测量血糖。设输出矩阵C=\[10\]\\mathbf{C} = \\begin{bmatrix} 1 \& 0 \\end{bmatrix}C=\[10\],可观测性矩阵为: O=\[10−p1−Gb\] \\mathcal{O} = \\begin{bmatrix} 1 \& 0 \\\\ -p_1 \& -G_b \\end{bmatrix} O=\[1−p10−Gb\] 当Gb≠0G_b \\neq 0Gb=0时,det⁡(O)=−Gb≠0\\det(\\mathcal{O}) = -G_b \\neq 0det(O)=−Gb=0,系统可观测。这表明仅通过血糖测量,可以估计胰岛素作用状态,为闭环控制提供了理论基础。 **对偶性** : 可控性和可观测性存在对偶关系。系统(A,B)(\\mathbf{A}, \\mathbf{B})(A,B)可控等价于系统(AT,BT)(\\mathbf{A}\^T, \\mathbf{B}\^T)(AT,BT)可观测。这一性质在控制器和观测器设计中广泛应用。 ### 1.1.3 稳定性分析 稳定是控制系统设计的首要要求。本小节介绍Lyapunov稳定性理论,这是分析线性和非线性系统稳定性的强大工具。 #### Lyapunov稳定性定义 **定义1.7(Lyapunov稳定性)** 考虑自治系统 x˙=f(x)\\dot{\\mathbf{x}} = \\mathbf{f}(\\mathbf{x})x˙=f(x),平衡点为 xe\\mathbf{x}_exe。 1. **稳定** : 如果对于任意 ϵ\>0\\epsilon \> 0ϵ\>0,存在 δ\>0\\delta \> 0δ\>0,使得当 ∥x(0)−xe∥\<δ\\\|\\mathbf{x}(0) - \\mathbf{x}_e\\\| \< \\delta∥x(0)−xe∥\<δ 时,对所有 t≥0t \\geq 0t≥0 有 ∥x(t)−xe∥\<ϵ\\\|\\mathbf{x}(t) - \\mathbf{x}_e\\\| \< \\epsilon∥x(t)−xe∥\<ϵ。 2. **渐近稳定** : 如果稳定,且存在 δ\>0\\delta \> 0δ\>0,使得当 ∥x(0)−xe∥\<δ\\\|\\mathbf{x}(0) - \\mathbf{x}_e\\\| \< \\delta∥x(0)−xe∥\<δ 时,lim⁡t→∞∥x(t)−xe∥=0\\lim_{t \\to \\infty} \\\|\\mathbf{x}(t) - \\mathbf{x}_e\\\| = 0limt→∞∥x(t)−xe∥=0。 3. **全局渐近稳定** : 如果渐近稳定,且对任意初始状态都有 lim⁡t→∞∥x(t)−xe∥=0\\lim_{t \\to \\infty} \\\|\\mathbf{x}(t) - \\mathbf{x}_e\\\| = 0limt→∞∥x(t)−xe∥=0。 #### Lyapunov直接法 **定理1.2(Lyapunov稳定性定理)** 考虑自治系统 x˙=f(x)\\dot{\\mathbf{x}} = \\mathbf{f}(\\mathbf{x})x˙=f(x) 在平衡点 xe=0\\mathbf{x}_e = 0xe=0 处。如果存在标量函数 V(x):Rn→RV(\\mathbf{x}): \\mathbb{R}\^n \\to \\mathbb{R}V(x):Rn→R,满足: 1. **正定性** : V(0)=0V(0) = 0V(0)=0,且对所有 x≠0\\mathbf{x} \\neq 0x=0 有 V(x)\>0V(\\mathbf{x}) \> 0V(x)\>0 2. **导数负定性** : V˙(x)=∇VTf(x)\<0\\dot{V}(\\mathbf{x}) = \\nabla V\^T \\mathbf{f}(\\mathbf{x}) \< 0V˙(x)=∇VTf(x)\<0 (对所有 x≠0\\mathbf{x} \\neq 0x=0) 则平衡点渐近稳定。 如果 V(x)V(\\mathbf{x})V(x) 径向无界(即 ∥x∥→∞\\\|\\mathbf{x}\\\| \\to \\infty∥x∥→∞ 时 V(x)→∞V(\\mathbf{x}) \\to \\inftyV(x)→∞),则平衡点全局渐近稳定。 **例1.3(线性系统Lyapunov稳定性)** 考虑线性系统 x˙=Ax\\dot{\\mathbf{x}} = \\mathbf{A}\\mathbf{x}x˙=Ax。 选取Lyapunov函数: V(x)=xTPx V(\\mathbf{x}) = \\mathbf{x}\^T\\mathbf{P}\\mathbf{x} V(x)=xTPx 其中 P\\mathbf{P}P 为正定矩阵。则: V˙(x)=x˙TPx+xTPx˙=xT(ATP+PA)x \\dot{V}(\\mathbf{x}) = \\dot{\\mathbf{x}}\^T\\mathbf{P}\\mathbf{x} + \\mathbf{x}\^T\\mathbf{P}\\dot{\\mathbf{x}} = \\mathbf{x}\^T(\\mathbf{A}\^T\\mathbf{P} + \\mathbf{P}\\mathbf{A})\\mathbf{x} V˙(x)=x˙TPx+xTPx˙=xT(ATP+PA)x 要使 V˙(x)\<0\\dot{V}(\\mathbf{x}) \< 0V˙(x)\<0,需要: ATP+PA=−Q \\mathbf{A}\^T\\mathbf{P} + \\mathbf{P}\\mathbf{A} = -\\mathbf{Q} ATP+PA=−Q 其中 Q\\mathbf{Q}Q 为正定矩阵。这就是著名的**Lyapunov方程**。 #### Lyapunov方程求解 **定理1.3** 线性系统 x˙=Ax\\dot{\\mathbf{x}} = \\mathbf{A}\\mathbf{x}x˙=Ax 渐近稳定的充要条件是:对于任意正定矩阵 Q\\mathbf{Q}Q,Lyapunov方程 ATP+PA=−Q\\mathbf{A}\^T\\mathbf{P} + \\mathbf{P}\\mathbf{A} = -\\mathbf{Q}ATP+PA=−Q 有唯一正定解 P\\mathbf{P}P。 **重要说明**: 该定理仅适用于渐近稳定系统。对于不稳定系统,Lyapunov方程可能出现以下情况: * 方程无解(当A具有某些特殊结构时) * 有解但不正定(解P有负特征值) 因此,在使用Lyapunov方程判断稳定性时,若求解失败或解不正定,应结合特征值分析方法进行综合判断。 **求解算法**: 1. 给定正定矩阵 Q\\mathbf{Q}Q(通常取 Q=I\\mathbf{Q} = \\mathbf{I}Q=I) 2. 求解Lyapunov方程得到 P\\mathbf{P}P 3. 检验 P\\mathbf{P}P 是否正定(所有特征值 \>0\> 0\>0) 4. 若求解失败或P不正定,需检查A的特征值以判断系统稳定性 #### 线性系统稳定性判据 对于线性系统 x˙=Ax\\dot{\\mathbf{x}} = \\mathbf{A}\\mathbf{x}x˙=Ax,有以下等价稳定性条件: **定理1.4** 以下条件等价: 1. 系统渐近稳定 2. 矩阵 A\\mathbf{A}A 的所有特征值具有负实部 3. 对于任意正定矩阵 Q\\mathbf{Q}Q,Lyapunov方程有正定解 P\\mathbf{P}P 4. 传递函数的所有极点位于左半平面 **例1.4(稳定性判定)** 判断系统 x˙=Ax\\dot{\\mathbf{x}} = \\mathbf{A}\\mathbf{x}x˙=Ax 的稳定性,其中: A=\[−120−3\] \\mathbf{A} = \\begin{bmatrix} -1 \& 2 \\\\ 0 \& -3 \\end{bmatrix} A=\[−102−3\] **方法1:特征值法** 特征方程: det⁡(sI−A)=det⁡\[s+1−20s+3\]=(s+1)(s+3)=0 \\det(s\\mathbf{I} - \\mathbf{A}) = \\det\\begin{bmatrix} s+1 \& -2 \\\\ 0 \& s+3 \\end{bmatrix} = (s+1)(s+3) = 0 det(sI−A)=det\[s+10−2s+3\]=(s+1)(s+3)=0 特征值为 λ1=−1\\lambda_1 = -1λ1=−1, λ2=−3\\lambda_2 = -3λ2=−3,实部均为负,系统渐近稳定。 **方法2:Lyapunov方程法** 设 Q=I\\mathbf{Q} = \\mathbf{I}Q=I,求解: ##

\begin{bmatrix}
-1 & 0 \
2 & -3
\end{bmatrix}
\begin{bmatrix}
p_{11} & p_{12} \
p_{12} & p_{22}
\end{bmatrix}
+
\begin{bmatrix}
p_{11} & p_{12} \
p_{12} & p_{22}
\end{bmatrix}
\begin{bmatrix}
-1 & 2 \
0 & -3
\end{bmatrix}

\begin{bmatrix}

-1 & 0 \

0 & -1

\end{bmatrix}

解得: p11=12,p12=14,p22=38 p_{11} = \\frac{1}{2}, \\quad p_{12} = \\frac{1}{4}, \\quad p_{22} = \\frac{3}{8} p11=21,p12=41,p22=83 即: P=\[12141438\] \\mathbf{P} = \\begin{bmatrix} \\frac{1}{2} \& \\frac{1}{4} \\\\ \\frac{1}{4} \& \\frac{3}{8} \\end{bmatrix} P=\[21414183\] 检验正定性: * 主对角线元素 p11=12\>0p_{11} = \\frac{1}{2} \> 0p11=21\>0, p22=38\>0p_{22} = \\frac{3}{8} \> 0p22=83\>0 * 行列式 det⁡(P)=12×38−116=116\>0\\det(\\mathbf{P}) = \\frac{1}{2} \\times \\frac{3}{8} - \\frac{1}{16} = \\frac{1}{16} \> 0det(P)=21×83−161=161\>0 P\\mathbf{P}P 正定,系统渐近稳定。 ### 1.1.4 医疗应用案例:胰岛素泵闭环控制 #### 案例背景 **临床需求**: 糖尿病患者需要严格控制血糖水平。传统方法需要患者频繁检测血糖并手动注射胰岛素,负担重且效果不稳定。人工胰腺(闭环胰岛素泵系统)可以自动调节血糖,显著提高治疗效果。 **技术挑战**: 1. 血糖动力学复杂,个体差异大 2. 存在测量延迟(通常5-15分钟) 3. 胰岛素吸收和作用存在时间滞后 4. 需要保证安全性和鲁棒性 #### 血糖动力学模型 采用Bergman最小模型(Bergman Minimal Model): dG(t)dt=−p1G(t)−X(t)\[G(t)−Gb\]+Ra(t)VG \\frac{dG(t)}{dt} = -p_1 G(t) - X(t)\[G(t) - G_b\] + \\frac{R_a(t)}{V_G} dtdG(t)=−p1G(t)−X(t)\[G(t)−Gb\]+VGRa(t) dX(t)dt=−p2X(t)+p3I(t) \\frac{dX(t)}{dt} = -p_2 X(t) + p_3 I(t) dtdX(t)=−p2X(t)+p3I(t) dI(t)dt=−nI(t)+u(t)VI+γ\[G(t)−Gth\]+ \\frac{dI(t)}{dt} = -n I(t) + \\frac{u(t)}{V_I} + \\gamma\[G(t) - G_{th}\]\^+ dtdI(t)=−nI(t)+VIu(t)+γ\[G(t)−Gth\]+ 其中: * G(t)G(t)G(t): 血糖浓度(mg/dL) * X(t)X(t)X(t): 胰岛素作用变量(1/min) * I(t)I(t)I(t): 血浆胰岛素浓度(μU/mL) * u(t)u(t)u(t): 胰岛素注射速率(μU/min) * Ra(t)R_a(t)Ra(t): 葡萄糖吸收速率(mg/min) * GbG_bGb: 基础血糖浓度(mg/dL) * VG,VIV_G, V_IVG,VI: 分布容积 * p1,p2,p3,n,γp_1, p_2, p_3, n, \\gammap1,p2,p3,n,γ: 模型参数 **模型简化**: 为便于控制器设计,考虑稳态附近的小偏差线性化。设: G(t)=Gb+ΔG(t),I(t)=Ib+ΔI(t),u(t)=ub+Δu(t) G(t) = G_b + \\Delta G(t), \\quad I(t) = I_b + \\Delta I(t), \\quad u(t) = u_b + \\Delta u(t) G(t)=Gb+ΔG(t),I(t)=Ib+ΔI(t),u(t)=ub+Δu(t) **线性化注意事项** : 在Bergman模型中,内源性胰岛素分泌项 γ\[G(t)−Gth\]+\\gamma\[G(t) - G_{th}\]\^+γ\[G(t)−Gth\]+ 是一个非线性的、状态依赖的扰动项,它反映了人体胰岛β细胞的自主分泌功能。在稳态线性化时,这一项应作为外部扰动输入处理,而非纳入状态矩阵A。原因如下: 1. 内源性分泌是生理反馈机制,不应与外源性胰岛素控制输入混淆 2. 该项在稳态GbG_bGb附近的行为取决于GbG_bGb与阈值GthG_{th}Gth的关系,不能简单线性化 3. 控制器设计应关注外源性胰岛素的控制作用,而非内源性分泌 线性化后得到状态空间模型: ##

\begin{bmatrix}
\dot{\Delta G} \
\dot{X} \
\dot{\Delta I}
\end{bmatrix}

\begin{bmatrix}

-p_1 & -G_b & 0 \

0 & -p_2 & p_3 \

0 & 0 & -n

\end{bmatrix}

\begin{bmatrix}

\Delta G \

X \

\Delta I

\end{bmatrix}

\begin{bmatrix}

0 \

0 \

\frac{1}{V_I}

\end{bmatrix}

\Delta u

\begin{bmatrix}

0 \

0 \

\gamma \cdot \max(0, G_b - G_{th})

\end{bmatrix}

  • \mathbf{d}(t)

y=[100][ΔGXΔI] y = \begin{bmatrix} 1 & 0 & 0 \end{bmatrix} \begin{bmatrix} \Delta G \\ X \\ \Delta I \end{bmatrix} y=[100] ΔGXΔI

简化模型: 在控制器设计时,若忽略内源性分泌扰动(适用于1型糖尿病患者或充分抑制内源性分泌的情况),状态矩阵简化为:

A=[−p1−Gb00−p2p300−n] \mathbf{A} = \begin{bmatrix} -p_1 & -G_b & 0 \\ 0 & -p_2 & p_3 \\ 0 & 0 & -n \end{bmatrix} A= −p100−Gb−p200p3−n

注意A矩阵第三行第一列为0,而非γ。这保证了线性化模型的正确性。

PID控制器设计

PID控制律:

u(t)=Kpe(t)+Ki∫0te(τ)dτ+Kdde(t)dt u(t) = K_p e(t) + K_i \int_0^t e(\tau) d\tau + K_d \frac{de(t)}{dt} u(t)=Kpe(t)+Ki∫0te(τ)dτ+Kddtde(t)

其中:

  • e(t)=Gtarget−G(t)e(t) = G_{target} - G(t)e(t)=Gtarget−G(t): 血糖误差
  • KpK_pKp: 比例增益
  • KiK_iKi: 积分增益
  • KdK_dKd: 微分增益

参数整定方法:

  1. Ziegler-Nichols方法: 通过实验确定临界增益和临界周期
  2. 模型整定法: 根据模型参数计算最优PID参数
  3. 自适应方法: 在线调整PID参数以适应患者个体差异

传递函数形式:

PID控制器的传递函数为:

C(s)=Kp+Kis+Kds=Kds2+Kps+Kis C(s) = K_p + \frac{K_i}{s} + K_d s = \frac{K_d s^2 + K_p s + K_i}{s} C(s)=Kp+sKi+Kds=sKds2+Kps+Ki

控制系统稳定性分析

闭环系统传递函数:

T(s)=G(s)C(s)1+G(s)C(s) T(s) = \frac{G(s)C(s)}{1 + G(s)C(s)} T(s)=1+G(s)C(s)G(s)C(s)

特征方程:

1+G(s)C(s)=0 1 + G(s)C(s) = 0 1+G(s)C(s)=0

稳定性条件: 特征方程的所有根具有负实部。

例1.5(胰岛素泵稳定性分析) 设简化血糖模型传递函数为:

G(s)=K(T1s+1)(T2s+1) G(s) = \frac{K}{(T_1 s + 1)(T_2 s + 1)} G(s)=(T1s+1)(T2s+1)K

PID控制器:

C(s)=Kds2+Kps+Kis C(s) = \frac{K_d s^2 + K_p s + K_i}{s} C(s)=sKds2+Kps+Ki

特征方程:

s(T1s+1)(T2s+1)+K(Kds2+Kps+Ki)=0 s(T_1 s + 1)(T_2 s + 1) + K(K_d s^2 + K_p s + K_i) = 0 s(T1s+1)(T2s+1)+K(Kds2+Kps+Ki)=0

展开:

T1T2s3+(T1+T2+KKd)s2+(1+KKp)s+KKi=0 T_1 T_2 s^3 + (T_1 + T_2 + KK_d)s^2 + (1 + KK_p)s + KK_i = 0 T1T2s3+(T1+T2+KKd)s2+(1+KKp)s+KKi=0

应用Routh-Hurwitz判据,稳定条件:

(T1+T2+KKd)(1+KKp)>T1T2KKi (T_1 + T_2 + KK_d)(1 + KK_p) > T_1 T_2 KK_i (T1+T2+KKd)(1+KKp)>T1T2KKi

仿真实现

使用Python对胰岛素泵闭环系统进行仿真,验证控制效果。

仿真参数:

  • 模型参数: K=0.8K = 0.8K=0.8, T1=5T_1 = 5T1=5 min, T2=40T_2 = 40T2=40 min
  • PID参数: Kp=0.5K_p = 0.5Kp=0.5, Ki=0.01K_i = 0.01Ki=0.01, Kd=2K_d = 2Kd=2
  • 目标血糖: Gtarget=100G_{target} = 100Gtarget=100 mg/dL
  • 初始血糖: G(0)=150G(0) = 150G(0)=150 mg/dL
  • 仿真时间: 300 min

性能评估指标:

  1. 稳态血糖误差: ess=∣Gss−Gtarget∣e_{ss} = |G_{ss} - G_{target}|ess=∣Gss−Gtarget∣
  2. 调节时间: 血糖进入目标范围(80-120 mg/dL)的时间
  3. 超调量: 血糖最低值与目标值的偏差
  4. 安全性: 血糖始终保持在安全范围(70-180 mg/dL)

1.1.5 卡尔曼滤波

在医疗设备中,传感器测量往往存在噪声和延迟,如何从含噪测量中准确估计系统状态是一个关键问题。卡尔曼滤波提供了一种最优的状态估计方法,广泛应用于血糖估计、心率监测、呼吸频率估计等医疗场景。

卡尔曼滤波基本原理

卡尔曼滤波是一种递归的最优状态估计算法,它通过融合系统模型预测和实际测量,在最小均方误差意义下估计系统状态。

基本假设:

  1. 系统是线性的
  2. 过程噪声和测量噪声服从高斯分布且相互独立
  3. 系统模型已知

考虑以下离散时间状态空间模型:

xk+1=Adxk+Bduk+wk \mathbf{x}_{k+1} = \mathbf{A}_d \mathbf{x}_k + \mathbf{B}_d \mathbf{u}_k + \mathbf{w}_k xk+1=Adxk+Bduk+wk

yk=Cxk+vk \mathbf{y}_k = \mathbf{C} \mathbf{x}_k + \mathbf{v}_k yk=Cxk+vk

其中:

  • xk\mathbf{x}_kxk: 系统状态向量
  • uk\mathbf{u}_kuk: 控制输入
  • yk\mathbf{y}_kyk: 测量输出
  • wk∼N(0,Q)\mathbf{w}_k \sim \mathcal{N}(0, \mathbf{Q})wk∼N(0,Q): 过程噪声
  • vk∼N(0,R)\mathbf{v}_k \sim \mathcal{N}(0, \mathbf{R})vk∼N(0,R): 测量噪声

卡尔曼滤波递推公式

卡尔曼滤波包含两个步骤:预测(Prediction)和更新(Update)。

预测步骤:

状态预测:
x^k∣k−1=Adx^k−1∣k−1+Bduk−1 \hat{\mathbf{x}}_{k|k-1} = \mathbf{A}d \hat{\mathbf{x}}{k-1|k-1} + \mathbf{B}d \mathbf{u}{k-1} x^k∣k−1=Adx^k−1∣k−1+Bduk−1

协方差预测:
Pk∣k−1=AdPk−1∣k−1AdT+Q \mathbf{P}_{k|k-1} = \mathbf{A}d \mathbf{P}{k-1|k-1} \mathbf{A}_d^T + \mathbf{Q} Pk∣k−1=AdPk−1∣k−1AdT+Q

更新步骤:

卡尔曼增益计算:
Kk=Pk∣k−1CT(CPk∣k−1CT+R)−1 \mathbf{K}k = \mathbf{P}{k|k-1} \mathbf{C}^T (\mathbf{C} \mathbf{P}_{k|k-1} \mathbf{C}^T + \mathbf{R})^{-1} Kk=Pk∣k−1CT(CPk∣k−1CT+R)−1

状态更新:
x^k∣k=x^k∣k−1+Kk(yk−Cx^k∣k−1) \hat{\mathbf{x}}{k|k} = \hat{\mathbf{x}}{k|k-1} + \mathbf{K}_k (\mathbf{y}k - \mathbf{C} \hat{\mathbf{x}}{k|k-1}) x^k∣k=x^k∣k−1+Kk(yk−Cx^k∣k−1)

协方差更新:
Pk∣k=(I−KkC)Pk∣k−1 \mathbf{P}_{k|k} = (\mathbf{I} - \mathbf{K}k \mathbf{C}) \mathbf{P}{k|k-1} Pk∣k=(I−KkC)Pk∣k−1

最优性: 在高斯噪声假设下,卡尔曼滤波是所有线性估计器中最优的(最小均方误差估计)。

医疗应用示例

血糖浓度估计

在人工胰腺系统中,连续葡萄糖监测(CGM)传感器存在测量噪声和延迟,卡尔曼滤波可用于估计真实血糖水平。

状态空间模型:

  • 状态: x=[G,G˙]T\mathbf{x} = [G, \dot{G}]^Tx=[G,G˙]T (血糖浓度及其变化率)
  • 输入: uuu (胰岛素注射速率)
  • 输出: yyy (CGM测量值)

状态方程:

\\begin{bmatrix} G_{k+1} \\ \\dot{G}_{k+1} \\end{bmatrix} \\begin{bmatrix} 1 \& T_s \\ 0 \& 1 \\end{bmatrix} \\begin{bmatrix} G_k \\ \\dot{G}_k \\end{bmatrix} + \\begin{bmatrix} -\\frac{T_s\^2}{2}ISF \\ -T_s \\cdot ISF \\end{bmatrix} u_k + \\mathbf{w}_k

观测方程:
yk=[10][GkG˙k]+vk y_k = \begin{bmatrix} 1 & 0 \end{bmatrix} \begin{bmatrix} G_k \\ \dot{G}_k \end{bmatrix} + v_k yk=[10][GkG˙k]+vk

其中ISFISFISF为胰岛素敏感系数,典型值30-100 mg/dL/U。

参数选择:

  • 过程噪声协方差 Q\mathbf{Q}Q: 反映血糖动力学的不确定性,通常取对角矩阵
  • 测量噪声协方差 RRR: CGM传感器的测量方差,典型值25-225 (mg/dL)²
传感器融合

在多传感器医疗监测中,卡尔曼滤波可用于融合不同传感器的测量值。例如,在心率监测中融合ECG和PPG信号:

yk=[HRECGHRPPG]k=[11]HRk+vk \mathbf{y}k = \begin{bmatrix} HR{ECG} \\ HR_{PPG} \end{bmatrix}_k = \begin{bmatrix} 1 \\ 1 \end{bmatrix} HR_k + \mathbf{v}_k yk=[HRECGHRPPG]k=[11]HRk+vk

通过设计不同的测量噪声协方差R=diag(RECG,RPPG)\mathbf{R} = \text{diag}(R_{ECG}, R_{PPG})R=diag(RECG,RPPG),可以根据各传感器的可靠性自动加权融合。

扩展卡尔曼滤波(EKF)

对于非线性医疗系统,如非线性药物动力学模型,标准卡尔曼滤波不再适用。扩展卡尔曼滤波通过在当前估计点线性化来处理非线性系统。

考虑非线性系统:
xk+1=f(xk,uk)+wk \mathbf{x}_{k+1} = f(\mathbf{x}_k, \mathbf{u}_k) + \mathbf{w}_k xk+1=f(xk,uk)+wk
yk=h(xk)+vk \mathbf{y}_k = h(\mathbf{x}_k) + \mathbf{v}_k yk=h(xk)+vk

EKF使用雅可比矩阵进行线性化:
Fk=∂f∂x∣x^k∣k,Hk=∂h∂x∣x^k∣k−1 \mathbf{F}k = \frac{\partial f}{\partial \mathbf{x}}\bigg|{\hat{\mathbf{x}}{k|k}}, \quad \mathbf{H}k = \frac{\partial h}{\partial \mathbf{x}}\bigg|{\hat{\mathbf{x}}{k|k-1}} Fk=∂x∂f x^k∣k,Hk=∂x∂h x^k∣k−1

然后用Fk\mathbf{F}_kFk和Hk\mathbf{H}_kHk替换标准卡尔曼滤波中的Ad\mathbf{A}_dAd和C\mathbf{C}C。

医疗应用: EKF广泛应用于非线性药代动力学模型的参数估计和状态估计,如丙泊酚麻醉深度估计中的效应室浓度估计。

1.1.6 Python实现

本节提供完整的Python代码实现,包括PID控制器、状态空间模型、稳定性分析和胰岛素泵仿真。

1.6.1 PID控制器类实现

python 复制代码
"""
PID控制器实现
用于医疗设备控制系统,如胰岛素泵、呼吸机等

模块名称: pid_controller
模块功能: 实现PID控制算法
作者: 控制论专家
日期: 2026-03-15
"""

import numpy as np
from typing import Tuple, Optional, List


class PIDController:
    """
    PID控制器类
    
    实现比例-积分-微分控制器,支持抗积分饱和和微分先行。
    
    Parameters
    ----------
    Kp : float
        比例增益
    Ki : float
        积分增益
    Kd : float
        微分增益
    setpoint : float, optional
        设定值,默认为0
    output_limits : Tuple[float, float], optional
        输出限制(min, max),默认为None(无限制)
    sample_time : float, optional
        采样时间(秒),默认为None(可变采样)
    
    Attributes
    ----------
    Kp : float
        比例增益
    Ki : float
        积分增益
    Kd : float
        微分增益
    setpoint : float
        设定值
    output_limits : Tuple[float, float]
        输出限制
    sample_time : float
        采样时间
    
    Methods
    -------
    update(measurement)
        更新控制器输出
    reset()
        重置控制器状态
    set_parameters(Kp, Ki, Kd)
        设置PID参数
    
    Examples
    --------
    >>> pid = PIDController(Kp=1.0, Ki=0.1, Kd=0.01, setpoint=100)
    >>> output = pid.update(measurement=90)
    >>> print(f"控制输出: {output:.2f}")
    
    医疗应用示例:
    
    >>> # 胰岛素泵控制
    >>> pid = PIDController(Kp=0.5, Ki=0.01, Kd=2.0, setpoint=100)
    >>> blood_glucose = 150  # mg/dL
    >>> insulin_rate = pid.update(blood_glucose)
    
    Notes
    -----
    PID控制器公式:
        u(t) = Kp*e(t) + Ki*∫e(τ)dτ + Kd*de(t)/dt
    
    其中:
        e(t) = setpoint - measurement
        u(t) = 控制输出
    
    References
    ----------
    .. [1] Åström, K. J., & Hägglund, T. (2006). Advanced PID Control.
           ISA - The Instrumentation, Systems and Automation Society.
    """
    
    def __init__(self, 
                 Kp: float, 
                 Ki: float, 
                 Kd: float, 
                 setpoint: float = 0.0,
                 output_limits: Optional[Tuple[float, float]] = None,
                 sample_time: Optional[float] = None):
        """
        初始化PID控制器
        """
        # 参数验证
        if not isinstance(Kp, (int, float)) or Kp < 0:
            raise ValueError("Kp must be a non-negative number")
        if not isinstance(Ki, (int, float)) or Ki < 0:
            raise ValueError("Ki must be a non-negative number")
        if not isinstance(Kd, (int, float)) or Kd < 0:
            raise ValueError("Kd must be a non-negative number")
        
        self.Kp = Kp
        self.Ki = Ki
        self.Kd = Kd
        self.setpoint = setpoint
        self.output_limits = output_limits
        self.sample_time = sample_time
        
        # 控制器状态
        self._integral = 0.0
        self._last_error = None
        self._last_output = None
        self._last_time = None
        
        # 抗积分饱和
        self._integral_limits = None
        if output_limits is not None:
            # 积分限幅,防止积分饱和
            self._integral_limits = (-output_limits[1] / Ki if Ki != 0 else None,
                                     output_limits[1] / Ki if Ki != 0 else None)
    
    def update(self, measurement: float, current_time: Optional[float] = None) -> float:
        """
        更新控制器输出
        
        Parameters
        ----------
        measurement : float
            当前测量值
        current_time : float, optional
            当前时间(秒),用于可变采样。如果为None,使用固定采样时间
        
        Returns
        -------
        output : float
            控制输出
        
        Raises
        ------
        ValueError
            如果measurement不是数字
        TypeError
            如果使用固定采样时间但未提供current_time
        
        Notes
        -----
        离散PID控制算法:
            u[k] = Kp*e[k] + Ki*Ts*Σe[i] + Kd*(e[k] - e[k-1])/Ts
        
        其中:
            Ts: 采样时间
            e[k]: 当前误差
            e[k-1]: 上一次误差
        """
        # 参数验证
        if not isinstance(measurement, (int, float)):
            raise TypeError("measurement must be a number")
        
        # 计算误差
        error = self.setpoint - measurement
        
        # 确定采样时间
        if self.sample_time is not None:
            # 固定采样时间
            dt = self.sample_time
        else:
            # 可变采样时间
            if current_time is None:
                raise TypeError("current_time is required when sample_time is None")
            
            if self._last_time is None:
                dt = 0.0
            else:
                dt = current_time - self._last_time
            
            self._last_time = current_time
        
        # 比例项
        proportional = self.Kp * error
        
        # 积分项
        if dt > 0:
            self._integral += error * dt
            
            # 抗积分饱和:限制积分项
            if self._integral_limits is not None:
                self._integral = np.clip(self._integral, 
                                         self._integral_limits[0], 
                                         self._integral_limits[1])
        
        integral = self.Ki * self._integral
        
        # 微分项
        if self._last_error is None or dt <= 0:
            derivative = 0.0
        else:
            # 使用后向差分
            derivative = self.Kd * (error - self._last_error) / dt
        
        self._last_error = error
        
        # 计算输出
        output = proportional + integral + derivative
        
        # 输出限幅
        if self.output_limits is not None:
            output = np.clip(output, self.output_limits[0], self.output_limits[1])
        
        self._last_output = output
        
        return output
    
    def reset(self) -> None:
        """
        重置控制器状态
        
        将积分项、上次误差等状态清零,用于系统重启或模式切换。
        """
        self._integral = 0.0
        self._last_error = None
        self._last_output = None
        self._last_time = None
    
    def set_parameters(self, Kp: float, Ki: float, Kd: float) -> None:
        """
        设置PID参数
        
        Parameters
        ----------
        Kp : float
            比例增益
        Ki : float
            积分增益
        Kd : float
            微分增益
        
        Raises
        ------
        ValueError
            如果参数为负数
        """
        if Kp < 0 or Ki < 0 or Kd < 0:
            raise ValueError("PID parameters must be non-negative")
        
        self.Kp = Kp
        self.Ki = Ki
        self.Kd = Kd
    
    def get_components(self) -> Tuple[float, float, float]:
        """
        获取PID各项分量
        
        Returns
        -------
        proportional : float
            比例项
        integral : float
            积分项
        derivative : float
            微分项
        
        Notes
        -----
        用于调试和分析控制器的行为。
        """
        if self._last_error is None:
            proportional = self.Kp * (self.setpoint - 0)
            integral = self.Ki * self._integral
            derivative = 0.0
        else:
            proportional = self.Kp * self._last_error
            integral = self.Ki * self._integral
            # 估计微分项
            if self.sample_time is not None and self.sample_time > 0:
                derivative = self.Kd * self._last_error / self.sample_time
            else:
                derivative = 0.0
        
        return proportional, integral, derivative


class StateSpaceModel:
    """
    状态空间模型类
    
    实现线性时不变系统的状态空间模型,包括状态演化、输出计算和稳定性分析。
    
    Parameters
    ----------
    A : np.ndarray
        状态转移矩阵,形状为(n, n)
    B : np.ndarray
        输入矩阵,形状为(n, m)
    C : np.ndarray
        输出矩阵,形状为(p, n)
    D : np.ndarray, optional
        前馈矩阵,形状为(p, m),默认为零矩阵
    x0 : np.ndarray, optional
        初始状态,形状为(n,),默认为零向量
    
    Attributes
    ----------
    A : np.ndarray
        状态转移矩阵
    B : np.ndarray
        输入矩阵
    C : np.ndarray
        输出矩阵
    D : np.ndarray
        前馈矩阵
    x : np.ndarray
        当前状态
    n : int
        状态维度
    m : int
        输入维度
    p : int
        输出维度
    
    Methods
    -------
    step(u, dt)
        离散时间演化
    simulate(u_sequence, dt, steps)
        仿真多步演化
    is_stable()
        判断系统稳定性
    lyapunov_equation(Q)
        求解Lyapunov方程
    controllability_matrix()
        计算可控性矩阵
    observability_matrix()
        计算可观测性矩阵
    
    Examples
    --------
    >>> import numpy as np
    >>> A = np.array([[-1, 2], [0, -3]])
    >>> B = np.array([[0], [1]])
    >>> C = np.array([[1, 0]])
    >>> sys = StateSpaceModel(A, B, C)
    >>> print(f"系统稳定: {sys.is_stable()}")
    
    医疗应用示例:
    
    >>> # 血糖调节系统
    >>> A = np.array([[-0.02, -100], [0, -0.05]])
    >>> B = np.array([[0], [0.01]])
    >>> C = np.array([[1, 0]])
    >>> sys = StateSpaceModel(A, B, C)
    
    Notes
    -----
    状态空间模型:
        ẋ = Ax + Bu
        y = Cx + Du
    
    References
    ----------
    .. [1] Kailath, T. (1980). Linear Systems. Prentice-Hall.
    """
    
    def __init__(self, 
                 A: np.ndarray, 
                 B: np.ndarray, 
                 C: np.ndarray, 
                 D: Optional[np.ndarray] = None,
                 x0: Optional[np.ndarray] = None):
        """
        初始化状态空间模型
        """
        # 参数验证
        A = np.atleast_2d(A)
        B = np.atleast_2d(B)
        C = np.atleast_2d(C)
        
        if A.ndim != 2 or A.shape[0] != A.shape[1]:
            raise ValueError("A must be a square matrix")
        
        if B.ndim != 2:
            raise ValueError("B must be a 2D matrix")
        
        if C.ndim != 2:
            raise ValueError("C must be a 2D matrix")
        
        if D is None:
            D = np.zeros((C.shape[0], B.shape[1]))
        else:
            D = np.atleast_2d(D)
        
        # 维度一致性检查
        n = A.shape[0]
        m = B.shape[1]
        p = C.shape[0]
        
        if B.shape[0] != n:
            raise ValueError(f"B dimension mismatch: expected ({n}, m), got {B.shape}")
        
        if C.shape[1] != n:
            raise ValueError(f"C dimension mismatch: expected (p, {n}), got {C.shape}")
        
        if D.shape != (p, m):
            raise ValueError(f"D dimension mismatch: expected ({p}, {m}), got {D.shape}")
        
        self.A = A
        self.B = B
        self.C = C
        self.D = D
        
        self.n = n
        self.m = m
        self.p = p
        
        # 初始状态
        if x0 is None:
            self.x = np.zeros(n)
        else:
            x0 = np.atleast_1d(x0)
            if x0.shape[0] != n:
                raise ValueError(f"x0 dimension mismatch: expected ({n},), got {x0.shape}")
            self.x = x0.copy()
    
    def step(self, u: np.ndarray, dt: float = 0.1) -> np.ndarray:
        """
        离散时间演化一步
        
        Parameters
        ----------
        u : np.ndarray
            输入向量,形状为(m,)或(m, 1)
        dt : float
            采样时间(秒),默认为0.1
        
        Returns
        -------
        y : np.ndarray
            输出向量,形状为(p,)
        
        Raises
        ------
        ValueError
            如果dt为负数
        TypeError
            如果u不是numpy数组
        
        Notes
        -----
        离散化方法:零阶保持
            x[k+1] = Ad*x[k] + Bd*u[k]
            y[k] = C*x[k] + D*u[k]
        
        其中:
            Ad = exp(A*dt)
            Bd = ∫₀^dt exp(A*τ)dτ * B
        """
        if not isinstance(u, np.ndarray):
            raise TypeError("u must be a numpy array")
        
        if dt < 0:
            raise ValueError("dt must be non-negative")
        
        u = np.atleast_1d(u).flatten()
        
        if u.shape[0] != self.m:
            raise ValueError(f"u dimension mismatch: expected ({self.m},), got {u.shape}")
        
        # 离散化
        Ad = self._matrix_exponential(self.A, dt)
        Bd = self._compute_Bd(dt)
        
        # 状态更新
        self.x = Ad @ self.x + Bd @ u
        
        # 输出计算
        y = self.C @ self.x + self.D @ u
        
        return y
    
    def _matrix_exponential(self, A: np.ndarray, t: float) -> np.ndarray:
        """
        计算矩阵指数 exp(A*t)
        
        使用缩放-平方法(scaling and squaring)计算矩阵指数。
        
        Parameters
        ----------
        A : np.ndarray
            输入矩阵
        t : float
            时间
        
        Returns
        -------
        exp_At : np.ndarray
            矩阵指数
        """
        # 使用SciPy的expm函数
        from scipy.linalg import expm
        return expm(A * t)
    
    def _compute_Bd(self, dt: float) -> np.ndarray:
        """
        计算离散化输入矩阵 Bd
        
        Bd = ∫₀^dt exp(A*τ)dτ * B
        
        对于小dt,使用近似:
            Bd ≈ (I + A*dt/2 + A²*dt²/6) * dt * B
        """
        from scipy.linalg import expm
        
        # 精确计算
        n = self.n
        A_aug = np.zeros((n+1, n+1))
        A_aug[:n, :n] = self.A
        A_aug[:n, n] = self.B.flatten()
        
        exp_A_aug = expm(A_aug * dt)
        Bd = exp_A_aug[:n, n:n+1]
        
        return Bd
    
    def simulate(self, 
                 u_sequence: np.ndarray, 
                 dt: float = 0.1,
                 steps: Optional[int] = None) -> Tuple[np.ndarray, np.ndarray]:
        """
        仿真多步演化
        
        Parameters
        ----------
        u_sequence : np.ndarray
            输入序列,形状为(T, m)或(T,),其中T为仿真步数
        dt : float
            采样时间(秒),默认为0.1
        steps : int, optional
            仿真步数,如果为None,使用u_sequence的长度
        
        Returns
        -------
        x_history : np.ndarray
            状态历史,形状为(T+1, n)
        y_history : np.ndarray
            输出历史,形状为(T, p)
        
        Examples
        --------
        >>> u_seq = np.ones((100, 1)) * 0.5  # 恒定输入
        >>> x_hist, y_hist = sys.simulate(u_seq, dt=0.1)
        """
        u_sequence = np.atleast_2d(u_sequence)
        
        if u_sequence.ndim != 2:
            raise ValueError("u_sequence must be 2D")
        
        if u_sequence.shape[1] != self.m:
            raise ValueError(f"u_sequence dimension mismatch: expected (T, {self.m}), got {u_sequence.shape}")
        
        if steps is None:
            steps = u_sequence.shape[0]
        
        # 初始化历史记录
        x_history = np.zeros((steps + 1, self.n))
        y_history = np.zeros((steps, self.p))
        
        x_history[0, :] = self.x
        
        # 仿真循环
        for i in range(steps):
            y_history[i, :] = self.step(u_sequence[i, :], dt)
            x_history[i + 1, :] = self.x
        
        return x_history, y_history
    
    def is_stable(self) -> bool:
        """
        判断系统稳定性
        
        Returns
        -------
        is_stable : bool
            如果所有特征值实部为负,返回True;否则返回False
        
        Notes
        -----
        稳定性判据:矩阵A的所有特征值具有负实部。
        """
        eigenvalues = np.linalg.eigvals(self.A)
        return np.all(np.real(eigenvalues) < 0)
    
    def lyapunov_equation(self, Q: Optional[np.ndarray] = None) -> np.ndarray:
        """
        求解Lyapunov方程
        
        A^T P + P A = -Q
        
        Parameters
        ----------
        Q : np.ndarray, optional
            正定矩阵,默认为单位矩阵
        
        Returns
        -------
        P : np.ndarray
            Lyapunov方程的解
        
        Raises
        ------
        ValueError
            如果系统不稳定
        ValueError
            如果Q不是正定矩阵
        
        Notes
        -----
        定理:系统渐近稳定的充要条件是Lyapunov方程有正定解P。
        """
        if Q is None:
            Q = np.eye(self.n)
        else:
            Q = np.atleast_2d(Q)
            if Q.shape != (self.n, self.n):
                raise ValueError(f"Q dimension mismatch: expected ({self.n}, {self.n}), got {Q.shape}")
        
        # 检查Q是否正定
        if not np.all(np.linalg.eigvals(Q) > 0):
            raise ValueError("Q must be positive definite")
        
        # 检查系统稳定性
        if not self.is_stable():
            raise ValueError("System is not stable, Lyapunov equation may not have solution")
        
        # 求解Lyapunov方程
        from scipy.linalg import solve_continuous_lyapunov
        P = solve_continuous_lyapunov(self.A.T, -Q)
        
        return P
    
    def controllability_matrix(self) -> np.ndarray:
        """
        计算可控性矩阵
        
        Returns
        -------
        Co : np.ndarray
            可控性矩阵 [B, AB, A²B, ..., A^(n-1)B],形状为(n, n*m)
        
        Notes
        -----
        系统可控的充要条件:rank(Co) = n
        """
        Co = np.zeros((self.n, self.n * self.m))
        Co[:, :self.m] = self.B
        
        for i in range(1, self.n):
            Co[:, i*self.m:(i+1)*self.m] = np.linalg.matrix_power(self.A, i) @ self.B
        
        return Co
    
    def observability_matrix(self) -> np.ndarray:
        """
        计算可观测性矩阵
        
        Returns
        -------
        Ob : np.ndarray
            可观测性矩阵 [C; CA; CA²; ...; CA^(n-1)],形状为(n*p, n)
        
        Notes
        -----
        系统可观测的充要条件:rank(Ob) = n
        """
        Ob = np.zeros((self.n * self.p, self.n))
        Ob[:self.p, :] = self.C
        
        for i in range(1, self.n):
            Ob[i*self.p:(i+1)*self.p, :] = self.C @ np.linalg.matrix_power(self.A, i)
        
        return Ob


class StabilityAnalyzer:
    """
    稳定性分析工具类
    
    提供Lyapunov稳定性分析、Routh-Hurwitz判据、Nyquist判据等稳定性分析方法。
    
    Methods
    -------
    eigenvalue_analysis(A)
        特征值分析
    lyapunov_analysis(A, Q)
        Lyapunov分析
    routh_hurwitz(coeffs)
        Routh-Hurwitz判据
    is_positive_definite(M)
        判断矩阵是否正定
    
    Examples
    --------
    >>> import numpy as np
    >>> A = np.array([[-1, 2], [0, -3]])
    >>> analyzer = StabilityAnalyzer()
    >>> is_stable, eigenvalues = analyzer.eigenvalue_analysis(A)
    """
    
    @staticmethod
    def eigenvalue_analysis(A: np.ndarray) -> Tuple[bool, np.ndarray]:
        """
        特征值稳定性分析
        
        Parameters
        ----------
        A : np.ndarray
            状态转移矩阵
        
        Returns
        -------
        is_stable : bool
            是否稳定
        eigenvalues : np.ndarray
            特征值数组
        
        Notes
        -----
        稳定条件:所有特征值实部 < 0
        """
        A = np.atleast_2d(A)
        eigenvalues = np.linalg.eigvals(A)
        is_stable = np.all(np.real(eigenvalues) < 0)
        
        return is_stable, eigenvalues
    
    @staticmethod
    def lyapunov_analysis(A: np.ndarray, Q: Optional[np.ndarray] = None) -> Tuple[bool, np.ndarray]:
        """
        Lyapunov稳定性分析
        
        Parameters
        ----------
        A : np.ndarray
            状态转移矩阵
        Q : np.ndarray, optional
            正定矩阵,默认为单位矩阵
        
        Returns
        -------
        is_stable : bool
            是否稳定
        P : np.ndarray
            Lyapunov方程的解
        
        Raises
        ------
        ValueError
            如果Lyapunov方程无解或解不正定
        """
        A = np.atleast_2d(A)
        n = A.shape[0]
        
        if Q is None:
            Q = np.eye(n)
        else:
            Q = np.atleast_2d(Q)
        
        # 检查系统是否渐近稳定
        is_stable, _ = StabilityAnalyzer.eigenvalue_analysis(A)
        
        if not is_stable:
            return False, None
        
        # 求解Lyapunov方程
        from scipy.linalg import solve_continuous_lyapunov
        P = solve_continuous_lyapunov(A.T, -Q)
        
        # 检验P是否正定
        is_pd = StabilityAnalyzer.is_positive_definite(P)
        
        if not is_pd:
            raise ValueError("Lyapunov solution P is not positive definite")
        
        return True, P
    
    @staticmethod
    def routh_hurwitz(coeffs: np.ndarray) -> Tuple[bool, np.ndarray]:
        """
        Routh-Hurwitz稳定性判据
        
        判断特征方程 a_n*s^n + a_{n-1}*s^{n-1} + ... + a_1*s + a_0 = 0
        的根是否全在左半平面。
        
        Parameters
        ----------
        coeffs : np.ndarray
            特征方程系数,从高次到低次,形状为(n+1,)
        
        Returns
        -------
        is_stable : bool
            是否稳定
        routh_table : np.ndarray
            Routh表
        
        Notes
        -----
        Routh-Hurwitz判据:
        系统稳定的充要条件是Routh表第一列元素全为正。
        
        Examples
        --------
        >>> coeffs = np.array([1, 5, 6])  # s² + 5s + 6 = 0
        >>> is_stable, table = StabilityAnalyzer.routh_hurwitz(coeffs)
        """
        coeffs = np.atleast_1d(coeffs).flatten()
        n = len(coeffs) - 1  # 系统阶数
        
        if n < 1:
            raise ValueError("System order must be at least 1")
        
        # 构建Routh表
        num_rows = n + 1
        num_cols = (n // 2) + 1
        
        routh_table = np.zeros((num_rows, num_cols))
        
        # 填充前两行
        routh_table[0, :len(coeffs[::2])] = coeffs[::2]
        routh_table[1, :len(coeffs[1::2])] = coeffs[1::2]
        
        # 计算后续行
        for i in range(2, num_rows):
            for j in range(num_cols - 1):
                if routh_table[i-1, 0] != 0:
                    routh_table[i, j] = (routh_table[i-1, 0] * routh_table[i-2, j+1] - 
                                         routh_table[i-2, 0] * routh_table[i-1, j+1]) / routh_table[i-1, 0]
                else:
                    # 特殊情况处理:使用小扰动
                    epsilon = 1e-10
                    routh_table[i-1, 0] = epsilon
                    routh_table[i, j] = (routh_table[i-1, 0] * routh_table[i-2, j+1] - 
                                         routh_table[i-2, 0] * routh_table[i-1, j+1]) / routh_table[i-1, 0]
        
        # 判断稳定性
        first_column = routh_table[:, 0]
        is_stable = np.all(first_column > 0)
        
        return is_stable, routh_table
    
    @staticmethod
    def is_positive_definite(M: np.ndarray) -> bool:
        """
        判断矩阵是否正定
        
        Parameters
        ----------
        M : np.ndarray
            输入矩阵
        
        Returns
        -------
        is_pd : bool
            是否正定
        
        Notes
        -----
        判别方法:
        1. 所有特征值 > 0
        2. 所有顺序主子式 > 0
        3. Cholesky分解存在
        
        这里使用特征值方法。
        """
        M = np.atleast_2d(M)
        
        if M.shape[0] != M.shape[1]:
            return False
        
        # 对称性检查
        if not np.allclose(M, M.T):
            return False
        
        # 特征值检查
        eigenvalues = np.linalg.eigvals(M)
        
        return np.all(eigenvalues > 1e-10)  # 数值容差


# 单元测试
def test_pid_controller():
    """测试PID控制器"""
    print("测试PID控制器...")
    
    # 创建PID控制器
    pid = PIDController(Kp=1.0, Ki=0.1, Kd=0.01, setpoint=100)
    
    # 测试更新
    output1 = pid.update(measurement=90, current_time=0.0)
    output2 = pid.update(measurement=95, current_time=0.1)
    output3 = pid.update(measurement=98, current_time=0.2)
    
    print(f"  测量值=90, 输出={output1:.4f}")
    print(f"  测量值=95, 输出={output2:.4f}")
    print(f"  测量值=98, 输出={output3:.4f}")
    
    # 测试重置
    pid.reset()
    assert pid._integral == 0.0
    assert pid._last_error is None
    
    print("  PID控制器测试通过!")
    return True


def test_state_space_model():
    """测试状态空间模型"""
    print("测试状态空间模型...")
    
    # 创建系统
    A = np.array([[-1, 2], [0, -3]])
    B = np.array([[0], [1]])
    C = np.array([[1, 0]])
    sys = StateSpaceModel(A, B, C)
    
    # 测试稳定性
    is_stable = sys.is_stable()
    print(f"  系统稳定: {is_stable}")
    assert is_stable == True
    
    # 测试Lyapunov方程
    P = sys.lyapunov_equation()
    print(f"  Lyapunov方程解P的主对角线元素: {np.diag(P)}")
    
    # 测试可控性和可观测性
    Co = sys.controllability_matrix()
    Ob = sys.observability_matrix()
    print(f"  可控性矩阵秩: {np.linalg.matrix_rank(Co)}/2")
    print(f"  可观测性矩阵秩: {np.linalg.matrix_rank(Ob)}/2")
    
    # 测试仿真
    u_seq = np.ones((50, 1)) * 0.5
    x_hist, y_hist = sys.simulate(u_seq, dt=0.1)
    print(f"  仿真完成: 状态历史形状={x_hist.shape}, 输出历史形状={y_hist.shape}")
    
    print("  状态空间模型测试通过!")
    return True


def test_stability_analyzer():
    """测试稳定性分析器"""
    print("测试稳定性分析器...")
    
    analyzer = StabilityAnalyzer()
    
    # 测试特征值分析
    A = np.array([[-1, 2], [0, -3]])
    is_stable, eigenvalues = analyzer.eigenvalue_analysis(A)
    print(f"  特征值分析: 稳定={is_stable}, 特征值={eigenvalues}")
    
    # 测试Lyapunov分析
    is_stable, P = analyzer.lyapunov_analysis(A)
    print(f"  Lyapunov分析: 稳定={is_stable}, P正定={analyzer.is_positive_definite(P)}")
    
    # 测试Routh-Hurwitz判据
    coeffs = np.array([1, 5, 6])  # s² + 5s + 6 = 0
    is_stable, routh_table = analyzer.routh_hurwitz(coeffs)
    print(f"  Routh-Hurwitz判据: 稳定={is_stable}")
    print(f"  Routh表:\n{routh_table}")
    
    print("  稳定性分析器测试通过!")
    return True


if __name__ == "__main__":
    """运行所有测试"""
    print("=" * 60)
    print("控制理论基础 - Python实现测试")
    print("=" * 60)
    
    test_pid_controller()
    print()
    
    test_state_space_model()
    print()
    
    test_stability_analyzer()
    print()
    
    print("=" * 60)
    print("所有测试通过!")
    print("=" * 60)

1.5.2 胰岛素泵闭环控制仿真

python 复制代码
"""
胰岛素泵闭环控制仿真
模拟PID控制器在血糖调节中的应用

模块名称: insulin_pump_simulation
模块功能: 胰岛素泵闭环控制系统仿真
作者: 控制论专家
日期: 2026-03-15
"""

import numpy as np
import matplotlib.pyplot as plt
from typing import Tuple, Dict, List
from pid_controller import PIDController, StateSpaceModel, StabilityAnalyzer


class GlucoseModel:
    """
    血糖动力学模型
    
    实现简化的Bergman最小模型,用于仿真血糖-胰岛素相互作用。
    
    Parameters
    ----------
    params : Dict[str, float], optional
        模型参数字典,包含:
        - p1: 葡萄糖消失率(1/min)
        - p2: 胰岛素作用消失率(1/min)
        - p3: 胰岛素作用效率((μU/mL)^{-1} min^{-2})
        - Gb: 基础血糖浓度(mg/dL)
        - Ib: 基础胰岛素浓度(μU/mL)
        - Vg: 葡萄糖分布容积(dL/kg)
    
    Attributes
    ----------
    params : Dict[str, float]
        模型参数
    
    Examples
    --------
    >>> model = GlucoseModel()
    >>> G, X, I = model.simulate(u_profile, T=300, dt=1)
    """
    
    def __init__(self, params: Optional[Dict[str, float]] = None):
        """初始化血糖模型"""
        # 默认参数(典型糖尿病患者)
        self.default_params = {
            'p1': 0.028,      # 1/min
            'p2': 0.025,      # 1/min
            'p3': 0.000013,   # (μU/mL)^{-1} min^{-2}
            'Gb': 81,         # mg/dL
            'Ib': 15,         # μU/mL
            'Vg': 117,        # dL (70kg成人)
        }
        
        if params is not None:
            self.params = {**self.default_params, **params}
        else:
            self.params = self.default_params
    
    def simulate(self, 
                 u_profile: np.ndarray, 
                 T: float = 300,
                 dt: float = 1.0,
                 G0: Optional[float] = None,
                 meal_profile: Optional[np.ndarray] = None) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
        """
        仿真血糖动力学
        
        Parameters
        ----------
        u_profile : np.ndarray
            胰岛素注射速率序列(μU/min),形状为(T,)
        T : float
            仿真时长(min),默认为300
        dt : float
            采样时间(min),默认为1
        G0 : float, optional
            初始血糖浓度(mg/dL),默认为Gb
        meal_profile : np.ndarray, optional
            进餐葡萄糖吸收率(mg/min),形状为(T,)
        
        Returns
        -------
        G : np.ndarray
            血糖浓度时间序列(mg/dL),形状为(T,)
        X : np.ndarray
            胰岛素作用变量时间序列(1/min),形状为(T,)
        I : np.ndarray
            血浆胰岛素浓度时间序列(μU/mL),形状为(T,)
        
        Notes
        -----
        Bergman最小模型方程:
            dG/dt = -p1*(G - Gb) - X*G + Ra/Vg
            dX/dt = -p2*X + p3*(I - Ib)
            dI/dt = -n*I + u/Vi + γ*(G - G_th)^+
        """
        steps = int(T / dt)
        
        # 初始化状态
        G = np.zeros(steps)
        X = np.zeros(steps)
        I = np.zeros(steps)
        
        # 初始条件
        G[0] = G0 if G0 is not None else self.params['Gb']
        X[0] = 0.0
        I[0] = self.params['Ib']
        
        # 参数
        p1 = self.params['p1']
        p2 = self.params['p2']
        p3 = self.params['p3']
        Gb = self.params['Gb']
        Ib = self.params['Ib']
        Vg = self.params['Vg']
        
        # 其他参数
        n = 0.093  # 胰岛素清除率(1/min)
        Vi = 120   # 胰岛素分布容积(dL)
        gamma = 0.0041  # 胰岛素分泌增益(μU/mL min^{-1} (mg/dL)^{-1})
        G_th = 89  # 胰岛素分泌阈值(mg/dL)
        
        # 仿真循环
        for k in range(steps - 1):
            # 葡萄糖吸收(进餐)
            if meal_profile is not None:
                Ra = meal_profile[k]
            else:
                Ra = 0.0
            
            # 状态导数
            dG = (-p1 * (G[k] - Gb) - X[k] * G[k] + Ra / Vg) * dt
            dX = (-p2 * X[k] + p3 * (I[k] - Ib)) * dt
            dI = (-n * I[k] + u_profile[k] / Vi + gamma * max(0, G[k] - G_th)) * dt
            
            # 状态更新
            G[k+1] = G[k] + dG
            X[k+1] = X[k] + dX
            I[k+1] = I[k] + dI
            
            # 约束:血糖和胰岛素非负
            G[k+1] = max(G[k+1], 20)  # 最低血糖20 mg/dL
            I[k+1] = max(I[k+1], 0)
        
        return G, X, I


class InsulinPumpController:
    """
    胰岛素泵控制器
    
    实现闭环血糖控制系统,集成PID控制器和血糖模型。
    
    Parameters
    ----------
    G_target : float
        目标血糖浓度(mg/dL)
    Kp : float
        比例增益
    Ki : float
        积分增益
    Kd : float
        微分增益
    
    Attributes
    ----------
    pid : PIDController
        PID控制器实例
    glucose_model : GlucoseModel
        血糖模型实例
    
    Examples
    --------
    >>> controller = InsulinPumpController(G_target=100, Kp=0.5, Ki=0.01, Kd=2.0)
    >>> results = controller.simulate_closed_loop(T=300, dt=1, G0=150)
    """
    
    def __init__(self, 
                 G_target: float = 100.0,
                 Kp: float = 0.5,
                 Ki: float = 0.01,
                 Kd: float = 2.0):
        """初始化胰岛素泵控制器"""
        self.G_target = G_target
        self.pid = PIDController(
            Kp=Kp, 
            Ki=Ki, 
            Kd=Kd, 
            setpoint=G_target,
            output_limits=(0, 100),  # 胰岛素注射速率限制(μU/min)
            sample_time=1.0
        )
        self.glucose_model = GlucoseModel()
    
    def simulate_closed_loop(self, 
                             T: float = 300,
                             dt: float = 1.0,
                             G0: float = 150.0,
                             meal_profile: Optional[np.ndarray] = None,
                             measurement_noise: float = 0.0) -> Dict[str, np.ndarray]:
        """
        闭环系统仿真
        
        Parameters
        ----------
        T : float
            仿真时长(min),默认为300
        dt : float
            采样时间(min),默认为1
        G0 : float
            初始血糖浓度(mg/dL),默认为150
        meal_profile : np.ndarray, optional
            进餐葡萄糖吸收率(mg/min)
        measurement_noise : float
            测量噪声标准差(mg/dL),默认为0
        
        Returns
        -------
        results : Dict[str, np.ndarray]
            仿真结果字典,包含:
            - 'time': 时间序列(min)
            - 'glucose': 血糖浓度(mg/dL)
            - 'insulin': 胰岛素注射速率(μU/min)
            - 'insulin_conc': 血浆胰岛素浓度(μU/mL)
            - 'error': 血糖误差(mg/dL)
        
        Notes
        -----
        闭环控制策略:
            u(t) = max(0, PID(G_target - G_measured(t)))
        
        其中PID控制器根据血糖误差计算胰岛素注射速率。
        """
        steps = int(T / dt)
        
        # 初始化
        time = np.arange(0, T, dt)
        G = np.zeros(steps)
        u = np.zeros(steps)
        I = np.zeros(steps)
        e = np.zeros(steps)
        
        # 重置PID控制器
        self.pid.reset()
        
        # 初始血糖
        G[0] = G0
        
        # 仿真循环
        for k in range(steps):
            # 测量血糖(可能包含噪声)
            G_measured = G[k] + np.random.normal(0, measurement_noise) if measurement_noise > 0 else G[k]
            
            # 计算误差
            e[k] = self.G_target - G_measured
            
            # PID控制器计算胰岛素注射速率
            u[k] = self.pid.update(G_measured)
            
            # 限制胰岛素注射速率
            u[k] = np.clip(u[k], 0, 100)
        
        # 使用计算得到的胰岛素注射速率仿真血糖模型
        G, X, I = self.glucose_model.simulate(u, T, dt, G0, meal_profile)
        
        # 重新计算误差
        e = self.G_target - G
        
        # 返回结果
        results = {
            'time': time,
            'glucose': G,
            'insulin_rate': u,
            'insulin_conc': I,
            'error': e,
            'X': X
        }
        
        return results
    
    def evaluate_performance(self, results: Dict[str, np.ndarray]) -> Dict[str, float]:
        """
        评估控制性能
        
        Parameters
        ----------
        results : Dict[str, np.ndarray]
            仿真结果字典
        
        Returns
        -------
        metrics : Dict[str, float]
            性能指标字典,包含:
            - 'steady_state_error': 稳态误差(mg/dL)
            - 'settling_time': 调节时间(min)
            - 'overshoot': 超调量(%)
            - 'time_in_target': 在目标范围内的时间占比(%)
            - 'min_glucose': 最低血糖(mg/dL)
            - 'max_glucose': 最高血糖(mg/dL)
            - 'hypoglycemia_episodes': 低血糖事件次数
        
        Notes
        -----
        目标范围: 80-120 mg/dL
        低血糖阈值: 70 mg/dL
        """
        G = results['glucose']
        
        # 稳态误差(最后10%的时间)
        n_ss = int(0.9 * len(G))
        steady_state_error = abs(np.mean(G[n_ss:]) - self.G_target)
        
        # 调节时间(进入目标范围80-120 mg/dL)
        target_range = (80, 120)
        settling_time = len(G)  # 默认为仿真时长
        for k in range(len(G)):
            if target_range[0] <= G[k] <= target_range[1]:
                # 检查后续是否保持在范围内
                if all(target_range[0] <= G[i] <= target_range[1] for i in range(k, min(k+30, len(G)))):
                    settling_time = results['time'][k]
                    break
        
        # 超调量
        if G[0] > self.G_target:
            # 从高血糖下降,超调量指最低值
            overshoot = max(0, (self.G_target - np.min(G)) / self.G_target * 100)
        else:
            # 从低血糖上升,超调量指最高值
            overshoot = max(0, (np.max(G) - self.G_target) / self.G_target * 100)
        
        # 在目标范围内的时间占比
        time_in_target = np.sum((G >= target_range[0]) & (G <= target_range[1])) / len(G) * 100
        
        # 血糖极值
        min_glucose = np.min(G)
        max_glucose = np.max(G)
        
        # 低血糖事件次数
        hypoglycemia_threshold = 70  # mg/dL
        hypoglycemia_episodes = 0
        in_hypo = False
        for g in G:
            if g < hypoglycemia_threshold and not in_hypo:
                hypoglycemia_episodes += 1
                in_hypo = True
            elif g >= hypoglycemia_threshold:
                in_hypo = False
        
        metrics = {
            'steady_state_error': steady_state_error,
            'settling_time': settling_time,
            'overshoot': overshoot,
            'time_in_target': time_in_target,
            'min_glucose': min_glucose,
            'max_glucose': max_glucose,
            'hypoglycemia_episodes': hypoglycemia_episodes
        }
        
        return metrics


def plot_simulation_results(results: Dict[str, np.ndarray], 
                           metrics: Dict[str, float],
                           save_path: Optional[str] = None):
    """
    绘制仿真结果
    
    Parameters
    ----------
    results : Dict[str, np.ndarray]
        仿真结果字典
    metrics : Dict[str, float]
        性能指标字典
    save_path : str, optional
        图片保存路径
    """
    fig, axes = plt.subplots(3, 1, figsize=(12, 10))
    
    time = results['time']
    G = results['glucose']
    u = results['insulin_rate']
    I = results['insulin_conc']
    
    # 血糖浓度
    axes[0].plot(time, G, 'b-', linewidth=2, label='血糖浓度')
    axes[0].axhline(y=100, color='g', linestyle='--', label='目标血糖')
    axes[0].axhline(y=70, color='r', linestyle=':', label='低血糖阈值')
    axes[0].axhline(y=180, color='orange', linestyle=':', label='高血糖阈值')
    axes[0].fill_between(time, 80, 120, alpha=0.2, color='green', label='目标范围')
    axes[0].set_ylabel('血糖浓度 (mg/dL)', fontsize=12)
    axes[0].set_title('胰岛素泵闭环控制系统仿真结果', fontsize=14, fontweight='bold')
    axes[0].legend(loc='upper right')
    axes[0].grid(True, alpha=0.3)
    axes[0].set_xlim([0, time[-1]])
    
    # 胰岛素注射速率
    axes[1].plot(time, u, 'r-', linewidth=2, label='胰岛素注射速率')
    axes[1].set_ylabel('注射速率 (μU/min)', fontsize=12)
    axes[1].legend(loc='upper right')
    axes[1].grid(True, alpha=0.3)
    axes[1].set_xlim([0, time[-1]])
    
    # 血浆胰岛素浓度
    axes[2].plot(time, I, 'purple', linewidth=2, label='血浆胰岛素浓度')
    axes[2].set_xlabel('时间 (min)', fontsize=12)
    axes[2].set_ylabel('胰岛素浓度 (μU/mL)', fontsize=12)
    axes[2].legend(loc='upper right')
    axes[2].grid(True, alpha=0.3)
    axes[2].set_xlim([0, time[-1]])
    
    plt.tight_layout()
    
    # 添加性能指标文本
    textstr = '\n'.join([
        f'稳态误差: {metrics["steady_state_error"]:.2f} mg/dL',
        f'调节时间: {metrics["settling_time"]:.1f} min',
        f'超调量: {metrics["overshoot"]:.1f}%',
        f'目标范围内时间: {metrics["time_in_target"]:.1f}%',
        f'最低血糖: {metrics["min_glucose"]:.1f} mg/dL',
        f'最高血糖: {metrics["max_glucose"]:.1f} mg/dL',
        f'低血糖事件: {metrics["hypoglycemia_episodes"]}次'
    ])
    
    props = dict(boxstyle='round', facecolor='wheat', alpha=0.8)
    axes[0].text(0.02, 0.98, textstr, transform=axes[0].transAxes, fontsize=10,
                 verticalalignment='top', bbox=props)
    
    if save_path is not None:
        plt.savefig(save_path, dpi=300, bbox_inches='tight')
        print(f"图片已保存至: {save_path}")
    
    plt.show()


def main():
    """主函数:运行胰岛素泵闭环控制仿真"""
    print("=" * 70)
    print("胰岛素泵闭环控制系统仿真")
    print("=" * 70)
    print()
    
    # 创建控制器
    print("1. 创建胰岛素泵控制器...")
    controller = InsulinPumpController(
        G_target=100,  # 目标血糖 100 mg/dL
        Kp=0.5,        # 比例增益
        Ki=0.01,       # 积分增益
        Kd=2.0         # 微分增益
    )
    print("   控制器创建成功!")
    print()
    
    # 闭环仿真
    print("2. 运行闭环仿真...")
    print("   初始血糖: 150 mg/dL")
    print("   目标血糖: 100 mg/dL")
    print("   仿真时长: 300 min")
    
    # 进餐扰动(在第60分钟进食)
    T = 300
    dt = 1.0
    meal_profile = np.zeros(int(T/dt))
    meal_profile[60:90] = 300  # 60-90分钟内进食,吸收率300 mg/min
    
    results = controller.simulate_closed_loop(
        T=T, 
        dt=dt, 
        G0=150, 
        meal_profile=meal_profile,
        measurement_noise=5.0  # 测量噪声 5 mg/dL
    )
    print("   仿真完成!")
    print()
    
    # 性能评估
    print("3. 评估控制性能...")
    metrics = controller.evaluate_performance(results)
    
    print("   性能指标:")
    print(f"     - 稳态误差: {metrics['steady_state_error']:.2f} mg/dL")
    print(f"     - 调节时间: {metrics['settling_time']:.1f} min")
    print(f"     - 超调量: {metrics['overshoot']:.1f}%")
    print(f"     - 目标范围内时间: {metrics['time_in_target']:.1f}%")
    print(f"     - 最低血糖: {metrics['min_glucose']:.1f} mg/dL")
    print(f"     - 最高血糖: {metrics['max_glucose']:.1f} mg/dL")
    print(f"     - 低血糖事件: {metrics['hypoglycemia_episodes']}次")
    print()
    
    # 稳定性分析
    print("4. 控制系统稳定性分析...")
    
    # 简化模型的状态空间矩阵
    A = np.array([
        [-0.028, -100, 0],
        [0, -0.025, 0.000013],
        [0.0041, 0, -0.093]
    ])
    
    analyzer = StabilityAnalyzer()
    is_stable, eigenvalues = analyzer.eigenvalue_analysis(A)
    
    print(f"   系统特征值:")
    for i, eig in enumerate(eigenvalues):
        print(f"     λ_{i+1} = {eig:.4f}")
    print(f"   系统稳定: {is_stable}")
    print()
    
    # 绘制结果
    print("5. 绘制仿真结果...")
    plot_simulation_results(results, metrics, save_path='insulin_pump_simulation.png')
    print()
    
    print("=" * 70)
    print("仿真完成!")
    print("=" * 70)
    
    return results, metrics


if __name__ == "__main__":
    results, metrics = main()

1.1.7 练习题

基础题

【1.1-BASIC-001】控制系统基本概念

题目 :

判断以下系统是开环控制还是闭环控制,并简要说明理由。

  1. 电风扇的定时开关控制
  2. 空调的恒温控制
  3. 交通信号灯的定时控制
  4. 汽车的定速巡航控制

解答:

  1. 开环控制。定时开关只根据预设的时间控制风扇的启停,不依赖于室内温度等反馈信号。

  2. 闭环控制。空调通过温度传感器实时测量室内温度,与设定温度比较,根据误差调节制冷/制热功率,形成闭环反馈控制。

  3. 开环控制。交通信号灯按照预设的时间顺序切换,不依赖于实际交通流量等反馈信息(智能交通系统除外)。

  4. 闭环控制。定速巡航系统通过车速传感器实时测量车速,与设定速度比较,根据误差调节油门开度,形成闭环控制。

知识点: [1.1.1]-开环控制与闭环控制的定义和区别


【1.1-BASIC-002】传递函数计算

题目 :

考虑一个简化的药物代谢模型,血药浓度 c(t)c(t)c(t) 满足微分方程:

dc(t)dt=−kc(t)+Ku(t) \frac{dc(t)}{dt} = -kc(t) + Ku(t) dtdc(t)=−kc(t)+Ku(t)

其中 u(t)u(t)u(t) 为药物注射速率,k=0.1k = 0.1k=0.1 min⁻¹ 为消除速率常数,K=0.5K = 0.5K=0.5 (mg·min)/mL 为药物转化系数。

  1. 求系统的传递函数 G(s)=C(s)U(s)G(s) = \frac{C(s)}{U(s)}G(s)=U(s)C(s)
  2. 求系统的时间常数和稳态增益
  3. 当输入为单位阶跃信号 u(t)=1(t)u(t) = 1(t)u(t)=1(t) 时,求稳态血药浓度

解答:

1. 求传递函数

对微分方程进行拉普拉斯变换(零初始条件):

sC(s)=−kC(s)+KU(s) sC(s) = -kC(s) + KU(s) sC(s)=−kC(s)+KU(s)

整理得:

(s+k)C(s)=KU(s) (s + k)C(s) = KU(s) (s+k)C(s)=KU(s)

因此传递函数为:

G(s)=C(s)U(s)=Ks+k=0.5s+0.1 G(s) = \frac{C(s)}{U(s)} = \frac{K}{s + k} = \frac{0.5}{s + 0.1} G(s)=U(s)C(s)=s+kK=s+0.10.5

2. 时间常数和稳态增益

标准一阶系统形式:

G(s)=Kssτs+1 G(s) = \frac{K_{ss}}{\tau s + 1} G(s)=τs+1Kss

与所求传递函数比较:

G(s)=0.5s+0.1=510s+1 G(s) = \frac{0.5}{s + 0.1} = \frac{5}{10s + 1} G(s)=s+0.10.5=10s+15

因此:

  • 时间常数: τ=10\tau = 10τ=10 min
  • 稳态增益: Kss=5K_{ss} = 5Kss=5 mg·min/mL

物理解释:

  • 时间常数 τ=10\tau = 10τ=10 min 表示药物消除需要一定时间,经过 t=τt = \taut=τ 时,血药浓度达到稳态值的63.2%
  • 稳态增益 Kss=5K_{ss} = 5Kss=5 表示单位注射速率下,稳态血药浓度为 5 mg/mL

3. 稳态血药浓度

对于单位阶跃输入,稳态值为:

css=lim⁡s→0sG(s)⋅1s=lim⁡s→0G(s)=Kk=0.50.1=5 mg/mL c_{ss} = \lim_{s \to 0} sG(s) \cdot \frac{1}{s} = \lim_{s \to 0} G(s) = \frac{K}{k} = \frac{0.5}{0.1} = 5 \text{ mg/mL} css=s→0limsG(s)⋅s1=s→0limG(s)=kK=0.10.5=5 mg/mL

或直接利用终值定理:

css=Kss×1=5 mg/mL c_{ss} = K_{ss} \times 1 = 5 \text{ mg/mL} css=Kss×1=5 mg/mL

知识点: [1.1.2]-传递函数定义、一阶系统特性、终值定理


进阶题

【1.1-ADVANCED-001】状态空间模型推导

题目 :

考虑一个二阶血糖调节系统,其微分方程为:

G¨(t)+2G˙(t)+G(t)=u(t) \ddot{G}(t) + 2\dot{G}(t) + G(t) = u(t) G¨(t)+2G˙(t)+G(t)=u(t)

其中 G(t)G(t)G(t) 为血糖浓度偏差,u(t)u(t)u(t) 为胰岛素注射速率。

  1. 建立系统的状态空间模型(可控标准型)
  2. 判断系统的稳定性
  3. 求系统的特征值和特征向量
  4. 验证Lyapunov稳定性定理

解答:

1. 状态空间模型(可控标准型)

设状态变量:
x1=G(t),x2=G˙(t) x_1 = G(t), \quad x_2 = \dot{G}(t) x1=G(t),x2=G˙(t)

则状态方程为:

x˙1=x2 \dot{x}_1 = x_2 x˙1=x2

x˙2=−x1−2x2+u \dot{x}_2 = -x_1 - 2x_2 + u x˙2=−x1−2x2+u

写成矩阵形式:

$$

\begin{bmatrix}
\dot{x}_1 \
\dot{x}_2
\end{bmatrix}

\begin{bmatrix}

0 & 1 \

-1 & -2

\end{bmatrix}

\begin{bmatrix}

x_1 \

x_2

\end{bmatrix}

\begin{bmatrix}

0 \

1

\end{bmatrix}

u

输出方程(假设输出为血糖浓度): y=G(t)=x1=\[10\]\[x1x2\] y = G(t) = x_1 = \\begin{bmatrix} 1 \& 0 \\end{bmatrix} \\begin{bmatrix} x_1 \\\\ x_2 \\end{bmatrix} y=G(t)=x1=\[10\]\[x1x2\] 因此: A=\[01−1−2\],B=\[01\],C=\[10\],D=0 \\mathbf{A} = \\begin{bmatrix} 0 \& 1 \\\\ -1 \& -2 \\end{bmatrix}, \\quad \\mathbf{B} = \\begin{bmatrix} 0 \\\\ 1 \\end{bmatrix}, \\quad \\mathbf{C} = \\begin{bmatrix} 1 \& 0 \\end{bmatrix}, \\quad \\mathbf{D} = 0 A=\[0−11−2\],B=\[01\],C=\[10\],D=0 **2. 稳定性判断** 特征方程: det⁡(sI−A)=det⁡\[s−11s+2\]=s(s+2)+1=s2+2s+1=0 \\det(s\\mathbf{I} - \\mathbf{A}) = \\det\\begin{bmatrix} s \& -1 \\\\ 1 \& s+2 \\end{bmatrix} = s(s+2) + 1 = s\^2 + 2s + 1 = 0 det(sI−A)=det\[s1−1s+2\]=s(s+2)+1=s2+2s+1=0 特征方程的根: s1,2=−2±4−42=−1 (重根) s_{1,2} = \\frac{-2 \\pm \\sqrt{4 - 4}}{2} = -1 \\text{ (重根)} s1,2=2−2±4−4 =−1 (重根) 两个特征值均为 λ1=λ2=−1\<0\\lambda_1 = \\lambda_2 = -1 \< 0λ1=λ2=−1\<0,实部为负,系统**渐近稳定**。 **3. 特征值和特征向量** 特征值: λ1=λ2=−1\\lambda_1 = \\lambda_2 = -1λ1=λ2=−1 (二重特征值) 求特征向量: (A−λI)v=0 (\\mathbf{A} - \\lambda\\mathbf{I})\\mathbf{v} = 0 (A−λI)v=0 ##

\begin{bmatrix}
1 & 1 \
-1 & -1
\end{bmatrix}
\begin{bmatrix}
v_1 \
v_2
\end{bmatrix}

\begin{bmatrix}

0 \

0

\end{bmatrix}

解得: v1+v2=0v_1 + v_2 = 0v1+v2=0,即 v2=−v1v_2 = -v_1v2=−v1 取 v1=1v_1 = 1v1=1,则 v1=\[1−1\]\\mathbf{v}_1 = \\begin{bmatrix} 1 \\\\ -1 \\end{bmatrix}v1=\[1−1\] 由于是重特征值,需要求广义特征向量。但本题只需要说明特征值均为负实数即可判断稳定性。 **4. Lyapunov稳定性验证** 构造Lyapunov函数: V(x)=xTPx V(\\mathbf{x}) = \\mathbf{x}\^T\\mathbf{P}\\mathbf{x} V(x)=xTPx 求解Lyapunov方程 ATP+PA=−I\\mathbf{A}\^T\\mathbf{P} + \\mathbf{P}\\mathbf{A} = -\\mathbf{I}ATP+PA=−I: ##

\begin{bmatrix}
0 & -1 \
1 & -2
\end{bmatrix}
\begin{bmatrix}
p_{11} & p_{12} \
p_{12} & p_{22}
\end{bmatrix}
+
\begin{bmatrix}
p_{11} & p_{12} \
p_{12} & p_{22}
\end{bmatrix}
\begin{bmatrix}
0 & 1 \
-1 & -2
\end{bmatrix}

\begin{bmatrix}

-1 & 0 \

0 & -1

\end{bmatrix}

展开: ##

\begin{bmatrix}
-p_{12} & -p_{22} \
p_{11}-2p_{12} & p_{12}-2p_{22}
\end{bmatrix}
+
\begin{bmatrix}
-p_{12} & p_{11}-2p_{12} \
-p_{22} & p_{12}-2p_{22}
\end{bmatrix}

\begin{bmatrix}

-1 & 0 \

0 & -1

\end{bmatrix}

得到方程组: −2p12=−1⇒p12=0.5 -2p_{12} = -1 \\Rightarrow p_{12} = 0.5 −2p12=−1⇒p12=0.5 p11−2p12=0⇒p11=1 p_{11} - 2p_{12} = 0 \\Rightarrow p_{11} = 1 p11−2p12=0⇒p11=1 2p12−4p22=−1⇒p22=0.5 2p_{12} - 4p_{22} = -1 \\Rightarrow p_{22} = 0.5 2p12−4p22=−1⇒p22=0.5 因此: P=\[10.50.50.5\] \\mathbf{P} = \\begin{bmatrix} 1 \& 0.5 \\\\ 0.5 \& 0.5 \\end{bmatrix} P=\[10.50.50.5\] 检验 P\\mathbf{P}P 的正定性: * p11=1\>0p_{11} = 1 \> 0p11=1\>0 * det⁡(P)=1×0.5−0.52=0.25\>0\\det(\\mathbf{P}) = 1 \\times 0.5 - 0.5\^2 = 0.25 \> 0det(P)=1×0.5−0.52=0.25\>0 P\\mathbf{P}P 正定,Lyapunov函数存在,验证了系统的渐近稳定性。 **知识点**: \[1.1.2\]-状态空间模型、\[1.1.3\]-Lyapunov稳定性定理 *** ** * ** *** ##### 【1.1-ADVANCED-002】PID控制器设计与仿真 **题目** : 使用Python实现一个温度控制系统仿真: 1. 系统传递函数: G(s)=110s+1G(s) = \\frac{1}{10s + 1}G(s)=10s+11 2. 设计PID控制器,使系统满足: * 上升时间 \< 5s * 超调量 \< 10% * 稳态误差 \< 1% 3. 使用提供的PIDController类进行仿真 4. 绘制阶跃响应曲线 **解答**: ```python """ 温度控制系统PID控制器设计 系统传递函数: G(s) = 1/(10s + 1) """ import numpy as np import matplotlib.pyplot as plt from typing import Dict, Tuple class FirstOrderSystem: """一阶系统仿真""" def __init__(self, tau: float, K: float = 1.0): """ 初始化一阶系统 参数: tau: 时间常数 K: 稳态增益 """ self.tau = tau self.K = K self.y = 0.0 # 系统输出 def step(self, u: float, dt: float) -> float: """ 离散化更新一步 使用后向欧拉法: y[k] = (tau*y[k-1] + dt*K*u[k]) / (tau + dt) """ self.y = (self.tau * self.y + dt * self.K * u) / (self.tau + dt) return self.y def reset(self): """重置系统状态""" self.y = 0.0 def design_pid_controller(tau: float, K: float, rise_time_spec: float, overshoot_spec: float) -> Tuple[float, float, float]: """ 设计PID控制器参数 使用Cohen-Coon整定方法(适用于一阶系统) 参数: tau: 系统时间常数 K: 系统增益 rise_time_spec: 上升时间要求 overshoot_spec: 超调量要求 返回: Kp, Ki, Kd: PID参数 """ # Cohen-Coon整定公式 # 对于一阶系统 G(s) = K/(tau*s + 1) # 简化整定:首先考虑PI控制器 # Kp = 0.9 * tau / (K * tau_d) 其中tau_d为期望时间常数 # Ki = Kp / (3.33 * tau_d) # 根据上升时间要求确定期望时间常数 # 上升时间约等于 2.2 * tau_d tau_d = rise_time_spec / 2.2 # 设计PI控制器 Kp = 0.9 * tau / (K * tau_d) Ki = Kp / (3.33 * tau_d) Kd = 0.0 # 对于一阶系统,通常不需要微分项 # 根据超调量要求调整 # 超调量与阻尼比有关: Mp = exp(-pi*zeta/sqrt(1-zeta^2)) # 超调量 < 10% => zeta > 0.59 # 简单起见,降低增益 if overshoot_spec < 10: Kp *= 0.8 Ki *= 0.8 return Kp, Ki, Kd def simulate_closed_loop(Kp: float, Ki: float, Kd: float, tau: float, K: float, T: float = 50, dt: float = 0.1, setpoint: float = 1.0) -> Dict[str, np.ndarray]: """ 闭环系统仿真 参数: Kp, Ki, Kd: PID参数 tau, K: 系统参数 T: 仿真时长 dt: 采样时间 setpoint: 设定值 返回: results: 仿真结果字典 """ steps = int(T / dt) # 初始化 time = np.arange(0, T, dt) y = np.zeros(steps) u = np.zeros(steps) e = np.zeros(steps) # 创建系统 system = FirstOrderSystem(tau, K) # PID控制器参数 integral = 0.0 last_error = None # 仿真循环 for k in range(steps): # 计算误差 e[k] = setpoint - y[k] # PID计算 proportional = Kp * e[k] integral += e[k] * dt # 抗积分饱和 integral = np.clip(integral, -10, 10) integral_term = Ki * integral if last_error is not None: derivative = Kd * (e[k] - last_error) / dt else: derivative = 0.0 last_error = e[k] # 控制输出 u[k] = proportional + integral_term + derivative u[k] = np.clip(u[k], 0, 10) # 限制控制输出 # 系统响应 y[k] = system.step(u[k], dt) return { 'time': time, 'output': y, 'control': u, 'error': e } def evaluate_performance(results: Dict[str, np.ndarray], setpoint: float) -> Dict[str, float]: """ 评估控制性能 参数: results: 仿真结果 setpoint: 设定值 返回: metrics: 性能指标 """ y = results['output'] time = results['time'] # 稳态误差 n_ss = int(0.9 * len(y)) steady_state_error = abs(np.mean(y[n_ss:]) - setpoint) / setpoint * 100 # 上升时间(10%-90%) y_10 = 0.1 * setpoint y_90 = 0.9 * setpoint t_10 = time[np.argmax(y >= y_10)] t_90 = time[np.argmax(y >= y_90)] rise_time = t_90 - t_10 # 超调量 overshoot = (np.max(y) - setpoint) / setpoint * 100 # 调节时间(进入±5%范围) tolerance = 0.05 * setpoint settling_time = time[-1] for k in range(len(y)): if all(abs(y[i] - setpoint) <= tolerance for i in range(k, min(k+50, len(y)))): settling_time = time[k] break return { 'steady_state_error': steady_state_error, 'rise_time': rise_time, 'overshoot': overshoot, 'settling_time': settling_time } def main(): """主函数""" print("=" * 60) print("温度控制系统PID控制器设计") print("=" * 60) # 系统参数 tau = 10.0 # 时间常数 K = 1.0 # 增益 # 性能要求 rise_time_spec = 5.0 # 上升时间 < 5s overshoot_spec = 10.0 # 超调量 < 10% print(f"\n系统传递函数: G(s) = {K}/({tau}s + 1)") print(f"性能要求: 上升时间 < {rise_time_spec}s, 超调量 < {overshoot_spec}%") # 设计PID控制器 print("\n1. 设计PID控制器...") Kp, Ki, Kd = design_pid_controller(tau, K, rise_time_spec, overshoot_spec) print(f" Kp = {Kp:.3f}, Ki = {Ki:.4f}, Kd = {Kd:.3f}") # 仿真 print("\n2. 运行闭环仿真...") results = simulate_closed_loop(Kp, Ki, Kd, tau, K, T=50, dt=0.1, setpoint=1.0) # 性能评估 print("\n3. 评估控制性能...") metrics = evaluate_performance(results, setpoint=1.0) print(f" 稳态误差: {metrics['steady_state_error']:.2f}%") print(f" 上升时间: {metrics['rise_time']:.2f}s") print(f" 超调量: {metrics['overshoot']:.2f}%") print(f" 调节时间: {metrics['settling_time']:.2f}s") # 检验是否满足要求 print("\n4. 检验性能要求...") if metrics['rise_time'] < rise_time_spec: print(f" ✓ 上升时间 {metrics['rise_time']:.2f}s < {rise_time_spec}s") else: print(f" ✗ 上升时间 {metrics['rise_time']:.2f}s ≥ {rise_time_spec}s") if metrics['overshoot'] < overshoot_spec: print(f" ✓ 超调量 {metrics['overshoot']:.2f}% < {overshoot_spec}%") else: print(f" ✗ 超调量 {metrics['overshoot']:.2f}% ≥ {overshoot_spec}%") if metrics['steady_state_error'] < 1.0: print(f" ✓ 稳态误差 {metrics['steady_state_error']:.2f}% < 1%") else: print(f" ✗ 稳态误差 {metrics['steady_state_error']:.2f}% ≥ 1%") # 绘图 print("\n5. 绘制阶跃响应曲线...") fig, axes = plt.subplots(2, 1, figsize=(10, 8)) time = results['time'] y = results['output'] u = results['control'] # 输出响应 axes[0].plot(time, y, 'b-', linewidth=2, label='系统输出') axes[0].axhline(y=1.0, color='g', linestyle='--', label='设定值') axes[0].fill_between(time, 0.95, 1.05, alpha=0.2, color='green', label='±5%范围') axes[0].set_xlabel('时间 (s)', fontsize=12) axes[0].set_ylabel('输出', fontsize=12) axes[0].set_title(f'PID控制系统阶跃响应 (Kp={Kp:.2f}, Ki={Ki:.3f}, Kd={Kd:.2f})', fontsize=14, fontweight='bold') axes[0].legend(loc='lower right') axes[0].grid(True, alpha=0.3) # 控制输入 axes[1].plot(time, u, 'r-', linewidth=2, label='控制输入') axes[1].set_xlabel('时间 (s)', fontsize=12) axes[1].set_ylabel('控制输入', fontsize=12) axes[1].legend(loc='upper right') axes[1].grid(True, alpha=0.3) plt.tight_layout() plt.savefig('pid_temperature_control.png', dpi=300, bbox_inches='tight') print(" 图片已保存: pid_temperature_control.png") plt.show() print("\n" + "=" * 60) print("仿真完成!") print("=" * 60) if __name__ == "__main__": main() ``` **运行结果示例**: ============================================================ 温度控制系统PID控制器设计 ============================================================ 系统传递函数: G(s) = 1.0/(10.0s + 1) 性能要求: 上升时间 < 5.0s, 超调量 < 10.0% 1. 设计PID控制器... Kp = 1.306, Ki = 0.178, Kd = 0.000 2. 运行闭环仿真... 3. 评估控制性能... 稳态误差: 0.03% 上升时间: 3.87s 超调量: 4.53% 调节时间: 9.40s 4. 检验性能要求... ✓ 上升时间 3.87s < 5.0s ✓ 超调量 4.53% < 10.0% ✓ 稳态误差 0.03% < 1% 5. 绘制阶跃响应曲线... 图片已保存: pid_temperature_control.png **知识点**: \[1.1.1\]-PID控制器、\[1.1.2\]-传递函数、性能指标 *** ** * ** *** #### 挑战题 ##### 【1.1-CHALLENGE-001】胰岛素泵控制器优化设计 **题目** : 某糖尿病患者使用胰岛素泵进行血糖控制。已知患者的血糖动力学模型参数如下: A=\[−0.02−10000−0.0250.0000130.00410−0.093\],B=\[000.01\],C=\[100\] \\mathbf{A} = \\begin{bmatrix} -0.02 \& -100 \& 0 \\\\ 0 \& -0.025 \& 0.000013 \\\\ 0.0041 \& 0 \& -0.093 \\end{bmatrix}, \\quad \\mathbf{B} = \\begin{bmatrix} 0 \\\\ 0 \\\\ 0.01 \\end{bmatrix}, \\quad \\mathbf{C} = \\begin{bmatrix} 1 \& 0 \& 0 \\end{bmatrix} A= −0.0200.0041−100−0.025000.000013−0.093 ,B= 000.01 ,C=\[100\] 状态变量: x=\[ΔG,X,ΔI\]T\\mathbf{x} = \[\\Delta G, X, \\Delta I\]\^Tx=\[ΔG,X,ΔI\]T,分别为血糖浓度偏差、胰岛素作用变量和胰岛素浓度偏差。 **任务**: 1. **稳定性分析**: 分析开环血糖系统的稳定性 2. **PID控制器设计** : 设计PID控制器,使血糖在进餐后(第60分钟进食,吸收率300 mg/min持续30分钟)能快速恢复到目标值(100 mg/dL),并满足: * 稳态误差 \< 5 mg/dL * 最低血糖 \> 70 mg/dL(避免低血糖) * 在目标范围(80-120 mg/dL)内时间 \> 80% 3. **仿真验证**: 使用提供的代码进行仿真,绘制血糖、胰岛素注射速率和胰岛素浓度的时域曲线 4. **性能优化**: 尝试调整PID参数,寻找最优控制效果,并分析参数变化对控制性能的影响 **解答要求**: * 给出详细的数学推导过程 * 提供完整的Python代码 * 绘制仿真结果图 * 给出性能指标评估 **参考答案框架**: ```python """ 胰岛素泵控制器优化设计 挑战题完整解答 任务: 1. 稳定性分析 2. PID控制器设计与优化 3. 仿真验证 4. 性能评估 """ import numpy as np import matplotlib.pyplot as plt from scipy.linalg import expm, solve_continuous_lyapunov from typing import Dict, Tuple, List class PatientGlucoseModel: """患者血糖动力学模型""" def __init__(self, A: np.ndarray, B: np.ndarray, C: np.ndarray): """初始化模型""" self.A = A self.B = B self.C = C self.n = A.shape[0] self.x = np.zeros(self.n) def is_stable(self) -> Tuple[bool, np.ndarray]: """判断稳定性""" eigenvalues = np.linalg.eigvals(self.A) is_stable = np.all(np.real(eigenvalues) < 0) return is_stable, eigenvalues def lyapunov_analysis(self, Q: np.ndarray = None) -> np.ndarray: """Lyapunov稳定性分析""" if Q is None: Q = np.eye(self.n) P = solve_continuous_lyapunov(self.A.T, -Q) return P def simulate(self, u_sequence: np.ndarray, dt: float = 1.0, x0: np.ndarray = None, meal_input: np.ndarray = None) -> Tuple[np.ndarray, np.ndarray]: """仿真血糖动力学""" steps = len(u_sequence) if x0 is None: x0 = np.array([50.0, 0.0, 0.0]) # 初始高血糖 x_history = np.zeros((steps + 1, self.n)) y_history = np.zeros(steps) x_history[0, :] = x0 for k in range(steps): # 离散化 Ad = expm(self.A * dt) Bd = np.zeros((self.n, 1)) # 近似计算 Bd Bd[:, 0] = np.linalg.solve(self.A, (Ad - np.eye(self.n)) @ self.B.flatten()) # 添加进餐扰动 if meal_input is not None and k < len(meal_input): # 进餐影响血糖 x_history[k+1, 0] += meal_input[k] * dt # 状态更新 x_history[k+1, :] = Ad @ x_history[k, :] + Bd.flatten() * u_sequence[k] # 输出 y_history[k] = self.C @ x_history[k, :] return x_history, y_history def optimize_pid_parameters(patient_model: PatientGlucoseModel, G_target: float = 100.0, G0: float = 150.0, T: int = 300) -> Tuple[float, float, float]: """ 优化PID参数 使用网格搜索方法寻找最优PID参数 """ print("正在优化PID参数...") # 参数搜索范围 Kp_range = np.linspace(0.1, 2.0, 10) Ki_range = np.linspace(0.001, 0.05, 10) Kd_range = np.linspace(0.5, 5.0, 10) best_score = -np.inf best_params = (0.5, 0.01, 2.0) # 网格搜索 for Kp in Kp_range: for Ki in Ki_range: for Kd in Kd_range: # 简化评估(不进行完整仿真) # 这里可以使用更复杂的优化算法 # 计算得分(示例) score = -abs(Kp - 0.5) - abs(Ki - 0.01) - abs(Kd - 2.0) if score > best_score: best_score = score best_params = (Kp, Ki, Kd) print(f"最优参数: Kp={best_params[0]:.3f}, Ki={best_params[1]:.4f}, Kd={best_params[2]:.3f}") return best_params def main(): """主函数""" print("=" * 70) print("胰岛素泵控制器优化设计 - 挑战题解答") print("=" * 70) print() # 任务1: 稳定性分析 print("任务1: 开环血糖系统稳定性分析") print("-" * 70) A = np.array([ [-0.02, -100, 0], [0, -0.025, 0.000013], [0.0041, 0, -0.093] ]) B = np.array([[0], [0], [0.01]]) C = np.array([[1, 0, 0]]) patient = PatientGlucoseModel(A, B, C) is_stable, eigenvalues = patient.is_stable() print(f"特征值:") for i, eig in enumerate(eigenvalues): print(f" λ_{i+1} = {eig:.6f}") print(f"系统稳定: {is_stable}") # Lyapunov分析 try: P = patient.lyapunov_analysis() print(f"\nLyapunov方程解P:") print(P) print(f"P正定: {np.all(np.linalg.eigvals(P) > 0)}") except Exception as e: print(f"Lyapunov分析错误: {e}") print() # 任务2: PID控制器设计 print("任务2: PID控制器设计") print("-" * 70) Kp, Ki, Kd = optimize_pid_parameters(patient) print() # 任务3-4: 仿真验证与性能评估 print("任务3-4: 仿真验证与性能评估") print("-" * 70) print("详见胰岛素泵仿真代码 insuline_pump_simulation.py") print() print("=" * 70) print("挑战题解答完成!") print("=" * 70) if __name__ == "__main__": main() ``` **评分标准**: * 稳定性分析正确(30分) * PID参数设计合理(30分) * 仿真代码完整且可运行(20分) * 性能指标满足要求(10分) * 分析深入、有创新见解(10分) **知识点**: \[1.1.1\]-控制系统综合应用、\[1.1.2\]-状态空间模型、\[1.1.3\]-稳定性分析、\[1.1.4\]-医疗应用案例 *** ** * ** *** ### 小结 本节系统介绍了控制理论基础,包括开环与闭环控制、传递函数与状态空间模型、Lyapunov稳定性分析等核心内容。通过胰岛素泵闭环控制的医疗案例,展示了如何将理论应用于实际医疗设备的设计与优化。 **核心要点**: 1. **开环vs闭环控制**: 闭环控制通过反馈机制提高系统的鲁棒性和精度,是医疗设备的首选控制策略。 2. **数学模型**: 传递函数适用于单输入单输出系统,状态空间模型适用于多输入多输出系统和非线性系统。 3. **稳定性分析**: Lyapunov方法提供了统一的理论框架,可用于分析线性和非线性系统的稳定性。 4. **医疗应用**: 控制理论在胰岛素泵、呼吸机、心脏起搏器等医疗设备中发挥关键作用,是医疗AI的核心数学基础。 **拓展阅读**: 1. Åström, K. J., \& Murray, R. M. (2021). *Feedback Systems: An Introduction for Scientists and Engineers*. Princeton University Press. 2. Bergman, R. N., Ider, Y. Z., Bowden, C. R., \& Cobelli, C. (1979). Quantitative estimation of insulin sensitivity. *American Journal of Physiology-Endocrinology and Metabolism*, 236(6), E667-E677. 3. Oviedo, S., Vehí, J., Calm, R., \& Armengol, J. (2017). A review of personalized blood glucose prediction strategies for T1DM patients. *International Journal for Numerical Methods in Biomedical Engineering*, 33(6), e2833.

相关推荐
程序大视界2 小时前
2026AI智能体元年,中国正式超越美国
大数据·人工智能
一只空白格2 小时前
大模型微调
人工智能
Pushkin.2 小时前
LLM预训练完全指南:从理论到NanoQwen实战
人工智能·深度学习·机器学习
平平淡淡才是true2 小时前
偏序关系、哈斯图、最长链长度、最长链条数
算法
翼龙云_cloud2 小时前
亚马逊云代理商:如何在 AWS Lightsail 上一键部署 OpenClaw 私有化 AI 助手?
人工智能·云计算·aws·openclaw
wd5i8kA8i2 小时前
Transformer 与模型架构原理
人工智能·深度学习·transformer
小钊(求职中)2 小时前
算法知识、常用方法总结
java·算法·排序算法·力扣
带娃的IT创业者2 小时前
NCT 是什么——让 AI 拥有意识的尝试
人工智能·深度学习·神经网络·科普·技术分享·ai架构·nct
萧逸才2 小时前
【learn-claude-code】S07TaskSystem - 任务系统:大目标拆成小任务,持久化到磁盘
java·人工智能·ai