【MATLAB例程,PMSM19】永磁同步电机(PMSM)基于多速率无迹卡尔曼滤波(UKF)的转速与转子位置估计。测量缺失、状态预测与恢复性能分析

原创代码,请勿翻卖

文章目录

程序简介

本程序基于MATLAB搭建永磁同步电机(Permanent Magnet Synchronous Motor,PMSM)仿真模型,采用多速率无迹卡尔曼滤波(Unscented Kalman Filter,UKF),实现不同电流测量频率及短时测量缺失条件下的电机状态估计。

在实际电机系统中,状态预测频率与传感器测量频率可能并不一致,传感器数据还可能受到采集异常或通信中断等因素影响,出现短时缺失。

针对这一问题,程序采用状态预测与量测更新分离的UKF递推方式,在测量不可用时依靠电机模型继续预测状态,在有效测量恢复后重新执行滤波更新,以研究多速率与缺测工况对状态估计精度的影响。

算法与仿真设置

程序采用四维状态模型,包括d轴电流、q轴电流、机械角速度和转子电角度。

UKF通过Sigma点无迹变换完成非线性状态预测及电流量测更新,无需显式计算系统模型的雅可比矩阵。

仿真主要设置以下三种工况:

  1. 正常采样阶段(0~0.35秒): 状态预测与电流量测更新频率均为10 kHz。
  2. 低频量测阶段(0.35秒以后): 状态预测保持10 kHz,电流量测更新频率降低至2 kHz。
  3. 连续缺测阶段(0.60~0.615秒): 设置15 ms连续测量中断,期间仅进行状态预测和协方差传播,待测量恢复后继续执行UKF量测更新。

仿真总时长为1.2秒,采样周期为0.1 ms,电流测量噪声标准差为0.04 A,并设置电机转速给定先上升、后下降的运行工况。

程序还针对转子电角度的周期性进行角度环绕处理,并对UKF协方差正定性及无迹变换计算结果进行数值检查。

结果分析

程序主要输出以下结果:

  1. 测量有效性变化: 展示电流测量从正常采样到低频更新,以及连续缺测和恢复的全过程。
  2. 缺测与恢复误差: 绘制连续测量中断前后的机械转速估计误差,分析模型预测和测量恢复对估计结果的影响。
  3. 估计不确定度: 展示转速估计标准差,观察缺测期间及量测恢复后的协方差变化情况。
  4. 转速与电角度估计: 对比机械转速、转子电角度真实值与UKF估计值,分析不同工况下的状态跟踪性能。
  5. 电流滤波结果: 展示α、β轴真实电流、带噪测量电流及UKF估计电流。
  6. 性能评价: 输出机械转速和转子电角度均方根误差(RMSE),以及连续缺测阶段和恢复阶段的转速RMSE,并通过归一化新息平方(NIS)辅助评价滤波性能。

程序特点与适用方向

本程序采用基础MATLAB函数实现,包含完整的PMSM数学模型、磁场定向控制(FOC)、Sigma点无迹变换、多速率UKF递推、测量缺失处理及结果可视化功能。

与固定频率UKF不同,本例将状态预测和测量更新分开执行,在缺测期间保持状态连续传播,测量恢复后重新利用观测信息修正估计结果。

电机参数、预测频率、测量更新频率、连续缺测时长、测量噪声及UKF协方差等均可自行调整。

运行结果

状态估计误差:

电压与新息诊断:

电流观测与估计:

缺测与恢复诊断:

转速与角度观测:

命令行输出:

MATLAB源代码

部分代码如下:

matlab 复制代码
% 多速率与缺测观测:独立MATLAB例程
% 2026-10-11/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);

current_ab_meas=current_ab_true+noise_std.*randn(2,sample_count);

measurement_valid=true(1,sample_count);
slow_region=time>=0.35;
measurement_valid(slow_region)=mod(find(slow_region)-1,5)==0;
gap_region=time>=0.60 & time<0.615; measurement_valid(gap_region)=false;
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=1;
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;
            
        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,:)));
gap_speed_rmse=sqrt(mean(speed_error(gap_region).^2));
recovery_region=time>=0.615 & time<0.645;
recovery_speed_rmse=sqrt(mean(speed_error(recovery_region).^2));
assert(all(isnan(nis_values(~measurement_valid))),'缺测时不得做测量更新');
assert(all(isnan(current_ab_meas(:,~measurement_valid)),'all'),'缺测应保存为NaN');

%% 绘图

完整代码直接打开后,运行即可:https://download.csdn.net/download/callmeup/93722089

如需帮助,或有滤波相关的MATLAB代码定制需求,可从个人主页左侧联系我

相关推荐
喵了几个咪17 分钟前
GoWind Flow 拆解:一个 Go 工作流引擎与它的双模式设计器
开发语言·人工智能·后端·golang
꧁细听勿语情꧂43 分钟前
二叉树余题,排序、直接插入排序、希尔排序
c语言·开发语言·数据结构·算法
是main不是漫1 小时前
【C++——类和对象(上)】筑基篇:以封装奠定面向对象之基
c语言·开发语言·c++
apcipot_rain5 小时前
C++转Java日记(06)
java·开发语言
SomeOtherTime12 小时前
Rust所有权(AI回答)
开发语言·后端·rust
Easyhood12 小时前
Android 开发入门实践(十四):Compose 副作用入门与四个常用 API
android·开发语言·kotlin·android jetpack·compose
白杨尚青13 小时前
C++进阶篇(六):map 和 set 的模拟实现——用红黑树封装 mymap/myset(迭代器 + operator[])
开发语言·c++·迭代器·stl·set·map·红黑树
饮水桶_T16 小时前
JAVA IO流笔记
开发语言·数据结构·算法
星夜离尘5617 小时前
MATLAB 离散数据分箱:半开区间、末端点与计数、加权和、平均
算法·matlab