
完整代码,附下载链接。包运行成功
文章目录
面向四维PMSM转速与电角度估计,实现标准扩展卡尔曼滤波(EKF),包含仿真数据生成、滤波递推、结果可视化与误差评价。从静止αβ轴电流观测中同时估计电流、机械转速和转子电角度。采用标准EKF,展示非零转速下的初始误差收敛和变速跟踪。
程序简介
算法原理
采用表贴式永磁同步电机模型,满足 Ld=Lq=p.L。通过已知αβ电压驱动机电状态预测,以αβ电流为量测修正电流、机械转速和电角度。 扩展卡尔曼滤波利用离散模型雅可比近似传播局部状态误差。 仿真从非零转速及明确初始估计误差开始;接近零速时反电动势减弱,电流对转子角度和转速的可观测性下降,不能据此例程推断零速启动能力。
实现流程
- 设置参数、固定随机种子,生成电压、真实电机状态和带噪电流。
- 初始化带误差的估计状态,核对解析雅可比。
- 逐步执行模型预测和当前案例的量测更新。
- 检查有限值与协方差正定性,统计指标并输出Figure。
输出说明
result.time为1×N时间;truth、estimate、error为状态数×N矩阵;observation和voltage为2×N矩阵。result.stateNames明确状态顺序:[i_alpha, i_beta, omega_m, theta_e],负载为已知常数。
result.metrics保存统计指标;result.diagnostic保存新息、NIS及案例专属诊断。初始样本尚未量测更新,相关新息以NaN表示。
电压第k列驱动t(k),t(k+1)区间,电流第k列对应t(k);最后一列电压复制前一列,仅为输出长度一致,不用于额外传播。
各图窗的主题见"运行结果"。命令行仅输出该节列出的指标,其余误差和数值诊断从 result.metrics 与 result.diagnostic 读取。 转速和电角度主指标统计后80%仿真区间;电角度误差先按圆周环绕处理,再计算RMSE。
运行结果
转速与位置估计图:对比真实与估计机械转速,并放大展示电角度局部曲线;机械转速以r/min显示,电角度以rad显示。

估计误差图:显示机械转速与环绕处理后的电角度误差,用于观察收敛过程和变速响应。

电流观测与估计图:分别展示α、β电流的真值、带噪观测和滤波估计,观察电流平滑与跟踪情况。

电压与新息诊断图:展示αβ轴电压输入及归一化新息平方,用于核查激励与观测残差。

命令行输出:输出算法名称、随机种子、转速RMSE及其额定转速百分比、电角度RMSE。

其他指标保存在MATLAB的工作区(workspace),可自行查看

MATLAB源代码
部分代码如下:
matlab
% PMSM标准EKF转速与位置估计:独立MATLAB例程
% 2026-09-20/Ver1,作者:matlabfilter,V同号,可获取代码定制、讲解等
% 直接点击"运行"。只依赖基础 MATLAB;本文件末尾包含全部局部函数。
% 验证可选接口:demoOptions.seed、demoOptions.makePlots。
% 不设置 demoOptions 时使用固定种子0并绘图。主输出为 result。
if ~exist('demoOptions','var'), demoOptions = struct; end
if ~isfield(demoOptions,'seed'), demoOptions.seed = 0; end
if ~isfield(demoOptions,'makePlots'), demoOptions.makePlots = true; end
rng(demoOptions.seed, 'twister');
if demoOptions.makePlots, close all; end
%% 集中参数:SI单位;wm为机械角速度,theta为电角度
p.Rs = 0.45; p.L = 3e-3; p.psi = 0.075;
p.pairs = 4; p.J = 2e-3; p.B = 5e-4;
p.dt = 1e-4; p.duration = 0.65; p.ratedSpeed = 150;
t = 0:p.dt:p.duration; count = numel(t);
%% 真值与观测生成(理想有编码器驱动台架,独立于待验证估计器)
% 台架的理想电流/速度闭环只用于生成物理一致的电压、电流数据。
% 估计器不使用台架的真实角度、转速、速度给定或未知负载。
% 本例验证无位置传感器"估计",并不声称实现无传感器闭环启动。
nx = 4;
plant = [0; 0; 80; 0.3];
truth = zeros(nx,count); voltage = zeros(2,count);
currentObs = zeros(2,count); loadTrue = zeros(1,count);
noiseStd = 0.04*ones(2,count); outlierMask = false(1,count);
speedReference = 80 + 25*(1+tanh((t-0.16)/0.035))/2 ...
- 15*(1+tanh((t-0.44)/0.035))/2;
loadTrue(:) = 0.35;
truth(1:4,1) = plant;
if nx==5, truth(5,:) = loadTrue; end
currentObs(:,1) = plant(1:2) + noiseStd(:,1).*randn(2,1);
speedIntegral = 0;
for k = 2:count
% 真实台架:有编码器FOC等效电压源;电压限幅为±60 V。
wm = plant(3); angle = plant(4);
rot = [cos(angle),sin(angle);-sin(angle),cos(angle)];
idq = rot*plant(1:2);
speedError = speedReference(k-1)-wm;
speedIntegral = max(-8,min(8,speedIntegral+p.dt*speedError));
iqRef = max(-10,min(10,0.28*speedError+3.0*speedIntegral+0.8));
udq = [p.Rs*idq(1)-p.pairs*wm*p.L*idq(2); ...
p.Rs*idq(2)+p.pairs*wm*(p.L*idq(1)+p.psi)] ...
+ 2.8*([0;iqRef]-idq);
u = max(-60,min(60,rot'*udq));
voltage(:,k-1) = u;
% 真值采用4个RK4子步,未知负载只传给真实电机。
for sub = 1:4
h = p.dt/4;
a = motorODE(plant,u,p,loadTrue(k-1));
b = motorODE(plant+h*a/2,u,p,loadTrue(k-1));
c = motorODE(plant+h*b/2,u,p,loadTrue(k-1));
d = motorODE(plant+h*c,u,p,loadTrue(k-1));
plant = plant+h*(a+2*b+2*c+d)/6;
end
plant(4) = wrapAngle(plant(4));
truth(1:4,k) = plant;
currentObs(:,k) = plant(1:2)+noiseStd(:,k).*randn(2,1);
end
voltage(:,end) = voltage(:,end-1);
available = true(1,count);
currentObs(:,~available) = NaN;
%% EKF初始化(故意设置初始误差,不从真值数组初始化)
x = [0.15;-0.12;87;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 nx==5
x = [x;0.20]; P = blkdiag(P,0.25^2); Q = blkdiag(Q,2e-5);
end
R = 0.04^2*eye(2); H = [eye(2),zeros(2,nx-2)];
estimate = zeros(nx,count); estimate(:,1) = x;
innovation = nan(2,count); nis = nan(1,count);
diagnostic = ones(2,count); rStdEstimate = 0.04*ones(2,count);
minEigenvalue = zeros(1,count); minEigenvalue(1) = min(eig(P));
symmetryError = zeros(1,count); sqrtError = zeros(1,count);
% 对离散预测函数作中心差分,核对链式解析雅可比。
完整代码的下载链接:
https://download.csdn.net/download/callmeup/93496932
如需帮助,或有滤波相关的MATLAB代码定制需求,可从个人主页左侧联系我