高性能PMSM编码器PLL测速解决方案

📅 2026/7/6 13:32:25
高性能PMSM编码器PLL测速解决方案
引言在高性能永磁同步电机PMSM的矢量控制FOC系统中高质量的转子位置与转速反馈是实现精准磁场定向与电流解耦的基石。反馈信号的精度与平滑度直接决定了驱动系统的稳态转矩脉动、动态跟随响应以及电机在极低速下的运行表现。由于结构紧凑、性价比高且抗干扰能力强增量式编码器早已成为中小功率伺服系统中获取位置信息的主流方案。然而如何从离散的增量脉冲中提取高质量的速度信号一直是工程实践中的一大挑战。传统的速度解算主要依赖 M 法、T 法或 M/T 混合测速法。这类方案本质上都属于开环的离散脉冲差分计算M 法在低速时存在严重的量化误差T 法在高速时受限于高频时钟的分辨率M/T 法虽取长补短但由于其“位置求导”的底层逻辑未变输出的速度信号往往伴随着明显的阶梯状跳变与高频噪声。在工程应用中若直接对这种含噪信号使用常规的一阶低通滤波器LPF进行平滑又不可避免地会引入显著的相位滞后从而限制速度环的控制带宽并影响系统稳定性。为了打破“信号平滑度与相位延迟”之间的博弈基于锁相环PLL, Phase Locked Loop的闭环观测算法提供了一种更为优雅的解算思路。与传统的直接求导不同PLL 测速的核心在于“相位跟踪”。它将编码器解析出的实际机械角度作为参考基准通过鉴相环节计算出“观测角度”与“实际角度”的偏差再交由 PI 环路进行动态滤波与校正最终积分输出平滑的观测角度与观测转速。这种闭环机制不仅能大幅削弱离散脉冲引入的量化噪声还能实现对转速的零延迟或低延迟跟踪为伺服系统的稳定运行提供了极佳的反馈数据。PLL是什么在编码器测速中是如何工作的PLL全称 Phase Locked Loop中文叫锁相环。它的核心思想非常简单: 我自己内部生成一个“估计角度然后不断和真实测得的角度meas比较。如果估计角度落后了就提高估计速度如果估计角度超前了就降低估计速度。最终让估计角度锁住输入角度同时得到一个平滑的速度估计值。在电机测速场景里PLL可以理解为一个二阶位置跟踪观测器。编码器PLL测速的基本框图其中输入编码器测得的位置输出 1估计速度ω̂输出 2估计角度θ̂核心误差PI 控制器根据位置误差输出速度然后速度积分得到估计角度这就是典型的二阶 Type-II PLL。为什么 PLL 比传统 M 法 / 差分测速更平滑传统差分测速本质是这个公式的物理意义是每间隔 Ts​ 时间读取一次编码器角度用两次角度差值除以采样间隔得到这段时间内的平均角速度并把该平均值当作当前时刻瞬时转速。但这本身存在一个问题编码器的角度是量化的。假设编码器一圈有CPR个计数则一个脉冲对应的机械角度为差分测速时一个采样周期内多一个脉冲或少一个脉冲速度就会跳变举个例子编码器四倍频后 10000采样周期 100 us因此我们可以得到换算为RPM可以得到也就是说传统差分测速在这个条件下速度分辨率就是60 rpm 一级跳变。低速时会非常抖。而 PLL 不直接对位置做差分而是用一个二阶系统去“跟踪位置”速度是内部观测器状态输出因此能明显抑制量化噪声。增量式编码器 PLL 测速离散化数学模型编码器脉冲数到机械角度我们做如下假设符号含义第k次采样时的累计脉冲数编码器一圈计数数注意是四倍频后的计数采样周期电机极对数测得的机械角度测得的电角度我们首先计算机械角度由机械角度就可以得到电角度机械角速度和电角速度的关系为注意如果你是做速度环控制通常建议 PLL 直接工作在机械角度上输出机械角速度如果你是做无感 FOC 或电角度估计则可以让 PLL 工作在电角度上。连续域 PLL 数学模型由PLL结构图我们可以得到在连续域下的数学结构方程其中位置误差单位 rad积分器状态单位 rad/s估计角速度单位 rad/s估计角度单位 rad比例增益积分增益在实际的工程中由于无法在mcu中实现这个连续域的数学模型结构因此我们需要将其进行离散化。模型离散化公式采用前向欧拉离散化固定采样周期为:第一步位置测量: 通过读取到的计数值去计算当前实际的位置信息第二步位置误差计算实际位置与估算位置的差值如果使用累计脉冲数即多圈连续角度如果角度是0 -周期量则需要做角度环绕其中表示将角度限制在。第三步PI 积分状态更新第四步估计速度输出第五步估计角度更新这就是 MCU 中最常用的编码器 PLL 离散实现形式。PLL 的闭环传递函数连续域下PLL 开环传递函数为将s带入闭环角度跟踪传递函数因为而真实的速度所以速度估计相对于真实速度的闭环传递函数也是这个系统的特征方程为与标准二阶系统对比可以得到非常重要的整定关系其中PLL 自然频率单位 rad/s阻尼比一般取 0.707 - 1.0MATLAB / Simulink 仿真与频域分析Simulink仿真分析首先我们在Simulink中搭建测试环节测试环节搭建分为四个模块为了便于搭建每个模块均采样M-Funcation实现在进行仿真之前我们需要确定几个前置条件首先仿真模型我们设置为定步长模拟MCU采样执行周期其次我们设置CPR计数值为10000这个CPR的含义代表我们在使用增量式编码器在MCU中电机旋转一圈对应的计数值。这四个模块分别为参考速度生成模块电机角度加编码器量化模块传统差分测速模拟模块软件PLL锁相环测速模块误差分析模块接线来对每个模块进行实现和分析参考速度生成模块模块内部实现function [t, omega_true, rpm_true] MF_SpeedProfile() %#codegen % 速度轨迹发生器 % % 输出 % t : 当前仿真时间单位 s % omega_true : 真实机械角速度单位 rad/s % rpm_true : 真实机械转速单位 rpm Ts 1e-4; % 采样周期 PI 3.141592653589793; persistent k; if isempty(k) k uint32(0); end t double(k) * Ts; % 速度轨迹设计 % 0 ~ 0.05 s : 0 rpm % 0.05 ~ 0.15 s : 0 - 1000 rpm 斜坡 % 0.15 ~ 0.35 s : 1000 rpm 恒速 % 0.35 ~ 0.45 s : 1000 - 300 rpm 斜坡 % 0.45 ~ 0.60 s : 300 rpm 恒速 if t 0.05 rpm_true 0.0; elseif t 0.15 rpm_true 1000.0 * (t - 0.05) / 0.10; elseif t 0.35 rpm_true 1000.0; elseif t 0.45 rpm_true 1000.0 - 700.0 * (t - 0.35) / 0.10; else rpm_true 300.0; end omega_true rpm_true * 2.0 * PI / 60.0; k k 1; end这个模块比较简单通过这模块我们可以生成给定的参考速度与参考角速度。电机角度加编码器量化模块模块内部实现function [theta_true, theta_meas, count, q_noise] MF_EncoderModel(omega_true) %#codegen % 电机真实角度 增量式编码器量化模型 % % 输入 % omega_true : 真实机械角速度rad/s % % 输出 % theta_true : 连续真实机械角度rad % theta_meas : 编码器量化后的机械角度rad % count : 编码器累计计数值 % q_noise : 位置量化误差rad Ts 1e-4; PI 3.141592653589793; CPR 10000.0; % 四倍频后每机械圈计数数 dtheta 2.0 * PI / CPR; % 一个 count 对应角度 persistent theta; if isempty(theta) theta 0.0; end % 真实角度积分 theta theta omega_true * Ts; theta_true theta; % 编码器量化 % 这里模拟增量式编码器只能输出整数 count count int32(round(theta_true / dtheta)); % 再由 count 还原成测量角度 theta_meas double(count) * dtheta; % 量化误差 q_noise theta_meas - theta_true; end这个模块模拟的是编码器量化其中传统差分测速模拟模块模块内部实现function [omega_diff, rpm_diff] MF_DiffSpeed(theta_meas) %#codegen % 传统差分测速 % % omega_diff[k] (theta_meas[k] - theta_meas[k-1]) / Ts Ts 1e-4; PI 3.141592653589793; persistent theta_last; persistent init_flag; if isempty(init_flag) init_flag false; theta_last 0.0; end if init_flag false omega_diff 0.0; rpm_diff 0.0; theta_last theta_meas; init_flag true; else omega_diff (theta_meas - theta_last) / Ts; rpm_diff omega_diff * 60.0 / (2.0 * PI); theta_last theta_meas; end end这个模块就是传统测速它的缺陷编码器输出位置是离散整数脉冲只要计数值变化1个count计算出的速度就会产生阶跃跳变转速波形毛刺严重。软件PLL锁相环测速模块模块内部实现function [omega_pll, rpm_pll, theta_hat, theta_hat_mod, err_pll, omega_i] MF_PLLSpeedObserver(count) %#codegen % 增量式编码器软件 PLL 速度观测器 % % 输入 % count : 编码器累计计数值 % % 输出 % omega_pll : PLL 估计机械角速度rad/s % rpm_pll : PLL 估计机械转速rpm % theta_hat : PLL 估计连续机械角度rad % theta_hat_mod : PLL 估计单圈机械角度0~2pi % err_pll : PLL 位置误差rad % omega_i : PLL 积分器状态rad/s Ts 1e-4; PI 3.141592653589793; TWO_PI 6.283185307179586; CPR 10000.0; dtheta TWO_PI / CPR; % PLL 参数 Kp 888.4420; Ki 394784.1760; omega_limit 1000.0; % rad/s integrator_limit 1000.0; % rad/s persistent theta_hat_state; persistent omega_i_state; persistent init_flag; if isempty(init_flag) init_flag false; theta_hat_state 0.0; omega_i_state 0.0; end % 由累计 count 得到测量角度 theta_meas double(count) * dtheta; % 初始化让 PLL 初始角度等于测量角度 if init_flag false theta_hat_state theta_meas; omega_i_state 0.0; init_flag true; end % 1. 计算位置误差 % 这里使用累计 count所以 theta_meas 是多圈连续角度 % 不需要 wrapToPi err_pll theta_meas - theta_hat_state; % 2. 积分器更新 % omega_i[k] omega_i[k-1] Ki * Ts * err[k] omega_i_state omega_i_state Ki * Ts * err_pll; % 积分器限幅 if omega_i_state integrator_limit omega_i_state integrator_limit; elseif omega_i_state -integrator_limit omega_i_state -integrator_limit; end % 3. PI 输出速度 % omega_pll[k] omega_i[k] Kp * err[k] omega_pll omega_i_state Kp * err_pll; % 速度限幅 if omega_pll omega_limit omega_pll omega_limit; elseif omega_pll -omega_limit omega_pll -omega_limit; end % 4. 速度积分得到估计角度 theta_hat_state theta_hat_state Ts * omega_pll; % 输出状态 theta_hat theta_hat_state; omega_i omega_i_state; % 单圈角度 0~2pi theta_hat_mod mod(theta_hat_state, TWO_PI); % rad/s - rpm rpm_pll omega_pll * 60.0 / TWO_PI; end这个模块对应的离散 PLL 公式是具体的实现方式可以这么理解将 MCU 读到的编码器脉冲计数值换算为实际机械角度。计算当前实测角度与上一拍 PLL 输出估计角度的差值作为环路相位跟踪误差。PI 调节器积分项离散迭代比例项 积分项合并输出 PLL 平滑后的估计角速度比例环节快速抑制瞬时角度误差积分环节消除稳态静差。角速度积分得到下一时刻估计角度完成闭环相位跟踪。误差分析模块模块内部实现function [err_diff_rpm, err_pll_rpm, rms_diff_rpm, rms_pll_rpm] MF_ErrorAnalysis(t, omega_true, omega_diff, omega_pll) %#codegen % 速度误差和稳态 RMS 分析 % % 这里在 0.20s ~ 0.34s 之间统计 RMS % 因为这段时间速度为 1000 rpm 恒速适合比较噪声 PI 3.141592653589793; radps_to_rpm 60.0 / (2.0 * PI); rpm_true omega_true * radps_to_rpm; rpm_diff omega_diff * radps_to_rpm; rpm_pll omega_pll * radps_to_rpm; err_diff_rpm rpm_diff - rpm_true; err_pll_rpm rpm_pll - rpm_true; persistent sum_diff_sq; persistent sum_pll_sq; persistent n; if isempty(n) sum_diff_sq 0.0; sum_pll_sq 0.0; n uint32(0); end % 只统计恒速区间 if t 0.20 t 0.34 sum_diff_sq sum_diff_sq err_diff_rpm * err_diff_rpm; sum_pll_sq sum_pll_sq err_pll_rpm * err_pll_rpm; n n 1; end if n 0 rms_diff_rpm sqrt(sum_diff_sq / double(n)); rms_pll_rpm sqrt(sum_pll_sq / double(n)); else rms_diff_rpm 0.0; rms_pll_rpm 0.0; end end这个模块用来定量比较传统差分测速RMS误差PLL测速RMS误差。整体仿真搭建最终误差分析结果这四组数据分别为传统差分测速误差PLL 测速误差差分测速 RMS 误差PLL 测速 RMS 误差从最终误差结果来看传统差分测速受编码器量化影响比较明显速度误差呈现周期性跳变。在当前参数下差分测速的误差幅值大约在60rpm 范围内RMS 误差约为28 rpm这与理论上的 60 rpm 速度分辨率跳变基本一致。相比之下PLL 测速的误差明显更小恒速段速度波动被有效抑制RMS 误差约为1.5 rpm。说明 PLL 没有直接对量化角度做差分而是通过位置闭环跟踪的方式对速度进行估计因此能够显著降低编码器量化噪声对测速结果的影响。在加速、减速切换点附近PLL 误差会出现短暂尖峰这是由于观测器带宽有限速度变化时存在一定跟踪滞后属于正常现象。总体来看当前参数下 PLL 测速结果更加平滑误差更小适合作为电机速度环的反馈信号。Matlab下对PLL进行频域分析在前面的时域仿真中已经可以直观看到传统差分测速会把编码器的位置量化误差直接放大成速度抖动而 PLL 速度观测器能够明显降低测速噪声。但是仅从时域波形中很难定量判断 PLL 的动态特性例如PLL 响应到底有多快参数 KpK_pKp​、KiK_iKi​ 是否会导致振荡PLL 对高频量化噪声的抑制能力如何当前参数对应的闭环带宽是多少。因此需要进一步从频域角度分析 PLL 观测器。在前面的建模分析中 我们已经得到了PLL 速度估计相对于真实速度的闭环传递函数这个传递函数反映了 PLL 对真实速度变化的跟踪能力。低频段增益接近 1说明 PLL 能够准确跟踪低频速度变化高频段增益下降说明 PLL 对高频扰动和量化噪声具有一定抑制作用。PLL 的特征方程为与标准二阶系统对比可得因此PLL 参数可以通过期望的自然频率和阻尼比直接设计。工程中通常先确定 PLL 带宽再选取阻尼比一般取在频域分析中主要关注以下三个方面分析开环传递函数的 Bode 图和相位裕度。相位裕度反映系统稳定。一般要求大于分析闭环传递函数传递函数可以反映 PLL 对真实速度的跟踪能力。其带宽越高PLL 响应越快但对编码器量化噪声也越敏感带宽越低速度估计越平滑但动态响应会变慢。第三分析角度测量噪声到速度输出的传递函数。由于编码器量化噪声首先作用在位置测量值上因此可以建立因此下面的 MATLAB 脚本主要完成以下工作根据给定的 PLL 带宽和阻尼比计算 Kp、Ki建立 PLL 的开环传递函数 L(s)建立 PLL 的闭环速度跟踪传递函数绘制开环 Bode 图并计算相位裕度绘制闭环 Bode 图并计算带宽分析编码器角度量化噪声到速度输出的频率响应对比连续域模型和离散化模型的频率特性。脚本实现%% pll_freq_analysis.m % 软件 PLL 速度观测器频域分析 clear; clc; close all; %% 参数 fs 10000; Ts 1 / fs; CPR 10000; dtheta 2*pi / CPR; f_pll 100; zeta 0.707; wn 2*pi*f_pll; Kp 2*zeta*wn; Ki wn^2; fprintf( PLL 参数 \n); fprintf(fs %.1f Hz\n, fs); fprintf(Ts %.8f s\n, Ts); fprintf(CPR %.0f counts/rev\n, CPR); fprintf(dtheta %.8e rad/count\n, dtheta); fprintf(f_pll %.2f Hz\n, f_pll); fprintf(zeta %.3f\n, zeta); fprintf(wn %.4f rad/s\n, wn); fprintf(Kp %.4f\n, Kp); fprintf(Ki %.4f\n, Ki); fprintf(Kp*Ts %.6f\n, Kp*Ts); fprintf(Ki*Ts %.6f\n, Ki*Ts); %% 连续域传递函数 s tf(s); % 开环传递函数 % L(s) (Kp Ki/s) * 1/s L (Kp*s Ki) / s^2; % 闭环角度跟踪传递函数 % theta_hat / theta H_theta feedback(L, 1); % 速度跟踪传递函数 % omega_hat / omega theta_hat / theta H_omega H_theta; % 角度测量噪声到速度输出 % omega_hat / theta_noise G_noise s * H_theta; %% 开环裕度 figure; margin(L); grid on; title(PLL Open Loop: L(s)); [GM, PM, Wcg, Wcp] margin(L); fprintf(\n 开环稳定裕度 \n); fprintf(Phase Margin %.2f deg\n, PM); fprintf(Gain crossover frequency %.2f Hz\n, Wcp/(2*pi)); %% 闭环带宽 bw_rad bandwidth(H_omega); bw_hz bw_rad / (2*pi); fprintf(\n 闭环带宽 \n); fprintf(Closed-loop bandwidth %.2f Hz\n, bw_hz); figure; bode(H_omega); grid on; title(Closed Loop: omega\_pll / omega\_true); %% 噪声传递函数 figure; bode(G_noise); grid on; title(Noise Transfer: omega\_pll / theta\_noise); %% 离散化对比 H_omega_z c2d(H_omega, Ts, tustin); figure; bode(H_omega, H_omega_z); grid on; legend(Continuous, Discrete Tustin); title(Continuous vs Discrete Closed Loop); %% 差分测速量化跳变 domega_diff dtheta / Ts; drpm_diff domega_diff * 60 / (2*pi); fprintf(\n 差分测速量化跳变 \n); fprintf(One count jump %.4f rad/s\n, domega_diff); fprintf(One count jump %.4f rpm\n, drpm_diff); %% PLL 对一个 count 误差的比例响应 domega_pll_p Kp * dtheta; drpm_pll_p domega_pll_p * 60 / (2*pi); fprintf(\n PLL 一个 count 误差的比例响应 \n); fprintf(Kp*dtheta %.4f rad/s\n, domega_pll_p); fprintf(Kp*dtheta %.4f rpm\n, drpm_pll_p);运行脚本后的输出 PLL 参数 fs 10000.0 Hz Ts 0.00010000 s CPR 10000 counts/rev dtheta 6.28318531e-04 rad/count f_pll 100.00 Hz zeta 0.707 wn 628.3185 rad/s Kp 888.4424 Ki 394784.1760 Kp*Ts 0.088844 Ki*Ts 39.478418 开环稳定裕度 Phase Margin 65.52 deg Gain crossover frequency 155.36 Hz 闭环带宽 Closed-loop bandwidth 205.56 Hz 差分测速量化跳变 One count jump 6.2832 rad/s One count jump 60.0000 rpm PLL 一个 count 误差的比例响应 Kp*dtheta 0.5582 rad/s Kp*dtheta 5.3307 rpm对仿真结果进行分析这个结果比较好。一般工程上相位裕度大于 45度就可以认为系统有足够稳定性。差分测速的一个 count 跳变量为而 PLL 对一个 count 位置误差的比例响应为。也就是说同样是一个编码器 count 的位置误差差分测速会直接表现成60 rpm的速度跳变而 PLL 比例项只产生大约5.33 rpm的速度修正再加上积分环节的平滑作用所以 PLL 速度输出会明显平滑很多。开环bode图分析从幅频曲线看低频段增益很高说明 PLL 对低频位置误差修正能力强能够保证估计角度跟随编码器角度。在高频段幅值逐渐下降说明高频误差不会被无限放大这对抑制编码器量化噪声是有利的。从相频曲线看系统在增益交越频率附近的相位还没有接近 −180度所以稳定裕度比较充足。闭环bode图分析从幅频曲线看低频段增益接近说明低频速度变化可以被 PLL 准确跟踪。也就是说对于缓慢变化的电机速度PLL 输出基本不会有明显幅值误差。在中频附近幅值有一点轻微抬升这是二阶系统的正常现象与阻尼比有关。这个抬升不大说明系统没有明显谐振问题。高频段幅值开始下降说明 PLL 不会跟随很高频的速度扰动或编码器量化噪声。这个特性正是 PLL 比传统差分测速更平滑的原因之一。前面计算得到闭环带宽为也就是说在大约 200 Hz 以内的速度变化PLL 可以比较有效地跟踪超过这个频率后PLL 会逐渐衰减速度输出会变得更平滑但动态响应也会变慢。和时域仿真的对应关系前面时域仿真中可以看到差分测速误差50 rpmPLL 测速误差约 1.5 rpm RMS这和频域结果是对应的。原因是PLL 低频增益接近 0 dB所以能跟踪真实速度PLL 高频增益下降所以能抑制编码器量化噪声相位裕度较高所以不会出现明显振荡。因此当前 PLL 参数在“响应速度”和“噪声抑制”之间取得了比较好的折中。C代码实现与平台验证代码实现typedef struct { float Ts; //速度环采样执行周期 float Count; //计数器的计数值 float Count_To_Rad; //计数值转化到角度值的系数 float Zeta; //阻尼比 float Omega_n; //自然频率 float Kp; //比例系数 float Ki; //积分系数 float Theta_Hat; //估计的机械角度 float Omega_m_Hat; //估计的机械角速度 float I_Port; //积分项 float Theta_Meas; //实际的机械角度 float Err; //当前角度误差 float Omega_m_Limit; //速度限幅 float I_Limit; //积分限幅 float Speed; //机械转速RPM; }Increment_Encoder_PLL_Get_Speed; //锁相环获取电机转速 Increment_Encoder_PLL_Get_Speed Bsp_Increment_Encoder_PLL //锁相环获取电机转速 void Bsp_PLL_Get_Motor_Speed(void) { /*将脉冲数转换为机械角度*/ Bsp_Increment_Encoder_PLL.Theta_Meas (float) Bsp_Increment_Encoder_PLL.Count * Bsp_Increment_Encoder_PLL.Count_To_Rad; /*计算角度误差*/ Bsp_Increment_Encoder_PLL.Err Bsp_Increment_Encoder_PLL.Theta_Meas - Bsp_Increment_Encoder_PLL.Theta_Hat; /*误差限幅*/ if(Bsp_Increment_Encoder_PLL.Err PLL_PI) { Bsp_Increment_Encoder_PLL.Err - PLL_TWO_PI; } else if(Bsp_Increment_Encoder_PLL.Err -PLL_PI) { Bsp_Increment_Encoder_PLL.Err PLL_TWO_PI; } /*计算锁相环积分项*/ Bsp_Increment_Encoder_PLL.I_Port Bsp_Increment_Encoder_PLL.Ki * Bsp_Increment_Encoder_PLL.Ts * Bsp_Increment_Encoder_PLL.Err; /*积分限幅度*/ if(Bsp_Increment_Encoder_PLL.I_Port Bsp_Increment_Encoder_PLL.I_Limit) { Bsp_Increment_Encoder_PLL.I_Port Bsp_Increment_Encoder_PLL.I_Limit; } else if(Bsp_Increment_Encoder_PLL.I_Port -Bsp_Increment_Encoder_PLL.I_Limit) { Bsp_Increment_Encoder_PLL.I_Port -Bsp_Increment_Encoder_PLL.I_Limit; } /*计算PI输出 估算的角速度*/ Bsp_Increment_Encoder_PLL.Omega_m_Hat Bsp_Increment_Encoder_PLL.I_Port Bsp_Increment_Encoder_PLL.Kp * Bsp_Increment_Encoder_PLL.Err; /*角速度输出限幅*/ if(Bsp_Increment_Encoder_PLL.Omega_m_Hat Bsp_Increment_Encoder_PLL.Omega_m_Limit) { Bsp_Increment_Encoder_PLL.Omega_m_Hat Bsp_Increment_Encoder_PLL.Omega_m_Limit; } else if(Bsp_Increment_Encoder_PLL.Omega_m_Hat -Bsp_Increment_Encoder_PLL.Omega_m_Limit) { Bsp_Increment_Encoder_PLL.Omega_m_Hat -Bsp_Increment_Encoder_PLL.Omega_m_Limit; } /*转化机械转速*/ Bsp_Increment_Encoder_PLL.Speed (Bsp_Increment_Encoder_PLL.Omega_m_Hat * 60.0f) / (2*PI); /*速度积分得到估算角度*/ Bsp_Increment_Encoder_PLL.Theta_Hat Bsp_Increment_Encoder_PLL.Omega_m_Hat * Bsp_Increment_Encoder_PLL.Ts; /*估算角度限幅度*/ if(Bsp_Increment_Encoder_PLL.Theta_Hat PLL_TWO_PI) { Bsp_Increment_Encoder_PLL.Theta_Hat - PLL_TWO_PI; } else if(Bsp_Increment_Encoder_PLL.Theta_Hat 0) { Bsp_Increment_Encoder_PLL.Theta_Hat PLL_TWO_PI; } }平台验证本次验证采用永磁同步电机实验平台编码器为1000线增量式编码器 MCU主控stm32g474vet6 ,通过配置定时器3为编码器模式来进行脉冲获取。采用4倍频后分别进行M法测速和PLL锁相环法进行测速设置阻尼比为0.707自然频率为2*PI*100。从 MCU 实测波形来看红色为设定转速300 rpm绿色为传统 M 法测速结果黄色为 PLL 锁相环测速结果。可以看出M 法测速波形存在明显的脉冲跳变和尖峰这是由于增量式编码器在低速下单位采样周期内脉冲数较少测速结果容易受到量化误差影响导致速度反馈抖动较大。相比之下PLL 测速结果明显更加平滑黄色曲线能够围绕设定转速附近变化没有出现 M 法那种剧烈的瞬时跳变。说明 PLL 通过“位置误差闭环 PI 调节 速度积分”的方式对编码器脉冲量化噪声起到了较好的抑制作用。不过从波形上看PLL 输出仍然存在一定周期性波动这可能与编码器分辨率、采样周期、PLL 带宽参数以及电机实际转速波动有关。当前 PLL 参数已经能够明显改善测速质量但后续如果希望速度反馈更平滑可以适当降低 PLL 带宽如果希望动态响应更快可以适当提高 PLL 带宽。结束语经过理论推导、Simulink 仿真验证以及最终的 MCU 实机部署本次基于增量式编码器的软件 PLL 测速方案已基本落地。对比测试表明软件 PLL 方案有效克服了传统 M 法在低速区间受量化误差影响而产生的剧烈抖动使得速度反馈曲线具备了出色的平滑度。需要指出的是PLL 的本质是基于角度偏差的闭环跟踪器而非单纯的低通滤波器。因此核心参数 Kp 与 Ki 即系统的带宽与阻尼比的匹配依然是决定动态响应与抗噪能力的关键。本次工作不仅验证了该算法在工程实践中的可行性也为后续速度环的精细调参及更高阶的伺服控制构筑了可靠的底层数据支持。觉得有用的话帮忙点个赞啦谢谢大家了