
原创例程,有中文注释。可直接运行、得到结果
文章目录
程序简介
程序基于MATLAB搭建永磁同步电机(Permanent Magnet Synchronous Motor,PMSM)仿真模型,采用自适应无迹卡尔曼滤波(Adaptive Unscented Kalman Filter,AUKF),实现电流测量噪声协方差的在线估计,以及机械转速、转子电角度和电流状态的联合观测。
传统UKF通常采用固定的测量噪声协方差。当电流传感器的实际噪声水平发生变化时,预设噪声参数可能与真实测量环境不匹配,从而影响状态估计结果。
针对这一问题,程序引入基于新息协方差匹配的自适应机制,根据滤波新息的统计信息在线调整测量噪声协方差,并通过固定噪声参数UKF与自适应UKF的对比,分析噪声变化条件下的状态估计性能。
算法与仿真设置
程序采用四维状态模型,包括d轴电流、q轴电流、机械角速度和转子电角度。
UKF通过Sigma点无迹变换完成非线性状态预测与电流量测更新,无需显式计算系统状态方程的雅可比矩阵。
为研究测量噪声自适应机制的作用,程序设置两组滤波方案:
- 标准UKF: 测量噪声协方差R保持固定,按照预设噪声参数执行状态预测与量测更新。
- 自适应UKF: 基于新息协方差匹配方法,采用指数加权方式统计新息信息,并扣除预测量测协方差,在线估计测量噪声协方差R。
程序对估计的R设置上下界,避免噪声参数出现过小或过大的情况。每次计算得到的新协方差用于后续量测更新。
仿真采用磁场定向控制(FOC)生成电机运行数据,总时长为1.2秒,采样周期为0.1 ms,并设置分阶段变化的电流测量噪声:
- 0~0.40秒: 测量噪声标准差为0.04 A。
- 0.40~0.80秒: 测量噪声标准差增大至0.18 A。
- 0.80~1.20秒: 测量噪声标准差降低至0.07 A。
两组UKF使用相同的电机运行数据和带噪电流量测,以便比较不同滤波策略的估计结果。
结果分析
程序主要输出以下结果:
- 测量噪声在线估计: 对比真实电流噪声标准差与自适应UKF估计的α、β轴测量噪声标准差,分析噪声变化的跟踪效果。
- 固定UKF与自适应UKF对比: 展示两种滤波方案的机械转速估计误差,重点分析0.40~0.80秒噪声增大阶段的估计表现。
- 转速与电角度观测: 对比机械转速和转子电角度的真实值与估计值,观察状态跟踪情况。
- 状态估计误差: 绘制机械转速和转子电角度估计误差曲线,计算对应的均方根误差(RMSE)。
- 电流滤波结果: 对比α、β轴真实电流、带噪电流和UKF估计电流,分析滤波效果。
- 滤波性能诊断: 展示实际施加的α、β轴电压以及归一化新息平方(NIS),并输出误差改善率、协方差正定性等指标。
程序特点与适用方向
本程序采用基础MATLAB函数实现,包含完整的PMSM数学模型、FOC控制、Sigma点生成、UKF状态预测与量测更新、测量噪声协方差自适应及结果可视化过程。
与标准UKF相比,本例在保留Sigma点非线性状态估计框架的基础上,引入新息协方差匹配机制,使滤波器能够根据测量数据调整噪声参数。
电机参数、测量噪声水平、噪声变化时刻、UKF协方差和自适应更新参数等均可自行修改,便于研究不同测量噪声条件下的滤波性能。
运行结果
测量噪声自适应:

状态估计误差:

电压与新息诊断:

电流观测与估计:

转速与角度观测:

命令行输出:

MATLAB源代码
部分代码展示:
matlab
% 电流噪声在线适应:独立MATLAB例程
% 2026-10-19/Ver1,作者:matlabfilter,V同号,可获取代码定制、讲解等
% 只使用基础MATLAB。参数为普通标量,信号为数值数组,不使用结构体。
% 点击运行即可;末尾含全部局部函数。Figure无水印,配套PNG由维护工具导出。
clear; clc; close all;
rng(0);
%% 共用教学参数与单位:不将本例解释为Word中15 kW电机的实机验证
Rs=0.45; Ld=3e-3; Lq=3.6e-3; psi_f=0.075;
pole_pairs=4; J=2e-3; B=5e-4;
Ts=1e-4; simulation_time=1.2;
dc_voltage=120; voltage_limit=dc_voltage/sqrt(3); current_limit=10;
Kp_speed=0.25; Ki_speed=4.0;
current_bandwidth=1200;
Kp_d=Ld*current_bandwidth; Kp_q=Lq*current_bandwidth;
Ki_d=Rs*current_bandwidth; Ki_q=Rs*current_bandwidth;
time=0:Ts:simulation_time; sample_count=numel(time);
Kt=1.5*pole_pairs*psi_f; Kr=1.5*pole_pairs*(Ld-Lq);
% 维护用汇总也是数值向量;各指标仍以独立、有意义的变量保留。
speed_rmse=NaN; angle_rmse_deg=NaN; load_rmse=NaN;
parameter_relative_rmse_pct=NaN; secondary_parameter_rmse_pct=NaN;
improvement_pct=NaN; current_rmse=NaN; peak_speed_error=NaN;
gap_speed_rmse=NaN; recovery_speed_rmse=NaN;
final_parameter=NaN; final_secondary_parameter=NaN;
disturbance_speed_peak=NaN; control_current_peak=NaN; takeover_speed_peak=NaN;
recovery_time=NaN; covariance_min=Inf; covariance_chol_failures=0;
ut_error=0; state_is_finite=1;
%% 编码器FOC台架:仅负责生成实际电压、电流和物理一致的真值
speed_reference=80+20*(1+tanh((time-0.25)/0.035))/2 ...
-10*(1+tanh((time-0.85)/0.035))/2;
load_true=0.35*ones(1,sample_count);
state_true=zeros(4,sample_count); voltage_ab=zeros(2,sample_count);
plant=[0;(0.35+B*80)/Kt;80;0.30]; state_true(:,1)=plant;
controller_integrals=zeros(3,1); iq_reference=zeros(1,sample_count);
voltage_saturated=false(1,sample_count);
iq_bias=(0.35+B*80)/Kt;
for k=2:sample_count
feedback_ab=current_measurement(plant);
[uab,controller_integrals,iq_reference(k-1),voltage_saturated(k-1)]=foc_controller( ...
feedback_ab,plant(4),plant(3),speed_reference(k-1),controller_integrals,Ts, ...
Rs,Ld,Lq,psi_f,pole_pairs,voltage_limit,current_limit, ...
Kp_speed,Ki_speed,Kp_d,Ki_d,Kp_q,Ki_q,iq_bias);
voltage_ab(:,k-1)=uab;
plant=motor_truth_step(plant,uab,Ts,Rs,Ld,Lq,psi_f,pole_pairs,J,B,load_true(k-1));
state_true(:,k)=plant;
end
voltage_ab(:,end)=voltage_ab(:,end-1);
iq_reference(end)=iq_reference(end-1);
current_ab_true=[cos(state_true(4,:)).*state_true(1,:)-sin(state_true(4,:)).*state_true(2,:); ...
sin(state_true(4,:)).*state_true(1,:)+cos(state_true(4,:)).*state_true(2,:)];
noise_std=0.04*ones(2,sample_count);
noise_std(:,time>=0.40 & time<0.80)=0.18; noise_std(:,time>=0.80)=0.07;
current_ab_meas=current_ab_true+noise_std.*randn(2,sample_count);
measurement_valid=true(1,sample_count);
current_ab_meas(:,~measurement_valid)=NaN;
%% 状态观测:不使用台架的真实转速、真实角度或未知负载
state_dimension=4;
ut_error=check_sigma_transform_ukf();
assert(abs(wrap_angle((-pi+0.01)-(pi-0.01))-0.02)<1e-12);
filter_count=2;
state_history=zeros(state_dimension,sample_count,filter_count);
nis_history=nan(filter_count,sample_count);
R_history=zeros(2,sample_count,filter_count);
weight_history=ones(2,sample_count);
innovation_history=nan(2,sample_count,filter_count);
sigma_speed_history=zeros(filter_count,sample_count);
for filter_index=1:filter_count
x=[0.15;(0.35+B*80)/Kt-0.1;85;0.42];
P=diag([0.3^2,0.3^2,12^2,0.18^2]);
Q=diag([2e-6,2e-6,2e-3,2e-8]);
if state_dimension==5
x=[x;0.20]; P=blkdiag(P,0.25^2); Q=blkdiag(Q,3e-5);
end
R=0.04^2*eye(2); innovation_covariance=R;
state_history(:,1,filter_index)=x;
R_history(:,1,filter_index)=diag(R);
sigma_speed_history(filter_index,1)=sqrt(P(3,3));
for k=2:sample_count
[xp,Pp]=motor_predict_ukf(x,P,Q,voltage_ab(:,k-1),Ts,Rs,Ld,Lq,psi_f,pole_pairs,J,B,0.35);
if measurement_valid(k)
[predicted,Czz,Pxz]=current_moments_ukf(xp,Pp);
residual=current_ab_meas(:,k)-predicted;
effective_R=R;
[x,P,residual,nis_value]=state_update_ukf(xp,Pp,current_ab_meas(:,k),effective_R);
innovation_history(:,k,filter_index)=residual;
nis_history(filter_index,k)=nis_value;
if filter_index==2
innovation_covariance=0.995*innovation_covariance+0.005*(residual*residual');
if k>300
R_target=diag(innovation_covariance-Czz);
R_target=max(0.01^2,min(0.5^2,R_target)); R=diag(R_target);
end
assert(all(diag(R)>=0.01^2) && all(diag(R)<=0.5^2),'R越界');
end
else
x=xp; x(4)=wrap_angle(x(4)); P=(Pp+Pp')/2;
end
[~,chol_flag]=chol(P);
covariance_chol_failures=covariance_chol_failures+(chol_flag~=0);
covariance_min=min(covariance_min,min(eig(P)));
assert(chol_flag==0 && all(isfinite(x)),'状态或协方差异常');
state_history(:,k,filter_index)=x;
R_history(:,k,filter_index)=diag(R);
sigma_speed_history(filter_index,k)=sqrt(P(3,3));
end
end
state_est=state_history(:,:,end);
current_est=[cos(state_est(4,:)).*state_est(1,:)-sin(state_est(4,:)).*state_est(2,:); ...
sin(state_est(4,:)).*state_est(1,:)+cos(state_est(4,:)).*state_est(2,:)];
innovation=innovation_history(:,:,end); nis_values=nis_history(end,:);
speed_true=state_true(3,:); speed_est=state_est(3,:);
angle_true=state_true(4,:); angle_est=state_est(4,:);
speed_error=speed_est-speed_true; angle_error=wrap_angle(angle_est-angle_true);
evaluation=time>=0.24;
speed_rmse=sqrt(mean(speed_error(evaluation).^2));
angle_rmse_deg=sqrt(mean(angle_error(evaluation).^2))*180/pi;
peak_speed_error=max(abs(speed_error(evaluation)));
valid_evaluation=evaluation & measurement_valid;
current_rmse=sqrt(mean((current_est(:,valid_evaluation)-current_ab_true(:,valid_evaluation)).^2,'all'));
control_current_peak=max(abs(state_true(2,:)));
event=time>=0.40 & time<0.80;
reference_speed_error=state_history(3,:,1)-speed_true;
reference_rmse=sqrt(mean(reference_speed_error(event).^2));
adaptive_rmse=sqrt(mean(speed_error(event).^2));
improvement_pct=100*(reference_rmse-adaptive_rmse)/max(reference_rmse,eps);
%% 绘图
完整代码:
如需帮助,或有滤波相关的MATLAB代码定制需求,可从个人主页左侧联系我