简介:这份资源是吉林大学通信工程学院自动化专业大三的计算机控制系统课件,面向自动化、控制工程等方向的学生与自学者,帮助系统掌握计算机控制系统的原理、设计与应用。内容围绕传感器、数据采集系统、计算机、控制器、执行机构、反馈系统与人机交互界面等核心组成展开,并覆盖开环与闭环控制、DCS、PLC、现场总线控制系统等类型,同时涉及PID控制、状态空间法、Z变换、实时操作系统、MODBUS与CAN等工业通信协议、冗余设计与故障诊断、控制系统软件开发流程等关键知识点。资源包共116个文件,以85个ppt课件为主,辅以10个doc试题与答案、9个m脚本、6个fig图形和6个gif素材,压缩包约14.54MB,目录结构便于按章节检索复习。目前已有185人学习,适合课堂同步学习、期末复习与考研备考使用。
1. 计算机控制系统:从采样周期到代码落地的真实门槛
很多做嵌入式和工控的朋友第一次接触计算机控制系统,都会卡在同一个地方:理论课上的 Z 变换、离散传递函数、极点配置算得滚瓜烂熟,真到把算法写进控制器里跑起来,电机就是抖,温度就是超调,位置环就是有稳态误差。问题往往不在算法本身,而在采样周期选错了、量化位数不够、或者积分项在输出限幅时没有做抗饱和处理。计算机控制系统这门技术,核心就是用数字计算机去替代模拟调节器,把连续的被控对象通过采样、量化、计算、输出这一套流程闭环起来。它适合做运动控制、过程控制、电源管理、机器人关节伺服这类需要精确动态响应的场景,也适合任何想把经典控制理论真正落到 MCU 或 PLC 上的工程师。这一章先把边界划清楚:不是所有控制都值得上计算机,采样频率、计算延迟、量化噪声这三个硬约束决定了你的系统能不能用数字方案。
2. 离散化方法怎么选:从连续域到数字域的四种映射
2.1 为什么不能直接把 s 换成 (z-1)/T
最朴素的想法是把连续传递函数 G(s) 里的 s 用 (z-1)/T 替换,这叫前向差分法。它确实简单,但有个致命问题:如果原系统在 s 平面左半平面有极点,映射到 z 平面后不一定还在单位圆内。举个例子,G(s)=1/(s+10),采样周期 T=0.1s,前向差分得到 G(z)=1/((z-1)/0.1+10)=0.1/(z-1+1)=0.1/z,极点从 s=-10 映射到 z=0,看起来还行。但如果 T 取大了,比如 T=0.5s,极点会跑到 z=-4,直接发散。所以前向差分只适合采样周期远小于系统最小时间常数的情况,工程上我一般要求 T 小于主导时间常数的十分之一。
后向差分法把 s 换成 (z-1)/(Tz),映射关系是 z=1/(1-sT)。这个映射有个好性质:s 左半平面一定映射到 z 单位圆内,无条件稳定。代价是频率轴会畸变,高频段压缩得厉害。对于大多数工业控制场景,后向差分是安全牌,尤其是你拿不准采样周期该取多少的时候。
双线性变换(Tustin)把 s 换成 (2/T)(z-1)/(z+1),频率预畸变后可以保证截止频率处映射准确。这是工程上最常用的方法,MATLAB 的 c2d 默认就是它。但要注意,双线性变换会在高频段引入相位滞后,如果你的系统带宽接近奈奎斯特频率,这个滞后可能吃掉相位裕度。
零极点匹配法(ZOH 等效)适合对象模型已知且需要精确保持脉冲响应的场景。它把连续极点按 z=exp(sT) 映射,零点按同样规则映射,再补上无穷远处的零点。这种方法在电机控制里用得很多,因为电机的电气时间常数和机械时间常数分离明显,ZOH 等效能保持低频特性。
2.2 用 Python 做离散化的最小可跑代码
下面这段代码用 scipy 的 cont2discrete 做四种方法的对比,你可以直接复制运行,改改参数就能看到不同采样周期下的极点分布。
import numpy as np from scipy.signal import cont2discrete, tf2zpk import matplotlib.pyplot as plt # 连续对象:二阶系统,自然频率 10 rad/s,阻尼比 0.5 num = [100] den = [1, 10, 100] T_values = [0.01, 0.05, 0.1] # 采样周期,单位秒 methods = ['zoh', 'bilinear', 'forward_diff', 'backward_diff'] fig, axes = plt.subplots(1, 3, figsize=(15, 5)) for idx, T in enumerate(T_values): ax = axes[idx] theta = np.linspace(0, 2*np.pi, 200) ax.plot(np.cos(theta), np.sin(theta), 'k--', linewidth=1, label='单位圆') for method in methods: try: # cont2discrete 返回 (num_d, den_d, dt) num_d, den_d, _ = cont2discrete((num, den), T, method=method) z, p, k = tf2zpk(num_d, den_d) ax.scatter(np.real(p), np.imag(p), label=method, s=60) except Exception as e: print(f"方法 {method} 在 T={T} 时失败: {e}") ax.set_title(f'T = {T}s') ax.set_xlabel('实部') ax.set_ylabel('虚部') ax.grid(True) ax.legend(fontsize=8) ax.set_aspect('equal') plt.tight_layout() plt.savefig('discretization_poles.png', dpi=150) plt.show()这段代码的逻辑很直接:对同一个连续二阶系统,分别在 0.01s、0.05s、0.1s 三个采样周期下,用四种离散化方法算出离散极点,画在 z 平面单位圆上。你会看到几个关键现象:T=0.01s 时四种方法极点几乎重合,都在单位圆内靠近 1 的位置;T=0.05s 时前向差分的极点开始往外跑;T=0.1s 时前向差分直接发散到单位圆外,后向差分和双线性还在圆内但位置差异明显。
参数说明:num 和 den 是连续传递函数的分子分母系数,这里对应 G(s)=100/(s²+10s+100),自然频率 ωn=10 rad/s,阻尼比 ζ=0.5。T_values 是你要评估的采样周期候选值。cont2discrete 的 method 参数支持 'zoh'、'bilinear'、'forward_diff'、'backward_diff'、'gbt' 等,其中 'gbt' 是带预畸变的双线性变换,需要额外传 alpha 参数。
实际选型时,我一般先算系统的闭环带宽 ωb,然后取采样频率 fs 在 10ωb 到 20ωb 之间。如果带宽是 100 rad/s,fs 至少 1000 rad/s,对应 T=1ms。这个规则不是死的,但低于 10 倍带宽时,离散化引入的相位滞后会明显降低相位裕度,你会看到阶跃响应超调变大、调节时间变长。
2.3 采样周期与计算延迟的联合约束
采样周期不是越小越好。T 越小,单位时间内中断次数越多,CPU 负载越高;同时量化噪声的相对影响也越大,因为每次采样的增量变小了。更隐蔽的问题是计算延迟:从 ADC 采样到 PWM 输出更新,中间有采样保持、AD 转换、算法计算、PWM 寄存器写入这几步,总延迟 Td 会直接吃掉相位裕度。相位损失近似为 ωc·Td,ωc 是截止频率。如果 ωc=1000 rad/s,Td=100μs,相位损失就是 0.1 rad,约 5.7 度。看起来不大,但如果你的相位裕度只有 45 度,这 5.7 度就很要命了。
工程上的做法是把计算延迟折算成等效的采样周期增加。比如实际 T=1ms,计算延迟 200μs,那么设计离散控制器时按 T_eff=1.2ms 来算,或者直接在连续域设计时把延迟环节 exp(-Td·s) 用帕德近似加进去。我一般会在 MATLAB 里用c2d之前先给连续模型串一个pade(Td, 2),这样离散化后的控制器更保守,实际跑起来超调更小。
3. 数字 PID 的工程实现:从位置式到增量式的五个细节
3.1 位置式 PID 的积分饱和与抗饱和
位置式 PID 的输出直接对应执行器位置,公式是 u(k)=Kp·e(k)+Ki·Σe(j)+Kd·(e(k)-e(k-1))。问题出在积分项:只要误差不为零,积分项就一直累加,直到输出饱和。饱和后误差依然存在,积分项继续涨,等误差反向时,积分项要花很长时间才能退回来,这就是积分饱和。现象是系统超调巨大、恢复极慢,血泪经验是电机直接撞限位。
抗饱和的常见做法有三种:积分分离、反计算、条件积分。积分分离是当误差大于某个阈值时停止积分,只保留比例和微分;反计算是把饱和后的输出与未饱和输出的差值乘一个系数反馈到积分项;条件积分是只在输出未饱和时累加积分。我一般用反计算,因为它平滑,不会在阈值附近抖动。
// 位置式 PID 带反计算抗饱和,定点数实现 typedef struct { float Kp, Ki, Kd; float integral; float prev_error; float out_max, out_min; float Kaw; // 抗饱和增益,通常取 1/Ki 或 1 } PID_Pos; float PID_Pos_Update(PID_Pos *pid, float setpoint, float feedback, float dt) { float error = setpoint - feedback; // 比例项 float P = pid->Kp * error; // 积分项(先算未饱和输出) float integral_new = pid->integral + pid->Ki * error * dt; // 微分项(对反馈微分,避免设定值突变冲击) float D = pid->Kd * (feedback - pid->prev_feedback) / dt; pid->prev_feedback = feedback; // 未饱和输出 float u_unsat = P + integral_new - D; // 饱和限幅 float u_sat = u_unsat; if (u_sat > pid->out_max) u_sat = pid->out_max; if (u_sat < pid->out_min) u_sat = pid->out_min; // 反计算抗饱和:把饱和差值反馈回积分项 pid->integral = integral_new + pid->Kaw * (u_sat - u_unsat) * dt; pid->prev_error = error; return u_sat; }这段代码的关键在最后一步:pid->integral = integral_new + pid->Kaw * (u_sat - u_unsat) * dt。当输出饱和时,u_sat 和 u_unsat 的差值会通过 Kaw 反馈到积分项,把积分项往回拉。Kaw 的取值影响恢复速度,太大容易振荡,太小抗饱和效果弱。我一般先取 Kaw=1/Ki,然后根据实际波形微调。注意微分项用的是反馈微分而不是误差微分,这样设定值阶跃变化时微分项不会产生尖峰冲击。
参数说明:dt 是采样周期,必须和实际中断周期一致,不能用理论值代替。out_max 和 out_min 是执行器的物理限幅,比如 PWM 占空比 0~100%、阀门开度 0~100%。Kp、Ki、Kd 的整定顺序是先 P 后 I 再 D,每次只调一个参数,观察阶跃响应。
3.2 增量式 PID 的适用场景与代码
增量式 PID 输出的是控制量的增量 Δu(k),执行器需要支持增量输入(比如步进电机的脉冲频率控制)。它的好处是不需要累加历史误差,积分饱和问题天然较弱,而且手动/自动切换时冲击小。公式是 Δu(k)=Kp·(e(k)-e(k-1))+Ki·e(k)+Kd·(e(k)-2e(k-1)+e(k-2))。
typedef struct { float Kp, Ki, Kd; float prev_error; float prev_prev_error; float out_max, out_min; float output; } PID_Inc; float PID_Inc_Update(PID_Inc *pid, float setpoint, float feedback) { float error = setpoint - feedback; // 增量计算 float delta_u = pid->Kp * (error - pid->prev_error) + pid->Ki * error + pid->Kd * (error - 2*pid->prev_error + pid->prev_prev_error); // 累加到输出并限幅 pid->output += delta_u; if (pid->output > pid->out_max) pid->output = pid->out_max; if (pid->output < pid->out_min) pid->output = pid->out_min; // 更新历史误差 pid->prev_prev_error = pid->prev_error; pid->prev_error = error; return pid->output; }增量式 PID 的 Ki 和位置式的 Ki 含义不同:位置式 Ki 是积分系数,增量式 Ki 直接乘当前误差。整定时先把 Kp 和 Kd 设为零,调 Ki 到输出开始缓慢变化,再加 Kp 加快响应,最后加 Kd 抑制超调。注意增量式 PID 对量化误差更敏感,因为每次增量可能很小,如果 ADC 位数不够,增量会被量化噪声淹没。我一般要求 ADC 有效位数至少比控制精度要求高 2 位。
3.3 微分项的四种实现与噪声抑制
微分项是数字 PID 里最容易翻车的部分。理想微分 D=Kd·de/dt 对噪声无限放大,实际 ADC 读数哪怕只有 1 个 LSB 的抖动,微分项输出就可能跳变几十个 LSB。常见做法有四种:对误差做差分后低通滤波、对反馈做差分、用不完全微分(串一个一阶低通)、用跟踪微分器。
我一般用不完全微分,传递函数是 Kd·s/(1+τ·s),离散化后 D(k)=α·D(k-1)+(1-α)·Kd·(e(k)-e(k-1))/dt,其中 α=τ/(τ+dt)。τ 取微分时间的 1/5 到 1/10,比如 Kd 对应微分时间 10ms,τ 取 1~2ms。这样高频噪声被压制,低频微分作用保留。
// 不完全微分实现 typedef struct { float Kd; float alpha; // 滤波系数,0.8~0.95 float D_prev; float prev_feedback; } PID_Diff; float PID_Diff_Update(PID_Diff *pd, float feedback, float dt) { float d_feedback = (feedback - pd->prev_feedback) / dt; pd->prev_feedback = feedback; // 不完全微分:一阶低通滤波 float D = pd->alpha * pd->D_prev + (1 - pd->alpha) * pd->Kd * d_feedback; pd->D_prev = D; return D; }参数说明:alpha 越接近 1,滤波越强,微分作用越弱。调试时先取 alpha=0.9,如果响应还是抖,降到 0.8;如果响应变慢,升到 0.95。注意这个微分项是独立计算的,最终输出是 P+I-D 或 P+I+D,取决于你对微分作用方向的定义。我习惯用 P+I-D,因为反馈增加时微分项应该减小输出,起到阻尼作用。
4. 状态空间与极点配置:从能控性到观测器的落地
4.1 离散状态空间模型的建立
连续状态空间是 ẋ=Ax+Bu,y=Cx+Du。离散化后 x(k+1)=Ad·x(k)+Bd·u(k),其中 Ad=exp(A·T),Bd=∫₀ᵀ exp(A·τ)·B·dτ。MATLAB 的 c2d 可以直接算,Python 用 scipy.signal.cont2discrete 传 'zoh' 也能算。关键是 A 矩阵的物理含义:它描述状态之间的耦合关系。比如电机控制里,状态选电流和转速,A 矩阵就包含电气时间常数和机械时间常数的耦合项。
import numpy as np from scipy.linalg import expm # 连续状态空间:直流电机简化模型 # 状态 x = [电流 i, 转速 omega] # di/dt = -R/L * i - Ke/L * omega + 1/L * u # domega/dt = Kt/J * i - B/J * omega R, L, Ke, Kt, J, B = 1.0, 0.01, 0.05, 0.05, 0.001, 1e-5 A = np.array([[-R/L, -Ke/L], [Kt/J, -B/J]]) B = np.array([[1/L], [0]]) C = np.array([[0, 1]]) # 只测转速 D = np.array([[0]]) T = 0.001 # 1ms 采样 # ZOH 离散化 Ad = expm(A * T) Bd = np.linalg.solve(A, (Ad - np.eye(2))) @ B print("Ad =", Ad) print("Bd =", Bd) # 能控性矩阵 Wc = np.hstack([Bd, Ad @ Bd]) print("能控性矩阵秩:", np.linalg.matrix_rank(Wc))这段代码算的是直流电机的离散状态空间模型。R/L=100,说明电气时间常数 10ms;J/B 很大,机械时间常数远大于电气时间常数。这种双时间尺度系统在离散化时要注意:如果 T 取 1ms,电气动态被采样了 10 个点,机械动态几乎没动。能控性矩阵的秩如果是 2,说明系统完全能控,可以任意配置极点。
参数说明:R 是电枢电阻,L 是电枢电感,Ke 是反电动势常数,Kt 是转矩常数,J 是转动惯量,B 是粘滞摩擦系数。这些参数从电机手册或实验辨识得到。T 是采样周期,必须小于电气时间常数的 1/5,否则离散化误差大。
4.2 极点配置与 LQR 的取舍
极点配置是给定期望的闭环极点位置,反算反馈增益 K。离散系统的期望极点一般取 z=exp(-ζωn·T)±j·exp(-ζωn·T)·sin(ωn·√(1-ζ²)·T),其中 ζ 和 ωn 是你期望的阻尼比和自然频率。极点配置的优点是直观,缺点是当系统阶数高时,极点位置对增益的影响很敏感,而且没有考虑控制能量。
LQR 是优化二次型代价函数 J=Σ(xᵀQx+uᵀRu),得到最优增益 K=(R+BdᵀP Bd)⁻¹BdᵀP Ad,其中 P 是离散黎卡提方程的解。LQR 的优点是自动权衡状态误差和控制能量,缺点是 Q 和 R 的整定需要经验。我一般先用极点配置得到一个粗略的 K,然后用 LQR 微调,Q 取对角阵,对角线元素对应各状态的允许误差倒数平方,R 取 1 起步。
from scipy.linalg import solve_discrete_are # LQR 设计 Q = np.diag([1.0, 100.0]) # 转速误差权重远大于电流误差 R = np.array([[1.0]]) # 控制能量权重 # 求解离散黎卡提方程 P = solve_discrete_are(Ad, Bd, Q, R) # 计算最优增益 K = np.linalg.inv(R + Bd.T @ P @ Bd) @ Bd.T @ P @ Ad print("LQR 增益 K =", K) # 闭环极点 Acl = Ad - Bd @ K eigvals = np.linalg.eigvals(Acl) print("闭环极点 =", eigvals) print("极点模值 =", np.abs(eigvals))这段代码用 scipy 的 solve_discrete_are 解离散黎卡提方程,然后算 LQR 增益。Q 的对角线是 [1, 100],意思是转速误差的惩罚是电流误差的 100 倍,因为转速是最终控制目标。R=1 是控制量的基准权重。算出的 K 是一个 1×2 的行向量,分别对应电流和转速的反馈系数。闭环极点的模值必须小于 1,否则系统不稳定。
参数说明:Q 和 R 的比值决定控制 aggressiveness。Q 相对 R 越大,控制越猛,响应快但可能超调;Q 相对 R 越小,控制越温和,响应慢但平滑。我一般先让 Q 的对角线元素等于对应状态最大允许误差的倒数平方,R 取最大允许控制量的倒数平方,然后根据仿真波形微调。
4.3 状态观测器的实现与降阶技巧
实际系统往往只能测部分状态,比如电机只测转速,电流要么用传感器测要么用观测器估。全维观测器是 x̂(k+1)=Ad·x̂(k)+Bd·u(k)+L·(y(k)-C·x̂(k)),L 是观测器增益,按观测器误差动态比控制器快 2~5 倍来配置。降阶观测器是利用已知的测量量,只估计不可测状态,计算量小但推导麻烦。
// 全维状态观测器 + 状态反馈,定点数实现 typedef struct { float Ad[2][2]; float Bd[2]; float L[2]; float x_hat[2]; // 估计状态 } Observer; void Observer_Update(Observer *obs, float u, float y) { // 预测 float x_pred[2]; x_pred[0] = obs->Ad[0][0]*obs->x_hat[0] + obs->Ad[0][1]*obs->x_hat[1] + obs->Bd[0]*u; x_pred[1] = obs->Ad[1][0]*obs->x_hat[0] + obs->Ad[1][1]*obs->x_hat[1] + obs->Bd[1]*u; // 测量残差 float y_hat = obs->x_hat[1]; // 假设 C=[0,1] float residual = y - y_hat; // 校正 obs->x_hat[0] = x_pred[0] + obs->L[0] * residual; obs->x_hat[1] = x_pred[1] + obs->L[1] * residual; } float State_Feedback(Observer *obs, float K[2], float ref) { // 状态反馈 u = -K*x_hat + ref return -K[0]*obs->x_hat[0] - K[1]*obs->x_hat[1] + ref; }这段代码实现了全维观测器和状态反馈。Observer_Update 先按模型预测下一步状态,然后用测量残差校正。L 的选择决定观测器收敛速度,L 越大收敛越快但对噪声越敏感。我一般让观测器极点模值在 0.1~0.3 之间,对应收敛时间 2~5 个采样周期。State_Feedback 里的 ref 是参考输入,如果是跟踪问题,ref 需要乘以一个前馈增益,使得稳态时输出等于设定值。
参数说明:Ad 和 Bd 是离散状态矩阵,L 是观测器增益,x_hat 是状态估计。注意观测器初始值 x_hat 一般设为零,但如果系统有稳态工作点,应该设成工作点状态,否则启动时会有较大瞬态。定点数实现时要注意 Ad 和 Bd 的 Q 格式,避免溢出。
5. 避坑与排查:计算机控制系统里最容易翻车的五件事
5.1 采样周期选错导致离散化失真
现象:阶跃响应超调远大于仿真值,或者系统直接振荡发散。原因:采样周期大于系统主导时间常数的 1/5,离散化后的极点位置严重偏离连续域设计。解决:先测系统的开环阶跃响应,找到上升到 63% 的时间 τ,取 T≤τ/10。如果 CPU 负载不允许,降低控制带宽,或者换更快的处理器。
5.2 积分饱和导致启动冲击
现象:系统启动时输出直接顶到限幅,误差反向时长时间不恢复,电机撞限位或阀门卡死。原因:位置式 PID 的积分项在饱和期间持续累加。解决:加反计算抗饱和,Kaw 取 1/Ki 起步;或者改用增量式 PID;或者在启动阶段用积分分离,误差大时先不积分。
5.3 微分噪声导致输出抖动
现象:执行器发出高频啸叫,电流波形毛刺大,电机发热。原因:微分项对 ADC 量化噪声和 PWM 开关噪声无限放大。解决:用不完全微分,alpha 取 0.8~0.95;对反馈做滑动平均滤波,窗口 3~5 点;提高 ADC 分辨率或加模拟前端滤波。
5.4 计算延迟吃掉相位裕度
现象:仿真相位裕度 50 度,实际跑起来只有 30 度,超调大、调节时间长。原因:从采样到输出有 ADC 转换、算法计算、PWM 更新等延迟,总延迟 Td 引入额外相位滞后 ωc·Td。解决:在连续域设计时串入 pade(Td,2) 近似延迟;或者把采样周期按 T_eff=T+Td 来设计;或者用预测控制补偿延迟。
5.5 定点数量化误差累积
现象:稳态时输出在小范围内极限环振荡,误差不收敛到零。原因:定点数运算的截断误差在积分项里累积,或者 ADC 有效位数不够,增量式 PID 的增量被量化噪声淹没。解决:积分项用 32 位累加器,输出前再截断;ADC 有效位数至少比控制精度要求高 2 位;关键路径用浮点运算,或者用 Q15 格式并做舍入处理。
6. 进阶技巧:用频域指标反推采样周期与滤波器参数
前面讲的都是时域设计和调试,但真正让计算机控制系统稳定可靠的,是频域指标的闭环验证。我一般会在离散化之后,用scipy.signal.dbode画离散系统的伯德图,检查幅值裕度和相位裕度。如果相位裕度低于 45 度,要么降低控制器增益,要么提高采样频率,要么加超前校正。
from scipy.signal import dbode import matplotlib.pyplot as plt # 假设已得到离散控制器 C(z) 和离散对象 G(z) # 这里用示例系数 num_c = [0.5, -0.4] # C(z) 分子 den_c = [1, -0.1] # C(z) 分母 num_g = [0.05, 0.02] # G(z) 分子 den_g = [1, -1.5, 0.7] # G(z) 分母 # 开环传递函数 num_open = np.polymul(num_c, num_g) den_open = np.polymul(den_c, den_g) # 画伯德图 plt.figure(figsize=(10, 8)) dbode(num_open, den_open, 0.001) # T=1ms plt.savefig('bode_discrete.png', dpi=150) plt.show() # 计算幅值裕度和相位裕度 from scipy.signal import freqresp w = np.logspace(-1, 4, 1000) _, h = freqresp((num_open, den_open), w, dt=0.001) mag_db = 20*np.log10(np.abs(h)) phase_deg = np.angle(h, deg=True) # 找穿越频率 idx_cross = np.where(np.diff(np.sign(mag_db)))[0] if len(idx_cross) > 0: wc = w[idx_cross[0]] pm = 180 + phase_deg[idx_cross[0]] print(f"穿越频率 {wc:.1f} rad/s, 相位裕度 {pm:.1f} 度")这段代码画离散系统的伯德图并算相位裕度。dbode 的第三个参数是采样周期,必须和实际一致。相位裕度的计算是 180 度加上穿越频率处的相位。如果相位裕度小于 45 度,系统会有明显超调;小于 30 度,基本不能用。我一般要求相位裕度 50~60 度,幅值裕度 10dB 以上。
参数说明:num_open 和 den_open 是开环传递函数的分子分母,由控制器和对象卷积得到。w 是频率扫描范围,从 0.1 到 10000 rad/s。dt 是采样周期。注意离散系统的频率响应是周期性的,只画到奈奎斯特频率(π/T)以内有效。
最后一个技巧:如果相位裕度不够,优先加超前校正,而不是一味降低增益。超前校正的离散实现是 C(z)=K·(z-zc)/(z-pc),其中 zc<pc<1,zc 和 pc 的位置根据需要的相位超前量算。我一般用scipy.signal.cont2discrete把连续超前校正离散化,然后微调零极点位置。调试时先看伯德图,再看阶跃响应,两者一致了再上实际系统。希望帮到你。
本文还有配套的精品资源,点击获取