2. SMO滑模面设计与切换函数选择
任务目标
本案例针对永磁同步电机(PMSM)无位置传感器控制中的滑模观测器(SMO),实现两种滑模面(线性滑模面、非线性滑模面)与两种切换函数(符号函数、饱和函数)的组合对比。通过仿真或实际代码运行,观察不同组合对反电动势观测波形的影响,重点评估抖振抑制效果与观测精度。
核心原理与设计要点
滑模观测器的核心是构造电流误差的滑模面,并设计切换控制律使系统状态到达并维持在滑模面上。线性滑模面形式为 s = i' - i(其中 i' 为观测电流,i 为实际电流),结构简单但收敛速度固定;非线性滑模面引入电流误差的幂次项,可加快趋近速度并降低稳态误差。切换函数方面,符号函数 sign(s) 产生高频抖振,而饱和函数 sat(s/φ) 在边界层内采用线性控制,可有效抑制抖振但会引入一定相位延迟。本案例通过可切换的配置参数,在统一框架下对比四种组合的性能差异。
完整实现代码
import numpy as np
import matplotlib.pyplot as plt
# ---------- PMSM 模型参数 ----------
Rs = 2.0 # 定子电阻 (Ω)
Ld = Lq = 0.01 # d/q轴电感 (H)
Ke = 0.1 # 反电动势系数 (V·s/rad)
J = 0.001 # 转动惯量 (kg·m²)
B = 0.0001 # 阻尼系数 (N·m·s)
pole_pairs = 4 # 极对数
# ---------- 仿真参数 ----------
dt = 1e-5 # 步长 (s)
t_end = 0.1 # 仿真时长 (s)
t = np.arange(0, t_end, dt)
n_steps = len(t)
# 电机运行条件
omega_e = 200.0 # 电角速度 (rad/s),恒定速度假设
theta_e = 0.0 # 初始电角度
# 实际电流(由理想反电动势驱动,用于生成观测器输入)
i_alpha_true = np.zeros(n_steps)
i_beta_true = np.zeros(n_steps)
for k in range(n_steps):
theta_e = omega_e * t[k]
e_alpha = -Ke * omega_e * np.sin(theta_e)
e_beta = Ke * omega_e * np.cos(theta_e)
# 简化:假设电流为反电动势经一阶惯性后的结果(模拟电机动态)
if k == 0:
i_alpha_true[k] = 0
i_beta_true[k] = 0
else:
di_alpha = (e_alpha - Rs * i_alpha_true[k-1]) / Ld * dt
di_beta = (e_beta - Rs * i_beta_true[k-1]) / Lq * dt
i_alpha_true[k] = i_alpha_true[k-1] + di_alpha
i_beta_true[k] = i_beta_true[k-1] + di_beta
# ---------- SMO 参数 ----------
k_smo = 50.0 # 滑模增益
phi = 0.5 # 饱和函数边界层厚度
# ---------- 滑模面与切换函数定义 ----------
def sliding_surface(err_alpha, err_beta, mode):
"""计算滑模面 s = [s_alpha, s_beta]"""
if mode == 'linear':
return err_alpha, err_beta
elif mode == 'nonlinear':
# 非线性滑模面:引入误差的立方项加速收敛
return err_alpha + 0.5 * err_alpha**3, err_beta + 0.5 * err_beta**3
else:
raise ValueError("Unknown sliding surface mode")
def switching_function(s_alpha, s_beta, mode):
"""切换函数输出"""
if mode == 'sign':
return np.sign(s_alpha), np.sign(s_beta)
elif mode == 'sat':
# 饱和函数
sat_a = np.clip(s_alpha / phi, -1, 1)
sat_b = np.clip(s_beta / phi, -1, 1)
return sat_a, sat_b
else:
raise ValueError("Unknown switching function mode")
# ---------- 运行SMO仿真 ----------
def run_smo(surface_mode, switch_mode):
i_alpha_hat = np.zeros(n_steps)
i_beta_hat = np.zeros(n_steps)
e_alpha_hat = np.zeros(n_steps)
e_beta_hat = np.zeros(n_steps)
for k in range(1, n_steps):
# 电流观测误差
err_a = i_alpha_true[k-1] - i_alpha_hat[k-1]
err_b = i_beta_true[k-1] - i_beta_hat[k-1]
# 滑模面
s_a, s_b = sliding_surface(err_a, err_b, surface_mode)
# 切换函数
u_a, u_b = switching_function(s_a, s_b, switch_mode)
# 反电动势观测值(滑模输出经低通滤波)
e_alpha_hat[k] = e_alpha_hat[k-1] + (k_smo * u_a - e_alpha_hat[k-1]) * 100 * dt
e_beta_hat[k] = e_beta_hat[k-1] + (k_smo * u_b - e_beta_hat[k-1]) * 100 * dt
# 电流观测器更新
di_hat_a = (e_alpha_hat[k] - Rs * i_alpha_hat[k-1] + k_smo * u_a) / Ld * dt
di_hat_b = (e_beta_hat[k] - Rs * i_beta_hat[k-1] + k_smo * u_b) / Lq * dt
i_alpha_hat[k] = i_alpha_hat[k-1] + di_hat_a
i_beta_hat[k] = i_beta_hat[k-1] + di_hat_b
return e_alpha_hat, e_beta_hat, i_alpha_hat, i_beta_hat
# ---------- 运行四种组合 ----------
combinations = [
('linear', 'sign', '线性滑模面 + 符号函数'),
('linear', 'sat', '线性滑模面 + 饱和函数'),
('nonlinear', 'sign', '非线性滑模面 + 符号函数'),
('nonlinear', 'sat', '非线性滑模面 + 饱和函数')
]
results = {}
for surf, switch, name in combinations:
e_a, e_b, i_a, i_b = run_smo(surf, switch)
results[name] = (e_a, e_b)
# ---------- 绘图对比 ----------
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
fig.suptitle('SMO不同滑模面与切换函数性能对比')
# 真实反电动势(用于参考)
theta_series = omega_e * t
e_alpha_real = -Ke * omega_e * np.sin(theta_series)
e_beta_real = Ke * omega_e * np.cos(theta_series)
for idx, (name, (e_a, e_b)) in enumerate(results.items()):
ax = axes[idx // 2, idx % 2]
# 仅显示稳态部分(后50%)
start_idx = n_steps // 2
ax.plot(t[start_idx:], e_alpha_real[start_idx:], 'k--', label='真实 e_α', linewidth=1)
ax.plot(t[start_idx:], e_a[start_idx:], 'r-', label='观测 e_α', alpha=0.7)
ax.plot(t[start_idx:], e_b[start_idx:], 'b-', label='观测 e_β', alpha=0.7)
ax.set_title(name)
ax.set_xlabel('时间 (s)')
ax.set_ylabel('反电动势 (V)')
ax.legend(loc='upper right', fontsize=8)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# ---------- 量化指标计算 ----------
print("\n===== 性能对比(稳态段) =====")
start_idx = n_steps // 2
for name, (e_a, e_b) in results.items():
# 计算观测误差的RMS
err_a = e_a[start_idx:] - e_alpha_real[start_idx:]
err_b = e_b[start_idx:] - e_beta_real[start_idx:]
rms_a = np.sqrt(np.mean(err_a**2))
rms_b = np.sqrt(np.mean(err_b**2))
# 抖振幅度(相邻采样点差值的RMS)
chattering_a = np.sqrt(np.mean(np.diff(e_a[start_idx:])**2))
print(f"{name}:")
print(f" e_α RMS误差: {rms_a:.4f} V")
print(f" e_β RMS误差: {rms_b:.4f} V")
print(f" e_α 抖振幅度: {chattering_a:.4f} V/step")
运行与验证
环境依赖:Python 3.8+,需安装 numpy 和 matplotlib。
运行方式:将上述代码保存为 smo_comparison.py,在终端执行 python smo_comparison.py。
验证方法:
- 程序运行后应弹出包含4个子图的对比图,每个子图显示真实反电动势(黑色虚线)与观测值(红色/蓝色实线)的跟踪情况。
- 观察稳态段(后50%时间):符号函数组合(子图1和3)的观测波形应呈现明显的高频抖振;饱和函数组合(子图2和4)的波形更平滑,但可能存在轻微相位滞后。
- 控制台输出的量化指标中,饱和函数组合的抖振幅度应显著小于符号函数组合(通常降低50%以上);非线性滑模面的RMS误差应略小于线性滑模面。
通过标准:四种组合均能稳定跟踪真实反电动势波形(无发散),且饱和函数组合的抖振幅度明显低于符号函数组合,非线性滑模面组合的RMS误差不劣于线性滑模面组合,即证明不同设计对观测性能的影响得到正确体现。