现场仪表数据跳得像心电图PID输出跟着乱摆设备一启动监控曲线全是毛刺——这种画面我在项目现场见过太多次了。工控信号滤波这事看着简单实际上很多现场问题都栽在选错算法或者参数没调好上。这篇文章把工控里最常用的10种滤波算法从头到尾梳理一遍每种都给出C语言实现和适用边界最后聊一聊实战中怎么选、怎么避坑。适合正在做数据采集、PLC程序优化、设备监控系统开发的工程师参考尤其是那些被变频器干扰、称重跳数、温度漂移折磨过的朋友。滤波不是把数据变好看而是让控制系统拿到尽可能接近物理真值的数字信号。一个道理我反复跟现场同事讲滤波算法没有绝对的好坏只有合不合适的区别。把你领进门口的不是华丽算法而是对信号干扰类型的正确判断。先把这个搞明白后面选什么滤波都是一眼看穿的事。1. 现场信号为啥总不干净——动手前先分清干扰类型跟很多工程师聊滤波上来第一句就是我写个平均滤波试试。这种思路容易走弯路因为平均滤波对付随机噪声还行碰上尖峰干扰就抓瞎。真正的问题是你根本没搞清楚自己要滤掉的到底是什么东西。工控现场的模拟量信号从传感器到采集端沿途要经过变送器、屏蔽电缆、接线端子、隔离模块每一段都可能引入干扰。变频器启动、大功率电机换向、继电器吸合的瞬间电磁耦合会在信号线上叠加出几毫伏到几百毫伏的毛刺。信号源本身还有自己的噪声比如热电偶的热噪声、应变片的机械振动噪声。这些干扰叠加在一起最终进到ADC里的就是一个真值多种噪声的混合体。我把常见的干扰分成四类这四类对应着完全不同的滤波策略随机噪声幅度不大但高频抖动像草皮一样贴在信号曲线上。主要来自电子热噪声、ADC量化噪声。对付它靠平均类算法。脉冲尖峰偶尔吧嗒跳一下可能只持续一个采样周期幅度很大。来自电磁耦合、静电放电、继电器火花。对付它靠限幅、中值这类不信邪的算法。周期性纹波有规律的波动比如变频器载波耦合进来的谐波、电源50Hz工频干扰。对付它需要频率域思路用低通滤波或窗口长度跟周期匹配的滑动平均。缓慢漂移整体趋势缓慢变化叠加小噪声比如热电阻测温随环境温度缓慢升降。这种信号本身很干净但需要无滞后的平滑用卡尔曼这类有预测能力的算法比较合适。滤波的本质是对一段历史数据做数学变换用过去的规律推测当前的真值。既然是推测就有代价——最常见的是滞后。你把噪声压得越狠信号就越迟到达这在闭环控制里可能引发系统发散。所以我一直主张先给信号画个像再挑算法。后面每一章讲算法时我都会把适合对付什么干扰放在第一位就是这个原因。2. 先解决毛刺和跳变限幅、中值、算术平均三种硬派算法2.1 限幅滤波对付一针扎破的尖峰最直接限幅滤波的逻辑朴素得像保安查证每次新采样值到来跟上次合法值比比差距超过预设阈值就直接扔了用旧值顶替。这个阈值就是最大允许偏差它的物理含义是信号在相邻两个采样周期里最多可能变化多少。#define LIMIT_A 50 // 最大允许偏差按实际工况标定 int16_t filter_limiting(int16_t new_value, int16_t last_valid) { if ((new_value - last_valid LIMIT_A) || (last_valid - new_value LIMIT_A)) { return last_valid; // 视为干扰维持旧值 } return new_value; }限幅滤波最大的价值是实时性。它不攒数据、不用排序、不引入平均延迟每来一个点立刻出结果。称重传感器被行车吊臂压到瞬间数值飙一下或者液位计偶尔被气泡顶出一个尖峰用限幅一刀切下去最干净。但阈值怎么定是个学问。定小了真信号也被当干扰掐掉曲线变成阶梯状定大了小尖峰照样穿过去。我的经验是先记录正常工况下信号变化的最大速率乘以采样周期再放1.5到2倍余量。比如温度采样周期200ms正常最快升温速率是0.5℃/周期那阈值取1℃就合理。如果是变频器启动瞬间的那种尖峰阈值就得按毛刺的实际幅度来。限幅的短板在于它只处理相邻两点跳变过大对缓慢叠加在信号上的噪声毫无办法也滤不掉周期纹波。它适合做第一道防线后面往往还要串别的滤波。2.2 中位值滤波宁可慢一点也不信邪中位值滤波的思路是连续采N个点排序后取中间那个。因为脉冲干扰一般只影响少数几个点处于中间位置的数值大概率是没被污染的。这招在对付抽风式跳变的现场特别管用。#define MEDIAN_N 11 int16_t filter_median(int16_t sample_buf[]) { int16_t tmp[MEDIAN_N]; int16_t temp; int i, j; for (i 0; i MEDIAN_N; i) { tmp[i] sample_buf[i]; // 复制一份避免破坏原始顺序 } // 简单冒泡排序N只有11个元素开销可接受 for (i 0; i MEDIAN_N - 1; i) { for (j 0; j MEDIAN_N - i - 1; j) { if (tmp[j] tmp[j 1]) { temp tmp[j]; tmp[j] tmp[j 1]; tmp[j 1] temp; } } } return tmp[MEDIAN_N / 2]; }N一般取奇数3、5、7、11都常见。N越大抗脉冲能力越强但响应越慢而且排序的内存和时间开销线性上升。实际使用中要注意一个陷阱如果干扰不是单点、而是连续多拍比如继电器触点抖动造成连续三四个点都偏高N取5的时候中值可能还是被污染的。这时候要加大N或者换成限幅中值的组合。中值滤波另一个特性是去真值风险。如果工艺过程本身发生了一个快速真实变化——比如物料突然加入导致温度骤升中值滤波会把这个真实跳变也当成干扰压掉。所以它只适合变化相对缓慢、偶尔被脉冲干扰的对象。我在皮带秤系统上见过中值滤波把落料瞬间的真实重量突变削成缓坡导致累计量偏差这点务必注意。2.3 算术平均滤波压随机噪声的笨办法算术平均滤波大概是大家学的第一个数字滤波方法采N个点加起来除以N。它的数学依据是随机噪声期望为零平均次数越多噪声被抵消得越干净。信号真值如果接近直流或变化极慢平均值就非常接近真值。#define AVG_N 100 int16_t filter_average(void) { int32_t sum 0; int16_t sample; int i; for (i 0; i AVG_N; i) { sample adc_read(); // 连续采样 sum sample; } return (int16_t)(sum / AVG_N); }算术平均最大的代价是采样时间被拉长。假设ADC单次转换要1ms平均100次就要100ms意味着100ms才能刷新一次结果。对温度、液位这种慢变量没问题对流量、压力这种需要快速响应的参数就会坏事。更隐蔽的问题是它对脉冲干扰几乎无效。一个幅度特别大的尖峰混进100个样本里平均之后虽然被稀释了但依然会把结果拉偏。我曾经用算术平均滤称重信号平时挺平滑叉车一过地磅数值就稳不住后来改看原始波形才发现是脉冲干扰混进去了。所以算术平均只适合噪声分布均匀、没有明显尖峰的场合。3. 让曲线平滑又不迟钝滑动平均、加权滑动平均与一阶滞后3.1 滑动平均滤波MCU上最常用、也最容易被用坏的窗口滑动平均和算术平均的区别在于算术平均是攒满N个重新算一遍滑动平均是维持一个固定长度的窗口每来一个新点窗口整体往前移动一格只做一次加新减旧的运算。实时性好很多每个采样周期都能输出一个新结果。#define WINDOW_SIZE 16 typedef struct { int16_t buf[WINDOW_SIZE]; uint8_t index; int32_t sum; } SlidingFilter; int16_t filter_sliding(SlidingFilter *f, int16_t new_value) { // 减去最旧的点加上新点窗口自动滑动 f-sum - f-buf[f-index]; f-buf[f-index] new_value; f-sum new_value; f-index (f-index 1) % WINDOW_SIZE; return (int16_t)(f-sum / WINDOW_SIZE); }滑动平均的高频衰减特性跟窗口长度直接相关。窗口越大噪声压得越狠但相位滞后跟窗口长度成正比。一个16点的窗口在100Hz采样下代表160ms的记忆长度——换句话说真值变化之后输出要大约160ms才能跟上。最容易被用坏的地方有两个。第一是窗口长度跟信号周期不匹配。信号里如果有个10Hz的周期性波纹你把窗口设在10个采样点对应10Hz波纹不但滤不掉反而会被平均成完整周期的平均值输出照样波动。要让波纹衰减20倍以上窗口长度最好取波纹周期的10倍。第二是窗口内数据权重完全一样旧数据和最新数据说话分量相同导致实时性被拖累。改进办法就是下面要讲的加权。3.2 加权滑动平均给新鲜数据更高话语权加权滑动平均的核心思想很简单越新的数据越接近当前真值给它更高的权重越旧的数据越不可信权重相应降低。这相当于在平滑度和响应速度之间找了个折中。权重序列的选择有讲究。最简单的是线性递减比如窗口长度5权重按{时间越新权重越大}分配。更工程化的做法是让权重符合指数衰减规律这样既保持了平滑性又不会被老数据绑住脚。#define W_WEIGHT_N 8 // 权重表新数据在低位旧数据在高位和为256用整数近似 static const uint16_t weight_table[W_WEIGHT_N] {128, 64, 32, 16, 8, 4, 2, 2}; static int16_t history[W_WEIGHT_N]; static uint8_t w_index; int16_t filter_weighted_average(int16_t new_value) { int32_t acc 0; int i; history[w_index] new_value; for (i 0; i W_WEIGHT_N; i) { uint8_t pos (w_index - i W_WEIGHT_N) % W_WEIGHT_N; acc (int32_t)history[pos] * weight_table[i]; } w_index (w_index 1) % W_WEIGHT_N; return (int16_t)(acc 8); // 权重和为256右移8位即除法 }这种实现把除法换成位移现场MCU上跑起来更省资源。加权滑动平均的局限是如果脉冲干扰恰好出现在最近的新数据上高权重会让结果瞬间被拉偏。所以它适合跟随性要求高、且信号本身没有剧烈尖峰的场所比如连续退火炉的炉温控制、电机的扭矩反馈。如果现场脉冲干扰频繁建议先过一道限幅再进加权平均。3.3 一阶滞后滤波用一个参数模拟RC电路一阶滞后滤波在模拟时代就是RC低通电路——电容充放电把电压波动抹平。数字化之后它的表达式只有一行// alpha 滤波系数0~1之间 // 当前输出 alpha * 当前采样 (1 - alpha) * 上一拍输出 output alpha * new_value (1.0f - alpha) * prev_output;alpha越大新数据占比越高响应越快平滑效果越弱alpha越小曲线越平滞后越大。它和滑动平均的本质区别在于滑动平均的记忆长度是固定的一阶滞后理论上记住的是全部历史只是越久远的占比越小服从指数衰减。alpha的标定有一个跟采样周期挂钩的经验式设采样周期为Ts你希望滤掉频率高于Fc的干扰那么alpha Ts / (Ts 1/(2πFc))。举个例子采样周期10ms希望截止频率5Hzalpha 0.01 / (0.01 1/(2π×5)) ≈ 0.24。这个系数再乘以0.5到1之间调优基本就能用。一阶滞后的优点在于只有一个参数、代码量极小、实时性比滑动平均好——因为它没有窗口概念每个点一到立刻更新。缺点也很明确对脉冲尖峰的抑制能力有限一个大尖峰会以alpha的比例漏一部分到输出里另外存在固有滞后参数压得越狠滞后越严重。在要求响应快的压力闭环里alpha严禁压到0.1以下否则系统会变得软绵绵。4. 复杂工况的进阶打法复合滤波、一维卡尔曼与IIR低通4.1 中位值平均滤波脉冲随机噪声一起压现场最讨厌的是脉冲干扰和随机噪声同时存在。单独套中值随机噪声还留着一大半单独套平均脉冲又会污染结果。所以就有了中位值平均滤波先连续采N个点去掉最大值和最小值剩下的取平均。等于先用去极值掐掉脉冲再用平均压随机噪声。#define MAV_N 12 int16_t filter_median_average(int16_t sample_buf[]) { int32_t sum 0; int16_t min_val 32767, max_val -32768; int i; for (i 0; i MAV_N; i) { sum sample_buf[i]; if (sample_buf[i] min_val) min_val sample_buf[i]; if (sample_buf[i] max_val) max_val sample_buf[i]; } sum - min_val max_val; return (int16_t)(sum / (MAV_N - 2)); }N的取值一般在6到12之间。太小去极值后剩下的样本太少平均效果差太大实时性吃亏。这个算法在化工罐区的液位、压力变送器信号上表现不错因为这些场合既有现场电磁干扰又有介质流动造成的随机波动。但要注意如果一帧数据里出现两个以上的大幅脉冲去掉了最大最小值之后第二个脉冲还是会被平均进去。所以它对付的是偶发单脉冲场景如果现场干扰特别密集就得先限幅或加重中值。4.2 限幅平均滤波先砍掉异常值再做平均限幅平均滤波是另一种复合思路先对每个新采样做限幅判断如果与上次合法值偏差超过阈值就丢弃然后用连续N个合法值做平均。它比限幅单点输出多了一道平均比中位值平均更适应连续多个脉冲的场合——限幅判断本身是逐点拦截的。#define LA_LIMIT 40 #define LA_N 10 typedef struct { int16_t valid_buf[LA_N]; uint8_t count; int16_t last_valid; int32_t sum; } LimitAverFilter; int16_t filter_limit_average(LimitAverFilter *f, int16_t new_value) { if ((new_value - f-last_valid LA_LIMIT) || (f-last_valid - new_value LA_LIMIT)) { return f-last_valid; // 这拍当干扰丢掉顺带输出旧值 } // 把新合法值推入平均窗口 if (f-count LA_N) { f-sum - f-valid_buf[0]; for (int i 1; i LA_N; i) { f-valid_buf[i - 1] f-valid_buf[i]; } f-valid_buf[LA_N - 1] new_value; f-sum new_value; } else { f-valid_buf[f-count] new_value; f-sum new_value; } f-last_valid new_value; return (int16_t)(f-sum / f-count); }这个算法写起来比中值平均复杂一点但好处是限幅保证了进入平均窗口的都是合理值不至于出现一个巨大脉冲把平均结果推歪。它很适合PLC读取4-20mA模拟量然后做PID控制的那种场景——限幅挡大毛刺平均压小噪声且维持每个周期都有输出。4.3 一维卡尔曼滤波延时最低的平滑方案卡尔曼滤波听起来很高大上实际上在工控里最常用的是一维形式也就是只处理一个变量。它最吸引人的地方在于它不是简单地对过去做平均而是每一拍都做预测校正输出的估计值理论上滞后最小、方差最小。白话解释它的运作假设信号真值缓慢变化你上一拍估计出一个值这一拍它应该还在那附近预测。来了一个测量值带噪声。你算一个增益KK大的时候信任测量多一些K小的时候信任预测多一些。这个K不是拍脑袋定的而是根据你对噪声的统计量自动调整的。typedef struct { float x; // 当前状态估计值 float p; // 当前估计误差协方差 float q; // 过程噪声方差越小越平滑 float r; // 测量噪声方差越大越平滑 } Kalman1D; void kalman_init(Kalman1D *k, float init_value) { k-x init_value; k-p 1.0f; k-q 0.001f; // 起步经验值后面要调 k-r 0.05f; // 根据传感器实测方差标定 } float kalman_update(Kalman1D *k, float z) { // 预测真值不变误差协方差累加过程噪声 float p_pred k-p k-q; // 更新计算卡尔曼增益 float kg p_pred / (p_pred k-r); // 校正用新测量值修正估计 k-x k-x kg * (z - k-x); k-p (1.0f - kg) * p_pred; return k-x; }两个关键参数q和r的物理意义要搞懂。q代表真值本身的变化剧烈程度q设得大滤波器就愿意相信新测量值响应快但平滑弱r代表测量噪声的强度r设得大滤波器觉得测量值不可靠更依赖自己的预测平滑强但滞后也大。一个实用的初始标定方法让传感器静止不动采集几百个点算方差这个方差就是rq先取r的千分之一然后按实际响应速度微调。我拿卡尔曼滤过热电偶温度、激光测距仪的液位、振动传感器的位移效果都比滑动平均好——尤其在响应速度上肉眼可见的差异。代价是需要浮点运算8位单片机上跑会吃力Cortex-M系列则毫无压力。4.4 二阶IIR巴特沃斯低通频率域思路的降维打击前几种算法都在时域里折腾数据IIR滤波器的思路是直接在频率域画一个响应曲线低于截止频率的保留高于截止频率的按斜率衰减。最常用的是二阶巴特沃斯低通它比一阶滞后滚降更陡对高频干扰衰减更猛同时相位滞后又比高阶滤波器温和。这里给一个可以直接套用的biquad双二阶结构实现。系数在初始化时根据采样率和截止频率算好运行时只做乘加。typedef struct { float b0, b1, b2; float a1, a2; float x1, x2, y1, y2; } BiquadLPF; // 初始化二阶巴特沃斯低通 // Fs: 采样率(Hz) Fc: 截止频率(Hz) void biquad_lpf_init(BiquadLPF *f, float Fs, float Fc) { float K tanf(3.14159265f * Fc / Fs); float norm 1.0f / (1.0f 1.41421356f * K K * K); f-b0 K * K * norm; f-b1 2.0f * f-b0; f-b2 f-b0; f-a1 2.0f * (K * K - 1.0f) * norm; f-a2 (1.0f - 1.41421356f * K K * K) * norm; f-x1 f-x2 f-y1 f-y2 0.0f; } float biquad_lpf_process(BiquadLPF *f, float x) { float y f-b0 * x f-b1 * f-x1 f-b2 * f-x2 - f-a1 * f-y1 - f-a2 * f-y2; f-x2 f-x1; f-x1 x; f-y2 f-y1; f-y1 y; return y; }截止频率的选择是核心。一个常见的错误是把Fc定得太低导致系统阶跃响应变得软绵绵。折中经验是Fc取信号真实带宽的3到5倍比如你关心的是0到2Hz的工艺变化Fc给6到10Hz就够不需要压到1Hz。另外IIR滤波器有相位滞后的本质闭环控制里如果滞后太大会降低相位裕度这个我在下一章展开讲。5. 实战选型照着干扰形态选算法别靠感觉5.1 现场三步给信号画像选型之前先干一件事把原始采样值完整地录下来画成波形。很多PLC或采集设备有历史趋势功能直接导出CSV在电脑上回放。看波形就盯三件事毛刺宽度尖峰只占一个采样点还是连续好几个拍占一个点限幅/中值有效连续好几拍要考虑限幅平均或加大中值窗口。抖动频率噪声是高频草皮还是低频摆动高频草皮用平均或低通低频摆动要用卡尔曼或者检查是不是传感器安装本身的问题。趋势漂移整体是不是在缓慢爬坡如果是任何大窗口平均都会严重滞后这时候一阶滞后/卡尔曼更合适。没有波形数据就凭经验猜十有八九选错。我见过有人把称重信号滤波调了三天最后发现是屏蔽层没接地滤波算法在这种物理干扰面前只能算创可贴。5.2 十种算法选型对照表下面这张表我贴了无数次现场调试时直接对着查算法主要对付干扰附带能力最大代价实时性内存开销典型场景限幅滤波单点尖峰无误杀真实跳变最高极小PLC模拟量入口保护中位值滤波偶发脉冲无压掉真实快变中等中称重、流量、压力跳字算术平均滤波随机噪声无采样周期拉长低极小慢速温度、液位滑动平均滤波随机噪声可匹配周期纹波窗口越大越迟钝中等小通用的数据平滑加权滑动平均随机噪声响应更快脉冲污染风险较高小对跟随性有要求的过程量一阶滞后滤波高频噪声一个参数调平滑有相位滞后较高极小电机电流、变频器反馈中位值平均滤波脉冲随机噪声去极值再平均连续多脉冲失效中等中化工罐区的液位压力限幅平均滤波密集尖峰噪声逐点拦截后平均代码稍复杂中等小4-20mA信号进PID一维卡尔曼滤波漂移噪声滞后最小参数标定有门槛较高中精密测温、液位、振动二阶IIR低通周期性纹波及高频频率选择性强需要算系数有滞后高中电源纹波、载波干扰5.3 参数怎么起步一组不容易翻车的初始值参数标定没有万能公式但有几个长期积累的靠谱起点限幅阈值记录正常工况下信号最大变化速率乘以采样周期再乘1.5到2。这是下限先尝到甜头再往下收。滑动平均窗口在采样率除以信号感兴趣最高频率的5到10倍之间起步。比如采样100Hz、关心5Hz变化窗口对10到20比较合理。一阶滞后alpha先按截止频率信号带宽的10倍算出来然后往下调调到曲线平滑度和响应速度都能接受为止。卡尔曼q/rr拿传感器静止方差实测q从r的千分之一起步逐级加加到你发现噪声开始漏进来为止再退回一档。这些初始值的共同原则是从偏迟钝、偏平滑的一侧开始逐步放松。因为现场常见的投诉是数值跳而不是响应慢先让曲线漂亮起来再慢慢提升响应速度调试过程会顺得多。6. 滤波翻车实录滞后、台阶、算力与启动时的假跳变6.1 温度曲线平得像直线PID却发散——滞后惹的祸有个温控项目现场工程师把滑动平均窗口从8一路调到64温度曲线在趋势图上漂亮得像一条直线。结果温度闭环开始震荡怎么整定PID参数都压不住。原因很简单滤波滞后等于在反馈通道里塞了一个大惯性环节控制器看到的温度永远是过去的温度它会认为升温太慢持续加大输出等真实温度追上估计值时已经过冲——这就是典型的滤波引发的控制发散。闭环系统里用滤波一定要量化滞后。最简单的测试办法给信号输入端叠加一个阶跃比如把设定值调高5℃统计从阶跃发生到滤波输出到达63.2%的时间这个时间最好小于系统主时间常数的十分之一。超过这个量级滤波就是来帮倒忙的。6.2 开机前几百毫秒的假跳变缓冲区没填满滑动平均、中位值平均这类带窗口的算法上电瞬间缓冲区全是零。如果直接起算平均值输出会从0慢慢爬向真实值看起来像信号突变。这个问题很隐蔽因为很多设备上电后本来就有初始化过程但如果你拿这个爬坡当真实信号触发报警就可能误报。解决办法有几种最简单的是一开始把缓冲区填满第一次有效采样值或者在窗口未填满前输出直接用当前采样值透传等填满再切换更规范的做法是上电后给滤波一个预热期期间只采集不参与逻辑判断。我一般习惯用第一种省事且有效。6.3 单片机浮点算力不够怎么办一阶滞后、卡尔曼、IIR都要浮点运算普通51单片机跑起来捉襟见肘。现场有两个变通思路一是用定点数近似比如把alpha放大成整数再用位移截断上面加权滑动平均那种右移8位的写法就是典型二是能不用浮点就别用改变算法组合——比如用限幅中位值平均就能解决大部分现场干扰没必要硬上卡尔曼。Cortex-M3及以上跑单路浮点滤波器毫无压力但你如果在一颗只有2KB RAM的小单片机上滤波RAM也要算账。滑动平均一个窗口16点就要32字节卡尔曼一个实例才20字节左右IIR更是只要6个状态变量。内存紧张时优先选IIR或卡尔曼这类状态量少的方案。6.4 一级不够串两级的误区有同事在信号链路里串了三层平均滤波效果还是不好。多层串联的后果不是更平滑而是滞后叠加、波形畸变。每加一级平均相位滞后就加一截而且两级相同截止频率的低通串联后实际截止频率会下移越串越钝。正确的做法是不同职责的滤波串联最前面限幅拦尖峰中间中值或平均去毛刺最后卡尔曼或一阶滞后做平滑每一级干一件事不要重复劳动。我经常推荐的组合是限幅→滑动平均→一阶滞后这个组合对付大多数模拟量现场都够用。6.5 现场验收滤波效果的两个笨办法滤波调没调好别只看趋势图平不平。我给你两个笨但有效的验收手段第一个是阶跃响应测试在信号源端短接或切换到一个已知跳变看滤波输出从旧值过渡到新值需要多少拍这决定了系统的响应速度。第二个是噪声衰减比测试让传感器处于稳定状态记录滤波前后的标准差算一下压缩比。随机噪声能压到1/10就算合格压到1/20以上说明参数已经偏激进响应会受影响。这两个测试结合起来既能量化滞后又能评估平滑度比凭感觉看曲线靠谱得多。我在现场给很多工程师演示过这种方法十分钟就能判断一个滤波方案能不能用。最后再说一个我自己踩过多次的坑滤波参数要跟采样周期绑定别单独存窗口大小而不关心采样率。同样的窗口长度采样率从10Hz改成100Hz实际滞后差了10倍。每次调完程序记得在注释里把采样率、截止频率、窗口对应的物理时间写清楚。过几个月回来维护你会感谢当时的自己。
阅读完成 · 觉得有帮助?