使用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.pswp.cn/bicheng/87493.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/87493.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode 3304. 找出第 K 个字符 I 简单

Alice 和 Bob 正在玩一个游戏。最初&#xff0c;Alice 有一个字符串 word "a"。 给定一个正整数 k。 现在 Bob 会要求 Alice 执行以下操作 无限次 : 将 word 中的每个字符 更改 为英文字母表中的 下一个 字符来生成一个新字符串&#xff0c;并将其 追加 到原始的…

数字人分身+矩阵系统聚合+碰一碰发视频: 源码搭建-支持OEM

以下是关于数字人分身、矩阵系统聚合及碰一碰发视频功能的源码搭建与OEM支持的方案整理&#xff1a;核心技术模块数字人分身技术 使用深度学习框架&#xff08;如PyTorch或TensorFlow&#xff09;训练生成对抗网络&#xff08;GAN&#xff09;或变分自编码器&#xff08;VAE&am…

【LeetCode 热题 100】189. 轮转数组——(解法一)额外数组

Problem: 189. 轮转数组 题目&#xff1a;给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 文章目录 整体思路完整代码时空复杂度时间复杂度&#xff1a;O(N)空间复杂度&#xff1a;O(N) 整体思路 这段代码旨在解决一个经典的…

【PyCharm 2025.1.2配置debug】

大家先看下我的配置 1.调试配置 选择 FastAPI 框架名称-》 自定义应用程序文件&#xff1a;必须选择当前项目的main.pyUvicorn 选项&#xff1a;这是启动命令&#xff0c;有第三步的选择 main.py 所以只需要–reload即可&#xff0c;如果想自定义启动端口补充–port xxxxPytho…

Python数据库软件:查询与预测功能集成系统

Python数据库软件:查询与预测功能集成系统 概述 本文将详细介绍一个具备查询和模型预测功能的Python数据库软件的设计与实现。该系统基于Python开发,使用Excel作为数据存储格式,包含约15个功能页面,支持数据管理、查询分析、模型预测等核心功能。 系统架构 技术栈 核心…

什么是持续集成/持续交付(CI/CD)?

基本概念 CI/CD旨在通过自动化流程提高代码质量、加快发布速度 CI &#xff08;Continuous Integration&#xff0c;持续集成&#xff09;CD&#xff08;Continuous Delivery/Deployment&#xff0c;持续交付/持续部署&#xff09; CI 持续集成 目标 频繁加粗样式将代码合…

核弹级漏洞

CVE-2025-6018 漏洞介绍&#xff1a; 该漏洞是Linux PAM&#xff08;可插拔认证模块&#xff09;中的一个本地权限提升漏洞&#xff0c;主要存在于openSUSE Leap 15和SUSE Linux Enterprise 15的PAM配置中。由于PAM规则错误地将检查条件设置为用户存在SSH或TTY会话&#xff0c…

LabVIEW自动扶梯振动监测

利用LabVIEW开发平台构建自动扶梯机械振动数据采集系统&#xff0c;实现驱动主机、减速器、梯级等关键部位的振动信号实时采集、频谱分析、数据存储及故障特征提取。系统通过加速度传感器与高速数据采集卡的协同工作&#xff0c;结合 LabVIEW 图形化编程的高效数据处理能力&…

PTA最少交换次数

最少交换次数 分数 15 作者 計科G隊長 单位 重庆大学 长度为N的数组中只有1&#xff0c;2&#xff0c;3三种值&#xff0c;要按升序排序&#xff0c;并且只能通过数值间的两两交换实现不能移位。比如某项竞赛的优胜者按金银铜牌排序&#xff0c;或者荷兰国旗问题都是该问题…

LiteHub中间件之跨域访问CORS

跨域访问CORS 原理基本概念简单请求非简单请求&#xff08;预检请求&#xff09; 代码实现服务器端Cors的关键配置服务端解析预检请求服务端填充响应 抓包分析 原理 基本概念 在浏览器安全模型中&#xff0c;同源策略是最重要的安全基石。 一个“域”是由3个要素组成的&#…

FastAPI开发教程

FastAPI 是一个现代、高性能的 Python Web 框架&#xff0c;专为构建 APIs 设计。它基于 Python 类型提示&#xff0c;支持异步编程&#xff0c;并提供自动生成的交互式文档&#xff08;Swagger UI 和 ReDoc&#xff09;。以下是 FastAPI 开发的核心指南&#xff1a; 1. 安装 …

基于Spring Boot + MyBatis-Plus + Thymeleaf的评论管理系统深度解析

你好呀&#xff0c;我是小邹。 个人博客系统日渐完善&#xff0c;现在的文章评论以及留言数量逐渐增多&#xff0c;所以今天重构了管理后台的评论列表&#xff08;全量查询 -> 分页条件搜索&#xff09;。 示例图 网页端手机端一、系统架构设计与技术选型 系统采用前后端分离…

sqlmap学习笔记ing(1.Easy_SQLi(时间,表单注入))

题解 根据题目提示&#xff0c;应为SQL注入&#xff0c;题目页面只有一个表单&#xff0c;用sqlmap进行表单注入。 使用--forms参数进行自动化表单注入&#xff0c;逐步得到flag。 ### 总结参数作用&#xff1a; -u 指定目标URL。 -C 指定列名&#xff08;多个…

SciPy 安装使用教程

一、SciPy 简介 SciPy&#xff08;Scientific Python&#xff09;是基于 NumPy 的开源科学计算库&#xff0c;提供了数值积分、优化、信号处理、线性代数、统计分析等高级科学计算功能。它是构建 Python 科学计算生态系统的核心组件之一&#xff0c;常用于科研、工程、数据分析…

【AI大模型】通义大模型与现有企业系统集成实战《CRM案例分析与安全最佳实践》

简介&#xff1a; 本文档详细介绍了基于通义大模型的CRM系统集成架构设计与优化实践。涵盖混合部署架构演进&#xff08;新增向量缓存、双通道同步&#xff09;、性能基准测试对比、客户意图分析模块、商机预测系统等核心功能实现。同时&#xff0c;深入探讨了安全防护体系、三…

如何进行需求全周期管理

实现高效的需求全周期管理&#xff0c;应从以下五个方面入手&#xff1a;1、建立系统化需求来源渠道、2、设置清晰的评审与优先级策略、3、加强执行过程的协同与跟踪、4、闭环需求验收与上线反馈、5、构建长期的需求知识沉淀机制。 其中&#xff0c;“加强执行过程的协同与跟踪…

热传导方程能量分析与边界条件研究

题目 问题 10. (a) 考虑热传导方程在 J = ( − ∞ , ∞ ) J = (-\infty, \infty) J=(−∞,∞) 上,证明“能量” E ( t ) = ∫ J u 2 ( x , t ) d x E(t) = \int_{J} u^{2}(x,t) dx E(t)=∫J​u2(x,t)dx (8) 不增加;进一步证明,除非 u ( x , t ) = 常数 u(x,t) = \text{常…

【AI News | 20250702】每日AI进展

AI Repos 1、LLM-RL-Visualized 提供100余张原创架构图&#xff0c;全面涵盖了 LLM (大语言模型)、VLM (视觉语言模型) 等大模型技术。内容深度解析了训练算法&#xff08;如 RL、RLHF、GRPO、DPO、SFT、CoT 蒸馏等&#xff09;、效果优化策略&#xff08;如 RAG、CoT&#xf…

安徽省企业如何做信创产品认证?信创认证流程与费用详解

安徽省作为长三角一体化发展的重要成员&#xff0c;正大力推进信息技术应用创新&#xff08;信创&#xff09;产业发展。依托合肥“中国声谷”、芜湖机器人及智能装备基地等产业集群&#xff0c;以及省内对信创产业的政策扶持&#xff0c;企业通过信创认证后&#xff0c;能更好…

百度文心 ERNIE 4.5 开源:开启中国多模态大模型开源新时代

百度文心 ERNIE 4.5 开源&#xff1a;开启中国多模态大模型开源新时代 随着DeepSeek-R1的横空出示&#xff0c;越来越多大公司开始开源模型&#xff0c;像DeepSeek R1发布的时候Kimi同步开源了技术文档&#xff0c;随着R1推动着思维链推理技术的发展&#xff0c;开源社区也出现…