当前位置: 首页 > news >正文

使用Rust原生实现小波卡尔曼滤波算法

一、算法原理概述

  1. 小波变换(Wavelet Transform)

    • 通过多尺度分解将信号分为高频(细节)和低频(近似)部分,高频通常包含噪声,低频保留主体信息。
    • 使用Haar小波(计算高效)进行快速分解与重构:
      // Haar小波分解公式
      approx = (x[2i] + x[2i+1]) / 2.0;
      detail = (x[2i] - x[2i+1]) / 2.0;
      
  2. 卡尔曼滤波(Kalman Filter)

    • 预测-更新两阶段递归估计[citation:5][citation:6]:
      • 预测:基于状态方程预估当前状态和误差协方差

        Xpred=A⋅Xprev+B⋅uPpred=A⋅Pprev⋅AT+QXpred​=A⋅Xprev​+B⋅uPpred​=A⋅Pprev​⋅AT+Q

      • 更新:结合观测值修正预测值,计算卡尔曼增益K

        K=Ppred⋅HT/(H⋅Ppred⋅HT+R)Xnew=Xpred+K⋅(z−H⋅Xpred)Pnew=(I−K⋅H)⋅PpredK=Ppred​⋅HT/(H⋅Ppred​⋅HT+R)Xnew​=Xpred​+K⋅(z−H⋅Xpred​)Pnew​=(I−K⋅H)⋅Ppred​

  3. 小波卡尔曼融合

    • 先对原始信号小波分解,对不同频段独立应用卡尔曼滤波,最后重构信号
    • 高频部分使用更高测量噪声协方差R(抑制噪声),低频部分使用更低R(保留主体)。

二、Rust实现代码

cargo.toml
[package]
name = "wavelet-kalman-filter"
version = "0.1.0"
edition = "2021"[dependencies]
plotters = "0.3.5"
rand = "0.8.5"
log = "0.4.17"
simple_logger = "5.0.0"
main.rs
use log::{info};
use log::LevelFilter;
use simple_logger::SimpleLogger;// 初始化日志记录,将日志保存到文件
fn init_logger() {SimpleLogger::new().with_level(LevelFilter::Info).with_utc_timestamps().init().expect("Failed to initialize logger");info!("日志系统初始化完成");
}// 主结构体
pub struct WaveletKalmanFilter {pub a: f64,      // 状态转移系数(如匀速运动时A=1)pub q: f64,      // 过程噪声协方差pub r_low: f64,  // 低频观测噪声协方差pub r_high: f64, // 高频观测噪声协方差pub state: f64,  // 当前状态估计pub cov: f64,    // 当前误差协方差
}// 一维Haar小波分解(返回低频近似 + 高频细节)
pub fn haar_decompose(signal: &[f64]) -> (Vec<f64>, Vec<f64>) {info!("开始Haar小波分解,输入信号长度: {}", signal.len());// 对信号进行对称延拓,以缓解小波分析的边界问题fn symmetric_extend(signal: &[f64]) -> Vec<f64> {if signal.len() <= 1 {info!("信号长度小于等于1,直接返回原信号");return signal.to_vec();}let mut extended = Vec::new();// 左侧对称部分for i in (1..=signal.len() - 1).rev() {extended.push(signal[i]);}// 原始信号部分extended.extend_from_slice(signal);// 右侧对称部分for i in 1..signal.len() {extended.push(signal[signal.len() - 1 - i]);}info!("对称延拓后信号长度: {} 信号内容: {:?}", extended.len(), extended);extended}// 对延拓后的信号进行Haar小波分解pub fn haar_decompose(signal: &[f64]) -> (Vec<f64>, Vec<f64>) {let extended = symmetric_extend(signal);let mut approx = Vec::new();let mut detail = Vec::new();for i in (0..extended.len()).step_by(2) {let sum = extended[i] + extended.get(i + 1).unwrap_or(&0.0);let diff = extended[i] - extended.get(i + 1).unwrap_or(&0.0);approx.push(sum / 2.0);detail.push(diff / 2.0);}// 截取与原始信号分解后相同长度的结果let half_len = (signal.len() + 1) / 2;let approx = approx[extended.len() / 4..extended.len() / 4 + half_len].to_vec();let detail = detail[extended.len() / 4..extended.len() / 4 + half_len].to_vec();info!("延拓后Haar分解完成,近似分量长度: {}, 细节分量长度: {}",approx.len(),detail.len());(approx, detail)}let mut approx = Vec::new();let mut detail = Vec::new();for i in (0..signal.len()).step_by(2) {let sum = signal[i] + signal.get(i + 1).unwrap_or(&0.0);let diff = signal[i] - signal.get(i + 1).unwrap_or(&0.0);approx.push(sum / 2.0);detail.push(diff / 2.0);}info!("直接Haar分解完成,近似分量长度: {}, 细节分量长度: {}",approx.len(),detail.len());(approx, detail)
}// 一维Haar小波重构
pub fn haar_recompose(approx: &[f64], detail: &[f64]) -> Vec<f64> {info!("开始Haar小波重构,近似分量长度: {}, 细节分量长度: {}",approx.len(),detail.len());let mut output = Vec::with_capacity(approx.len() * 2);for i in 0..approx.len() {output.push(approx[i] + detail[i]);output.push(approx[i] - detail[i]);}info!("Haar小波重构完成,输出信号长度: {}", output.len());output
}impl WaveletKalmanFilter {// 初始化滤波器pub fn new(a: f64, q: f64, r_low: f64, r_high: f64) -> Self {info!("创建新的WaveletKalmanFilter,a: {}, q: {}, r_low: {}, r_high: {}",a, q, r_low, r_high);WaveletKalmanFilter {a,q,r_low,r_high,state: 0.0,cov: 1.0, // 初始协方差设为较大值(表示不确定性高)}}// 单步预测pub fn predict(&mut self) {info!("执行单步预测前,状态: {}, 协方差: {}", self.state, self.cov);self.state = self.a * self.state; // X_pred = A * X_prevself.cov = self.a * self.cov * self.a + self.q; // P_pred = A*P*A^T + Qinfo!("执行单步预测后,状态: {}, 协方差: {}", self.state, self.cov);}// 单步更新(根据频段选择R)pub fn update(&mut self, measurement: f64, is_low_freq: bool) {// info!(//     "执行单步更新前,测量值: {}, 是否低频: {}",//     measurement, is_low_freq// );let r = if is_low_freq { self.r_low } else { self.r_high };let k = self.cov / (self.cov + r); // 卡尔曼增益Kself.state += k * (measurement - self.state); // X_new = X_pred + K*(z - H*X_pred)self.cov = (1.0 - k) * self.cov; // P_new = (I - K*H)*P_predinfo!("执行单步更新后,状态: {}, 协方差: {}", self.state, self.cov);}
}pub fn wavelet_kalman_filter(signal: &[f64],levels: usize, // 小波分解层数a: f64,        // 状态转移系数q: f64,        // 过程噪声r_low: f64,    // 低频观测噪声r_high: f64,   // 高频观测噪声
) -> Vec<f64> {info!("开始小波卡尔曼滤波,输入信号长度: {}, 分解层数: {}",signal.len(),levels);// 1. 递归小波分解(多尺度)let mut approx = signal.to_vec();let mut details = Vec::new();for level in 0..levels {info!("第 {} 层小波分解", level + 1);let (a, d) = haar_decompose(&approx);details.push(d);approx = a;}// 2. 对各频段独立应用卡尔曼滤波let mut kalman = WaveletKalmanFilter::new(a, q, r_low, r_high);kalman.state = approx[0]; // 初始化状态// 低频滤波(R较小,信任观测值)info!("开始低频滤波,近似分量长度: {}", approx.len());for i in 0..approx.len() {info!("低频滤波第 {} 步", i + 1);kalman.predict();kalman.update(approx[i], true); // 标记为低频approx[i] = kalman.state;}// 高频滤波(R较大,抑制噪声)info!("开始高频滤波,细节分量数量: {}", details.len());for (level, d) in details.iter_mut().enumerate() {info!("第 {} 层细节分量滤波,长度: {}", level + 1, d.len());kalman = WaveletKalmanFilter::new(a, q, r_low, r_high); // 重置滤波器kalman.state = d[0];for i in 0..d.len() {info!("第 {} 层细节分量第 {} 步滤波", level + 1, i + 1);kalman.predict();kalman.update(d[i], false); // 标记为高频d[i] = kalman.state;}}// 3. 小波重构info!("开始小波重构,分解层数: {}", levels);for _ in 0..levels {approx = haar_recompose(&approx, &details.pop().unwrap());}info!("小波卡尔曼滤波完成,输出信号长度: {}", approx.len());approx
}// 绘图函数实现
fn draw_signals(clean: &[f64],noisy: &[f64],filtered: &[f64],
) -> Result<(), Box<dyn std::error::Error>> {info!("开始绘制信号图,原始信号长度: {}, 含噪信号长度: {}, 滤波信号长度: {}",clean.len(),noisy.len(),filtered.len());use plotters::prelude::*;let root = BitMapBackend::new("signals.png", (1024, 768)).into_drawing_area();root.fill(&WHITE)?;let mut chart = ChartBuilder::on(&root).caption("信号处理结果", ("sans-serif", 50).into_font()).margin(10).x_label_area_size(30).y_label_area_size(30).build_cartesian_2d(0f64..clean.len() as f64, -2f64..2f64)?;chart.configure_mesh().draw()?;chart.draw_series(LineSeries::new(clean.iter().enumerate().map(|(i, &y)| (i as f64, y)),&RED,))?.label("原始信号").legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));chart.draw_series(LineSeries::new(noisy.iter().enumerate().map(|(i, &y)| (i as f64, y)),&BLUE,))?.label("含噪信号").legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE));chart.draw_series(LineSeries::new(filtered.iter().enumerate().map(|(i, &y)| (i as f64, y)),&GREEN,))?.label("滤波信号").legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &GREEN));chart.configure_series_labels().background_style(&WHITE.mix(0.8)).border_style(&BLACK).draw()?;info!("信号图绘制完成,保存至 signals.png");Ok(())
}// 测试函数:添加高斯噪声的信号滤波
fn test_noisy_sine() {info!("开始测试含噪正弦信号滤波");let clean_signal: Vec<_> = (0..1000).map(|i| (i as f64 * 0.1).sin()).collect();let noisy_signal: Vec<_> = clean_signal.iter().map(|x| x + rand::random::<f64>()).collect();let filtered = wavelet_kalman_filter(&noisy_signal, 3, 1.0, 0.01, 0.1, 2.0);// 绘图比较(使用plotters库)draw_signals(&clean_signal, &noisy_signal, &filtered);info!("含噪正弦信号滤波测试完成");
}// 主函数
fn main() {init_logger();info!("程序启动");test_noisy_sine();info!("程序结束");
}

http://www.lryc.cn/news/578359.html

相关文章:

  • 408第三季part1 - 操作系统 - 基本分页
  • 算法赋能管理:工厂安全与效率双突破
  • 【仿muduo库实现并发服务器】Channel模块
  • 回转体航行器控制系统中深度控制与俯仰姿态控制的解耦策略
  • 基于springboot的养老院管理系统
  • C# Linq to XML 详解:强大的XML处理工具
  • (自用)Java学习-5.21(支付宝沙箱支付、Vue总结)
  • 插入排序解析
  • sqlmap学习笔记ing(1.Easy_SQLi(时间,表单注入))
  • Django打造智能Web机器人控制平台
  • HarmonyOS应用开发高级认证知识点梳理 (一) 布局与样式
  • 记本好书:矩阵力量:线性代数全彩图解+微课+Python编程
  • 深蓝海域承建某大型保险集团产险知识库升级项目
  • 主流零信任安全产品深度介绍
  • 11OAuth2
  • 从零到一搭建远程图像生成系统:Stable Diffusion 3.5+内网穿透技术深度实战
  • 【深度学习1】ModernBert学习
  • 发布/订阅模式:解耦系统的强大设计模式
  • Spring Boot 集成 Dufs 通过 WebDAV 实现文件管理
  • 从零到一:VNC+内网穿透技术搭建企业级远程控制系统的完整路径
  • ubuntu系统安装docker 和 mongdb,YaPi(包含中间过程不能拉去依赖问题)
  • langchain从入门到精通(三十二)——RAG优化策略(八)自查询检索器实现动态数据过滤
  • 自由学习记录(66)
  • 聚观早报 | 知乎直答新升级;特斯拉V4超级充电桩首批上线;苹果将推出廉价版Macbook
  • 缓存系统-淘汰策略
  • 边缘人工智能与医疗AI融合发展路径:技术融合与应用前景(下)
  • 定时器的设计
  • 借助飞算AI新手小白快速入门Java实操记录
  • 25-7-1 论文学习(1)- Fractal Generative Models 何恺明大佬的论文
  • 分布式爬虫数据存储开发实战