JavaScript如何正确实现低通滤波器?代码返回NaN问题排查
JavaScript 正确实现低通滤波器的方法
你第一版代码返回NaN的核心原因:声明grav_accelX、grav_accelY、grav_accelZ的同一行就引用了变量自身,此时变量仅完成声明、未完成赋值,初始值为undefined,数值运算中undefined会被转换为NaN,后续所有计算结果自然全部为NaN。
你修改后的第二版代码逻辑是错误的,不属于低通滤波器实现:代码每次仅对当前输入值做两次乘法运算,完全没有保留历史输出值做平滑加权,最终输出永远是当前输入值的固定倍数,根本起不到过滤高频信号的作用。
正确实现逻辑
你最初写的滤波公式本身是传感器数据处理领域非常通用的一阶低通滤波公式,逻辑完全正确:
滤波后输出 = 当前输入值 * 滤波系数 + 上一次滤波输出值 * (1 - 滤波系数)
实现时只要满足两个核心要求即可:
- 滤波系数
kFilteringFactor取值范围为01:系数越小,滤波截止频率越低,输出平滑效果越强,信号响应延迟越高;系数越大,输出越贴近原始输入,平滑效果越弱。如果是从加速度计数据中分离重力分量,通常系数取0.10.3区间即可,你之前设置的0.9几乎没有平滑效果。 - 存储上一次滤波输出的变量必须在计算逻辑外部持久声明、初始化,不能在每次计算时重新声明,否则会丢失历史值。
可直接复用的代码示例
// 滤波系数,根据实际平滑需求调整 const kFilteringFactor = 0.1; // 提前初始化存储历史滤波结果的变量,初始值可设为0,也可直接用第一次读取的传感器值做初始值加快收敛 let grav_accelX = 0; let grav_accelY = 0; let grav_accelZ = 0; /** * 每次读取到新的加速度数据时调用,更新滤波后的重力分量 * @param {{x: number, y: number, z: number}} acceleration 原始加速度读数 * @returns {{x: number, y: number, z: number}} 滤波后分离出的重力分量 */ function updateLowPassFilter(acceleration) { grav_accelX = acceleration.x * kFilteringFactor + grav_accelX * (1.0 - kFilteringFactor); grav_accelY = acceleration.y * kFilteringFactor + grav_accelY * (1.0 - kFilteringFactor); grav_accelZ = acceleration.z * kFilteringFactor + grav_accelZ * (1.0 - kFilteringFactor); return { x: grav_accelX, y: grav_accelY, z: grav_accelZ }; }
如果需要获取去除重力后的线性加速度,直接用原始加速度值减去滤波得到的重力分量即可。
常见注意事项
- 不要在每次执行滤波计算的函数内部重新声明存储历史值的变量,否则变量会被反复重置,既可能出现
NaN问题,也完全无法实现滤波效果 - 若将历史值初始化为0,程序启动后的前几帧输出会有短暂的收敛爬升过程,如果需要跳过这个过程,直接将第一次读取到的加速度原始值赋值给三个历史变量即可
- 滤波系数不要设置过大或过小:过小会导致信号响应严重滞后,过大则无法过滤高频抖动噪声,需要根据实际采样频率和业务需求调试到合适值
内容的提问来源于stack exchange,提问作者BGTabulation BGTabulate
相关产品推荐
相关产品推荐

