PLC编码器测速:中心差分法与自适应滤波算法解决低速跳变难题

📅 2026/8/27 10:27:43
PLC编码器测速:中心差分法与自适应滤波算法解决低速跳变难题
1. 项目缘起从“跳变”到“稳定”的测速挑战在工业自动化现场尤其是伺服电机、主轴驱动这类对速度反馈精度和实时性要求极高的场景编码器测速的稳定性是控制系统能否平稳运行的基石。然而任何一个在现场摸爬滚打过的工程师都或多或少遇到过这样的困扰电机在低速、甚至极低速运行时读取到的速度值会时不时出现一个“毛刺”或者“跳变”明明设备运行得很平稳但监控画面上反馈的速度曲线却像心电图一样偶尔来一下“早搏”。这个问题在我最近调试的一条精密涂布生产线上尤为突出。问题的根源正如热词中提到的行业共性物理现象伺服电机编码器在低速运行时光电开关或磁敏元件的感应点可能恰好停在码盘刻线的边缘。此时由于元件本身的灵敏度存在微小差异或者现场难以避免的轻微机械振动、电磁干扰就可能导致单相信号比如A相或B相发生一次不应有的跳变。对于依赖脉冲计数和周期测量的传统测速方法这种单次跳变会被误认为是一个完整的脉冲沿从而计算出一个瞬间的、错误的高速度值这就是速度反馈出现“毛刺”的本质。面对这个问题硬件上的优化如选用更高精度编码器、加强机械安装刚性、改善屏蔽固然重要但成本高且有时受限于既有设备。因此在软件算法层面进行“后处理”滤除这种由物理局限引入的噪声就成了性价比最高、也最体现工程师功力的解决方案。本次分享的“PLC编码器测速(中心差分法测速自适应滤波算法)”项目正是基于西门子S7-1200/1500系列PLC用SCL语言实现的一套从高精度速度计算到智能滤波的完整解决方案。它不依赖任何特殊的硬件模块纯粹通过算法优化让即使在最苛刻的低速工况下速度反馈也能平滑如丝。2. 测速核心为什么是中心差分法在深入代码之前我们必须先搞清楚为什么在PLC中做高精度速度测量中心差分法Central Difference Method是一个优选方案。这需要从最基础的M法、T法测速说起。2.1 M法、T法的局限与速度计算的本质M法频率测量法是在固定时间窗口内统计编码器脉冲数。它的精度在高速时很高因为脉冲多统计误差小。但在低速时时间窗口内可能只收到寥寥几个甚至零个脉冲速度分辨率极低且无法反映速度的瞬时变化。T法周期测量法是测量两个相邻脉冲之间的时间间隔。它在低速时精度高因为周期长PLC的高精度定时器能测得很准。但在高速时脉冲周期极短受限于PLC定时器的计时分辨率通常为1微秒测量误差会急剧增大同样可能丢失动态信息。而速度的定义是位移对时间的导数。对于编码器位移就是脉冲数乘以一个系数时间就是PLC的扫描周期或更精确的定时器时间。我们追求的是尽可能准确地计算每个采样时刻的瞬时速度。这就引出了数值微分方法。2.2 中心差分法的优势精度与实时性的平衡前向差分用当前和未来脉冲不现实因为无法预知未来。后向差分用当前和过去脉冲简单但误差较大。中心差分法使用过去和未来的脉冲信息来计算当前时刻的速度其数学形式近似为v(t) ≈ (x(tΔt) - x(t-Δt)) / (2Δt)。在PLC的上下文中x是编码器累计值Δt是采样周期。这意味着我们在t时刻计算的速度实际上利用了t-Δt和tΔt两个时刻的位置信息。这样做有什么好处精度更高数值分析理论表明中心差分法的截断误差是二阶的比一阶的后向差分法精度更高。对于速度变化不太剧烈的情况它能更准确地逼近真实瞬时速度。抗噪性更好相比于只用两个相邻点后向差分中心差分法相当于对数据进行了一个简单的平滑处理对于脉冲计数中偶尔的跳变比如我们开头提到的单相信号跳变其影响会被部分抵消。相位滞后小虽然利用了点未来的信息tΔt但这个未来是相对于计算时刻t的。在实际编程中我们总是在一个扫描周期结束时利用本周期采集到的“最新”位置值即t时刻和上一个周期保存的位置值即t-Δt时刻来计算。这里的“未来”信息tΔt在下一个扫描周期就会变成“当前”信息。因此实际算法引入的相位滞后只有一个采样周期这对于大多数控制回路来说是可接受的。在SCL中实现核心代码段如下所示。这里假设我们有一个功能块FB_CentralDiffSpeed在每个扫描周期调用。FUNCTION_BLOCK FB_CentralDiffSpeed VAR_INPUT i_EncoderRawValue: DINT; // 输入编码器原始计数值 i_SamplingTimeMs: REAL : 10.0; // 输入采样周期单位ms i_Reset: BOOL : FALSE; // 输入复位 END_VAR VAR_OUTPUT o_SpeedRPM: REAL; // 输出计算出的速度单位RPM o_SpeedValid: BOOL; // 输出速度值有效标志 END_VAR VAR r_PrevValue: DINT; // 上次采样值 (t-Δt) r_CurrValue: DINT; // 当前采样值 (t) r_PrevPrevValue: DINT; // 上上次采样值 (t-2Δt)用于初始化 r_FirstScan: BOOL : TRUE; r_PulsePerRevolution: REAL : 1000.0; // 编码器每转脉冲数 END_VAR // 复位处理 IF i_Reset OR r_FirstScan THEN r_PrevPrevValue : i_EncoderRawValue; r_PrevValue : i_EncoderRawValue; r_CurrValue : i_EncoderRawValue; o_SpeedRPM : 0.0; o_SpeedValid : FALSE; r_FirstScan : FALSE; RETURN; END_IF; // 更新值队列实现“中心”概念 // 将旧值依次传递上上次值 上次值 上次值 当前值 当前值 新采样值 r_PrevPrevValue : r_PrevValue; r_PrevValue : r_CurrValue; r_CurrValue : i_EncoderRawValue; // 中心差分法速度计算 // 速度 (脉冲/ms) (当前值 - 上上次值) / (2 * 采样周期) // 转换为 RPM: RPM (速度 * 60000) / (每转脉冲数) // 注意这里用 (r_CurrValue - r_PrevPrevValue) 模拟了 (x(tΔt) - x(t-Δt)) // 因为我们的“当前值”r_CurrValue是在周期末读取的对于本周期计算来说它相对于周期中的“计算时刻”已是未来信息。 IF i_SamplingTimeMs 0 THEN o_SpeedRPM : ((r_CurrValue - r_PrevPrevValue) / (2.0 * i_SamplingTimeMs)) * (60000.0 / r_PulsePerRevolution); o_SpeedValid : TRUE; ELSE o_SpeedValid : FALSE; END_IF;注意这段代码是一种简化的实现。严格意义上的中心差分需要对称的时间点。这里利用三个历史点(t-2Δt, t-Δt, t)用(x(t) - x(t-2Δt)) / (2Δt)来近似t-Δt时刻的速度。这是一种常用且有效的工程近似其效果和抗噪性依然远优于后向差分。3. 滤波进阶自适应滤波算法的设计与实现中心差分法已经滤除了一部分高频噪声但对于那种低频、偶发的单脉冲跳变其抑制能力仍然有限。特别是当这种跳变发生在r_CurrValue或r_PrevPrevValue上时会直接导致速度计算出现一个尖峰。这时就需要一个“智能”的滤波器上场。3.1 为什么不用普通的低通滤波器一阶低通滤波器First Order Low Pass Filter, FOLPF是PLC里最常用的滤波手段但它有一个致命缺点滞后与带宽的矛盾。截止频率设低了滤波效果好但信号滞后严重影响系统动态响应截止频率设高了滞后小但又滤不掉低频干扰。在电机速度从零启动或低速运行时我们希望能快速跟踪真实速度需要高带宽同时又希望能抑制跳变需要低带宽。这是一个矛盾。自适应滤波算法的核心思想就是让滤波器的“强度”根据信号的特性动态调整。在我们的场景里调整的依据就是当前速度值是否“合理”。3.2 自适应滤波逻辑基于“合理性”判断的智能切换我们的算法设计思路如下状态判断根据电机控制器的使能状态、给定速度等判断电机当前处于“静止”、“低速运行”、“高速运行”还是“加减速”状态。不同状态对速度反馈的噪声容忍度和响应速度要求不同。合理性校验计算一个“预期速度范围”。例如在静止状态下任何超过某个极小阈值如0.1%额定转速的速度读数都可以被认为是“不合理”的噪声。在匀速运行时可以根据前一时刻的滤波后速度和加速度限幅推算出一个当前时刻速度的可能范围。滤波策略切换正常情况当本次计算出的原始速度值落在“合理范围”内认为信号可信使用一个截止频率较高的低通滤波器或较小的滤波系数让反馈快速跟踪。异常情况当原始速度值超出“合理范围”特别是出现一个巨大的正/负尖峰时判定为脉冲跳变噪声。此时果断切换到截止频率极低的强滤波器或直接采用上一周期的滤波输出值将这个野值滤掉。特殊状态在启动加速阶段可以适当放宽“合理范围”因为速度本身变化剧烈在高速稳态阶段可以收紧范围因为此时不应有大的速度突变。下面是用SCL实现的一个简化版自适应滤波功能块FB_AdaptiveFilter的核心逻辑。它融合了状态判断和基于偏差的滤波系数调整。FUNCTION_BLOCK FB_AdaptiveFilter VAR_INPUT i_RawSpeed: REAL; // 输入原始速度值来自中心差分法 i_SpeedRef: REAL : 0.0; // 输入速度给定值用于判断状态 i_MotorEnabled: BOOL : FALSE; // 输入电机使能状态 i_SamplingTimeMs: REAL : 10.0; // 输入采样周期 i_MaxAcceleration: REAL : 1000.0; // 输入最大加速度 (RPM/s)用于合理性校验 i_Reset: BOOL : FALSE; END_VAR VAR_OUTPUT o_FilteredSpeed: REAL; // 输出滤波后速度 o_IsNoiseDetected: BOOL; // 输出本次是否检测到噪声 END_VAR VAR r_PrevFilteredSpeed: REAL; r_FilterCoeff: REAL : 0.1; // 动态滤波系数0coeff1越小滤波越强 r_NormalCoeff: REAL : 0.3; // 正常情况系数 r_StrongCoeff: REAL : 0.05; // 强滤波系数 r_DeadBand: REAL : 2.0; // 静止死区单位RPM r_FirstScan: BOOL : TRUE; // 状态枚举 e_State: (IDLE, ACCEL, STEADY, DECEL); END_VAR // 复位与初始化 IF i_Reset OR r_FirstScan THEN r_PrevFilteredSpeed : 0.0; o_FilteredSpeed : 0.0; o_IsNoiseDetected : FALSE; r_FirstScan : FALSE; r_FilterCoeff : r_NormalCoeff; e_State : IDLE; RETURN; END_IF; // 1. 状态机判断简化版 IF NOT i_MotorEnabled THEN e_State : IDLE; ELSIF ABS(i_SpeedRef) 1.0 THEN // 给定速度很小认为稳态或微动 e_State : STEADY; ELSE // 此处可加入更复杂的加速度判断逻辑来区分ACCEL/DECEL e_State : STEADY; END_IF; // 2. 计算“预期速度范围” CASE e_State OF IDLE: // 静止时预期速度应在零附近死区内 IF ABS(i_RawSpeed) r_DeadBand THEN r_FilterCoeff : r_NormalCoeff; o_IsNoiseDetected : FALSE; ELSE // 超出死区判定为噪声启用强滤波 r_FilterCoeff : r_StrongCoeff; o_IsNoiseDetected : TRUE; END_IF; STEADY: // 稳态运行时预期速度不应突变。根据最大加速度和采样时间计算允许变化量 VAR_TEMP allowedDelta: REAL; END_VAR allowedDelta : i_MaxAcceleration * i_SamplingTimeMs / 1000.0; // 转换为RPM/周期 // 预期范围 上一滤波值 ± 允许变化量 IF (i_RawSpeed (r_PrevFilteredSpeed - allowedDelta)) AND (i_RawSpeed (r_PrevFilteredSpeed allowedDelta)) THEN r_FilterCoeff : r_NormalCoeff; o_IsNoiseDetected : FALSE; ELSE r_FilterCoeff : r_StrongCoeff; o_IsNoiseDetected : TRUE; END_IF; // ACCEL, DECEL 状态可根据需要类似实现通常放宽 allowedDelta END_CASE; // 3. 应用一阶低通滤波 (如果检测到强噪声可选择保持原值) IF o_IsNoiseDetected AND (r_FilterCoeff r_StrongCoeff) THEN // 方案A遇到强噪声时直接丢弃本次原始值输出保持为上次滤波值 // o_FilteredSpeed : r_PrevFilteredSpeed; // 方案B使用极强的滤波系数进行滤波更平滑 o_FilteredSpeed : r_PrevFilteredSpeed r_FilterCoeff * (i_RawSpeed - r_PrevFilteredSpeed); ELSE // 正常滤波 o_FilteredSpeed : r_PrevFilteredSpeed r_FilterCoeff * (i_RawSpeed - r_PrevFilteredSpeed); END_IF; // 更新历史值 r_PrevFilteredSpeed : o_FilteredSpeed;这个自适应滤波器就像一个经验老道的操作工平时正常监控正常滤波一旦发现仪表指针猛地抖一下异常跳变他立刻就知道这是干扰不是真实工况于是选择忽略这个抖动或者用一个很慢的速度去相信它强滤波从而保证输出给控制系统的速度信号始终是平稳可靠的。4. 系统集成与工程实践要点将中心差分法和自适应滤波算法集成到实际的PLC项目中并确保其稳定可靠远不止是代码堆砌。下面结合我在涂布生产线项目中的实施经验分享几个关键要点。4.1 采样周期的选择与中断处理测速算法的精度严重依赖固定的、精确的采样周期。绝对不要在OB1主循环组织块里直接调用这些功能块因为OB1的循环时间是不稳定的会受到程序长度、通信负载等因素影响。正确做法是使用循环中断组织块Cyclic Interrupt OB。例如在S7-1200/1500中可以创建一个OB30将其循环时间设置为10ms根据需求可调常见为1-20ms。所有的编码器值读取、速度计算、滤波都在这个中断OB中完成。这样i_SamplingTimeMs参数就可以固定设置为10.0保证了速度计算分母的准确性这是中心差分法精度的重要保障。// 在循环中断OB (如OB30) 中调用 // 读取编码器硬件输入通道值注意处理溢出 #iRawCount : “HW_Input”.ID1000; // 举例 // 处理32位计数器溢出如果编码器是增量式并循环计数 #encoder.ActualPosition : CALCULATE_ACTUAL_POSITION(#iRawCount, #encoder.LastRawCount); // 调用中心差分法速度计算 #speedCalcFB( i_EncoderRawValue : #encoder.ActualPosition, i_SamplingTimeMs : 10.0, // 与OB30周期一致 i_Reset : #bReset, o_SpeedRPM #rawSpeedRPM ); // 调用自适应滤波器 #adaptiveFilterFB( i_RawSpeed : #rawSpeedRPM, i_SpeedRef : #setpointSpeedRPM, i_MotorEnabled : #bMotorEnabled, i_SamplingTimeMs : 10.0, i_MaxAcceleration : 500.0, // 根据实际电机性能设定 i_Reset : #bReset, o_FilteredSpeed #finalSpeedRPM, // 最终用于控制的速度反馈 o_IsNoiseDetected #bNoiseFlag );4.2 编码器计数与方向处理上述代码假设i_EncoderRawValue是一个带符号的DINT双整数能正确反映正反转。对于常见的A/B相正交编码器PLC的高速计数器HSC模块通常可以配置为“四倍频”和“带有方向的增/减计数”模式。务必在硬件组态中正确配置这样PLC会自动处理脉冲计数和方向判断我们直接读取的就是一个有符号的累计值。这是整个测速算法的数据源头必须确保准确无误。如果使用的是单相脉冲编码器则需要自己通过比较前后周期计数值来判断方向逻辑会复杂一些且精度和抗噪性会下降。4.3 参数整定让算法适应你的设备算法是骨架参数是血肉。两个核心功能块有几个关键参数需要现场调试中心差分法块r_PulsePerRevolution编码器每转脉冲数考虑四倍频后的值。这是将“脉冲/时间”转换为“RPM”的关键必须准确。i_SamplingTimeMs必须与调用它的循环中断OB周期严格一致。自适应滤波块调试重点r_DeadBand静止死区这个值需要根据现场噪声水平设定。可以先让电机静止观察i_RawSpeed的波动范围然后将r_DeadBand设置为波动峰峰值的1.5-2倍。设置太小会导致频繁误报噪声设置太大会漏掉真实的低速信号。i_MaxAcceleration最大加速度这是“合理性校验”的基石。需要从电机和负载的物理特性中获取。可以查阅伺服驱动器手册中的最大加速度参数或者在实际设备上做一个最大加减速测试测量速度变化率。这个值宁可设得稍大一些也不要设小否则在正常加速时会被误判为噪声。r_NormalCoeff和r_StrongCoeff滤波系数这两个系数决定了滤波器的“惯性”大小。系数越小惯性越大滤波效果越强但滞后也越严重。通常r_NormalCoeff在0.1~0.5之间选择r_StrongCoeff在0.01~0.1之间选择。调试时可以观察在电机匀速运行时给编码器信号线一个轻微干扰模拟脉冲跳变看o_IsNoiseDetected是否会置位以及o_FilteredSpeed的曲线是否平滑。实操心得参数整定是一个“观察-调整-验证”的循环过程。务必利用好PLC的跟踪Trace功能将i_RawSpeed、o_FilteredSpeed、o_IsNoiseDetected等关键变量同时录下来。在电机启动、低速运行、高速运行、急停等多种工况下反复测试分析滤波效果和响应速度找到最适合当前设备的一组“黄金参数”。4.4 高级扩展应对复杂干扰与状态切换前述的自适应滤波逻辑是一个基础框架。在实际更复杂的场景中还可以进一步扩展多级噪声判断不要只用一个allowedDelta。可以设置多个阈值对应不同的滤波强度。例如偏差在allowedDelta的1倍以内用正常系数偏差在1-3倍之间用中等系数偏差超过3倍用最强系数或保持输出。连续噪声抑制如果o_IsNoiseDetected连续多个周期置位可能不是单脉冲跳变而是遇到了持续干扰如强电磁场。此时可以触发一个报警并可能切换到更保守的控制模式。与运动控制器状态机联动滤波器的状态如e_State最好能与上级运动控制器的状态机如回零完成、点位运动、同步跟随紧密联动。在不同控制模式下对速度反馈的“预期”是不同的可以动态调整i_MaxAcceleration等参数使滤波行为更具针对性。5. 效果验证与常见问题排查一套算法是否有效必须用数据说话。在涂布生产线项目中应用此算法后低速5 RPM下的速度反馈波动从原来的±15 RPM降低到了±0.5 RPM以内完全满足了高精度张力控制的要求。5.1 如何验证算法效果静态测试电机静止使能驱动器但不给速度指令让电机轴保持静止。监控i_RawSpeed和o_FilteredSpeed。理想情况下i_RawSpeed可能会有小幅波动来自工频干扰等而o_FilteredSpeed应迅速收敛并稳定在0附近。o_IsNoiseDetected应对大的波动置位。低速匀速测试给定一个很低的速度如2 RPM让电机平稳运行。观察滤波后的速度曲线是否平滑没有毛刺。同时观察在匀速状态下o_IsNoiseDetected不应频繁置位。加减速测试给定一个梯形速度曲线。观察在加速和减速阶段滤波后的速度是否能很好地跟踪给定值没有明显的滞后或过冲。在加减速转折点由于速度变化率大可能会触发噪声检测这是正常的但只要滤波后的曲线平滑过渡即可。抗干扰测试在电机运行时人为地轻微敲击编码器线缆或靠近的继电器注意安全模拟瞬时干扰。观察滤波算法是否能有效抑制由此产生的速度尖峰。5.2 常见问题与排查清单如果算法效果不理想可以按照以下清单进行排查问题现象可能原因排查步骤与解决方案滤波后速度仍有明显毛刺1. 自适应滤波参数过于宽松r_DeadBand太大i_MaxAcceleration太大r_StrongCoeff太大。2. 噪声并非单脉冲跳变而是持续高频干扰。1. 使用Trace功能抓取i_RawSpeed的波形分析毛刺的幅值和频率。2. 适当收紧r_DeadBand确保其大于正常波动但小于毛刺幅值。3. 检查编码器电缆屏蔽层是否单端接地是否与动力线分开敷设。速度反馈滞后严重响应慢1. 正常滤波系数r_NormalCoeff设置过小。2. 采样周期i_SamplingTimeMs设置过长。3. 在加减速等动态过程算法误判为噪声并使用了强滤波。1. 适当增大r_NormalCoeff如从0.1调到0.3。2. 在保证PLC性能前提下缩短循环中断OB的周期。3. 检查i_MaxAcceleration是否设置过小或在动态过程中临时切换到一个更宽松的滤波模式。电机静止时滤波后速度不为零1. 编码器零漂或硬件存在微小偏差。2. 死区r_DeadBand设置过小未能包含零漂。1. 在电机静止时记录一段时间的i_RawSpeed计算其平均值作为零偏在最终速度输出前减去此零偏软件调零。2. 适当增大r_DeadBand。低速时速度显示为零或跳变1. 中心差分法在极低速下由于脉冲间隔大于2倍采样周期计算出的速度可能间歇性为零。2. 编码器分辨率过低。1. 这是M/T法测速的固有限制。可以考虑在极低速段如脉冲周期大于某个阈值切换到T法周期测量法进行速度计算与中心差分法结果进行平滑切换。2. 考虑使用更高分辨率的编码器。o_IsNoiseDetected频繁误报1. “合理性”判断条件过于苛刻。2. 电机实际运行加速度超过了预设的i_MaxAcceleration。1. 检查r_DeadBand和i_MaxAcceleration是否合理。在稳态下观察速度波动范围在动态下实测最大加速度。2. 考虑引入更复杂的状态机在明确知道电机处于加减速状态时使用另一套更大的allowedDelta参数。这套“中心差分法自适应滤波”的组合拳经过多个项目的验证能够有效解决编码器低速跳变这一经典难题。它最大的优势在于纯软件实现不增加硬件成本且灵活性极高可以通过参数调整适应不同的机械特性和噪声环境。将这套算法封装成标准的PLC函数块已经成为我处理高精度速度反馈项目的标准工具箱之一。