使用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
英文地址,請注明出處:http://en.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;開源社區也出現…