扰动补偿自触发MPC控制器设计【附代码】
✨ 长期致力于永磁同步电机、模型预测控制、扰动补偿、死区时间优化、自触发控制研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。
✅ 专业定制毕设、代码
✅如需沟通交流,点击《获取方式》
(1)基于预测误差驱动的扰动补偿MPC:
针对永磁同步电机参数摄动和外部负载扰动,提出一种扰动补偿模型预测控制算法。在每个控制周期,测量八个候选电压矢量对应的预测误差,通过卡尔曼滤波器对扰动进行在线估计。扰动观测器的状态方程为d(k+1)=d(k)+w(k),输出方程为y(k)=Cx(k)+d(k)+v(k)。更新后的扰动值直接加在预测模型的输出端,修正下一时刻的预测。控制器的目标函数为J = Σ||y_ref-y_pred||^2 + λ||Δu||^2,约束电压矢量幅值不超过直流母线电压。在MATLAB/Simulink中搭建PMSM双闭环控制系统,电机参数:Rs=0.2Ω,Ld=Lq=4.5mH,磁链0.12Wb,转动惯量0.001kg·m^2。在额定转速1500rpm下突加5N·m负载,传统MPC的转速跌落120rpm,恢复时间45ms;扰动补偿MPC的转速跌落35rpm,恢复时间12ms。稳态误差从±10rpm降至±2rpm。
(2)死区时间优化补偿的MPC策略:
针对逆变器死区时间引起的电压畸变和电流谐波,提出死区时间优化补偿方法。分析死区效应,对于每个候选电压矢量,计算出对应的死区时间电压矢量(幅值正比于死区时间和电流方向)。将候选电压矢量与死区电压矢量通过线性组合形成新的有限控制集,组合系数为λ(0≤λ≤1)。控制器同时优化原始矢量和λ,选择使目标函数最小的组合。利用电流相角快速判断该死区电压是否有助于降低谐波,若是则通过梯度下降法优化死区时间,否则λ取0。在Links-RT半实物平台上进行实验,开关频率10kHz,死区时间2μs。采用死区补偿后,电流总谐波畸变率从6.8%降至3.2%,低速(100rpm)时的转矩脉动从0.12N·m降至0.05N·m。在额定工况下,效率从89%提升到91.5%。
(3)双模自触发MPC降低计算与通信负荷:
针对一般非线性约束系统,提出双模自触发MPC。离线预先计算一个线性状态反馈控制器作为辅助模式,当系统状态进入终端不变集时切换到辅助模式。在线求解最优控制问题获得开环控制轨迹,然后通过自触发机制计算下一个触发时刻,即预测状态在开环控制下保持可行域内的最大时间步长。触发时刻更新算法为t_{k+1}=t_k+min(N, floor(T_pred)),其中T_pred由状态约束和输入约束决定。在PMSM控制中应用该策略,将计算负担降低约60%。对于自主移动机器人轨迹跟踪,常规MPC每个控制周期(50ms)都需要求解QP问题,而自触发MPC平均每120ms求解一次,跟踪误差仅增加5%。在仿真中对比,自触发MPC的CPU占用率从78%降至31%,同时稳定性得到保证,终端代价函数满足Lyapunov下降条件。
import numpy as np from scipy.linalg import solve_discrete_are import cvxpy as cp class DisturbanceObserver: def __init__(self, A, B, C, Q_obs, R_obs): self.A = A self.B = B self.C = C self.P = np.eye(A.shape[0]) * 10 self.K = np.zeros((A.shape[0], C.shape[0])) def update(self, y, u, x_est): # 卡尔曼估计扰动 x_pred = self.A @ x_est + self.B @ u P_pred = self.A @ self.P @ self.A.T + Q_obs S = self.C @ P_pred @ self.C.T + R_obs self.K = P_pred @ self.C.T @ np.linalg.inv(S) x_est = x_pred + self.K @ (y - self.C @ x_pred) self.P = (np.eye(len(self.P)) - self.K @ self.C) @ P_pred d_est = x_est[-1] # 假设扰动为状态扩展 return d_est, x_est class DeadtimeCompensatedMPC: def __init__(self, dt, Ts_dead=2e-6, Vdc=300): self.dt = dt self.Ts = Ts_dead self.Vdc = Vdc def deadtime_voltage(self, ia, ib, ic): # 根据电流极性计算死区电压矢量 sign_a = 1 if ia>0 else -1 sign_b = 1 if ib>0 else -1 sign_c = 1 if ic>0 else -1 V_dead = self.Vdc * self.Ts / self.dt * np.array([sign_a, sign_b, sign_c]) * 0.01 return V_dead def optimize(self, x0, ref, candidates): # 候选电压矢量与死区组合 best_u = None best_cost = np.inf for u_orig in candidates: for lam in np.linspace(0, 1, 5): u_comb = (1-lam) * u_orig + lam * self.deadtime_voltage(x0[3], x0[4], x0[5]) # 预测 cost 计算 cost = np.linalg.norm(ref - self.predict(x0, u_comb)) if cost < best_cost: best_cost = cost best_u = u_comb return best_u class SelfTriggeredMPC: def __init__(self, A, B, Q, R, N_horizon=10): self.A = A self.B = B self.Q = Q self.R = R self.N = N_horizon # 求解LQR terminal cost P = solve_discrete_are(A, B, Q, R) self.P = P self.K_lqr = -np.linalg.inv(R + B.T @ P @ B) @ B.T @ P @ A def solve_ocp(self, x0): nx = self.A.shape[0] nu = self.B.shape[1] x = cp.Variable((nx, self.N+1)) u = cp.Variable((nu, self.N)) cost = 0 constraints = [x[:,0] == x0] for k in range(self.N): cost += cp.quad_form(x[:,k], self.Q) + cp.quad_form(u[:,k], self.R) constraints += [x[:,k+1] == self.A @ x[:,k] + self.B @ u[:,k]] constraints += [cp.norm(u[:,k], 'inf') <= 1.0] cost += cp.quad_form(x[:,self.N], self.P) prob = cp.Problem(cp.Minimize(cost), constraints) prob.solve(solver=cp.OSQP) return u.value, x.value def compute_trigger_time(self, x0, u_seq): # 确定在开环控制下状态满足约束的最大步数 x = x0 for i, u in enumerate(u_seq.T): x = self.A @ x + self.B @ u if np.any(np.abs(x) > 1.5): # 超出安全集 return i+1 return self.N def run(self, x0): u_seq, x_seq = self.solve_ocp(x0) T_hold = self.compute_trigger_time(x0, u_seq) return u_seq[:,0], T_hold