动态调整 K,就是为了打破固定系数 "平稳与灵敏度不可兼得" 的矛盾
动态K的运用 不存在于 高通滤波中(目标相反,不能混用!)动态 K 要 "稳变化、跟平稳" 高通要 "留变化、去平稳"
动态 K 是为了 "稳",高通是为了 "抓变";一个要静,一个要动,天生不能一起用。

目录
[1. 趋势计数(dir_cnt)](#1. 趋势计数(dir_cnt))
[2. 变化幅度(diff)](#2. 变化幅度(diff))
[3.这两参数,直接影响 K 的变化率](#3.这两参数,直接影响 K 的变化率)
为何要动态调整系数K:
因为固定 K 永远做不到:既不抖动、又不滞后、又能跟趋势!
- K 太大 → 反应快,但毛刺、抖动压不住
- K 太小 → 很平稳,但严重滞后、跟不上真实变化
- 无论怎么调,只能二选一,无法兼顾
动态 K = 让滤波自己变聪明,该稳就稳、该快就快。
动态 K 做了一件固定 K 做不到的事:
- 数据稳定 / 抖动时
K 自动变小 → 输出纹丝不动,抗干扰极强
- 数据持续上涨 / 下跌(真实趋势)
K 自动变大 → 输出立刻跟上,不滞后、不拖尾
- 数据快速跳变
K 加速变大
动态K滤波原理:
动态 K 滤波对比固定(静态)K 一阶滤波 ,核心是增加了对滤波系数 K 的动态调整逻辑模块
动态 K 滤波 对比 静态 K 滤波,核心就多了两个东西:1. 趋势计数(dir_cnt)
判断是不是连续涨 / 连续跌 → 决定 K 要不要开始变大
2. 变化幅度(diff)
判断变化大不大 → 决定 K 变大的速度有多快
3.这两参数,直接影响 K 的变化率
① 改 趋势计数
dir_cnt > 1→ K 启动更快
dir_cnt > 3→ K 启动更慢② 改 变化幅度判断
diff > 0.2→ 稍微一动就加速 K
diff > 1.0→ 必须很大变化才加速 K③ 改 K 增加的步长
K += 0.25→ K 涨得飞快
K += 0.05→ K 涨得很慢
cppfloat diff = now_val - last_out; // 当前值与滤波输出差值 int is_same_dir; // 判断:本次变化 和 上一次变化 是否【同向】 is_same_dir = ((now_val > last_out) && (last_val > last_out)) || ((now_val < last_out) && (last_val < last_out)); // ==================== 动态调整 K ==================== if (is_same_dir) { dir_cnt++; // 同向 = 真实趋势,加速响应 if (dir_cnt > 1)// 判断数据变化幅度:变化大则K多涨,变化小则K少涨 { K += (diff > 0.5f || diff < -0.5f) ? 0.15f : 0.05f; } } else { dir_cnt = 0; // 抖动/反向 = 防抖 K = 0.1f; // 系数重置变小 } // K 限制范围(防止太灵敏/太迟钝) if (K > 0.8f) K = 0.8f; if (K < 0.05f) K = 0.05f;
C代码:
cpp#include <stdio.h> // ==================== 动态滤波核心参数 ==================== float last_out = 0.0f; // 上一次滤波输出 float last_val = 0.0f; // 上一次原始值 float K = 0.1f; // 初始系数(会自动变) int dir_cnt = 0; // 同向趋势计数 // 初始化 void dynamic_filter_init(float val) { last_out = val; last_val = val; K = 0.1f; dir_cnt = 0; } // ==================== 动态K一阶滤波(核心函数) ==================== float dynamic_filter(float now_val) { float diff = now_val - last_out; // 当前值与滤波输出差值 int is_same_dir; // 判断:本次变化 和 上一次变化 是否【同向】 is_same_dir = ((now_val > last_out) && (last_val > last_out)) || ((now_val < last_out) && (last_val < last_out)); // ==================== 动态调整 K ==================== if (is_same_dir) { dir_cnt++; // 同向 = 真实趋势,加速响应 if (dir_cnt > 1)// 判断数据变化幅度:变化大则K多涨,变化小则K少涨 { K += (diff > 0.5f || diff < -0.5f) ? 0.15f : 0.05f; } /* K += (diff > 0.5f || diff < -0.5f) ? 0.15f : 0.05f; 等效的if else 语句如下: if (diff > 0.5f || diff < -0.5f) { K = K + 0.15f; // 变化幅度大(快速趋势/跳变),K猛加,提升灵敏度 } else { K = K + 0.05f; // 变化幅度小(平稳慢变),K少加,保持平稳性 } */ } else { dir_cnt = 0; // 抖动/反向 = 防抖 K = 0.1f; // 系数重置变小 } // K 限制范围(防止太灵敏/太迟钝) if (K > 0.8f) K = 0.8f; if (K < 0.05f) K = 0.05f; // ==================== 一阶滤波公式 ==================== float out = K * now_val + (1.0f - K) * last_out; // 更新历史值 last_val = now_val; last_out = out; return out; } // ==================== 测试(用50个趋势+毛刺数据) ==================== int main(void) { // 你的50个带趋势+毛刺数据 float data[50] = { 10.00,10.05,99.90,10.10,10.15, 10.20,10.25,88.80,10.30,10.35, 10.40,10.45,77.70,10.50,10.55, 10.60,10.65,66.60,10.70,10.75, 10.80,10.85,55.50,10.90,10.95, 11.00,11.10,44.40,11.15,11.20, 11.25,11.30,33.30,11.35,11.40, 11.50,11.60,22.20,11.70,11.80, 11.90,12.00,12.05,12.10,12.15, 12.20,12.30,12.35,12.40,12.50 }; dynamic_filter_init(data[0]); printf("序号\t原始数据\t动态滤波输出\n"); printf("-----------------------------------------\n"); for(int i=0; i<50; i++) { float res = dynamic_filter(data[i]); printf("%2d\t%.2f\t\t%.2f\n", i+1, data[i], res); } return 0; }
