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。

验证方法:

  1. 程序运行后应弹出包含4个子图的对比图,每个子图显示真实反电动势(黑色虚线)与观测值(红色/蓝色实线)的跟踪情况。
  2. 观察稳态段(后50%时间):符号函数组合(子图1和3)的观测波形应呈现明显的高频抖振;饱和函数组合(子图2和4)的波形更平滑,但可能存在轻微相位滞后。
  3. 控制台输出的量化指标中,饱和函数组合的抖振幅度应显著小于符号函数组合(通常降低50%以上);非线性滑模面的RMS误差应略小于线性滑模面。

通过标准:四种组合均能稳定跟踪真实反电动势波形(无发散),且饱和函数组合的抖振幅度明显低于符号函数组合,非线性滑模面组合的RMS误差不劣于线性滑模面组合,即证明不同设计对观测性能的影响得到正确体现。