这是一个用 Rust 编写的高性能科学计算信号处理库,旨在逐步重现 Python 中广泛使用的 scipy.signal 模块功能。该库专注于滤波器设计、信号平滑、频域分析以及模态分解等,适用于嵌入式系统、实时处理、高性能计算等对性能和稳定性有较高要求的场景
📦 模块功能覆盖情况(Rust 替代 SciPy.signal)
| 模块类型 | 功能 | 状态 |
|---|---|---|
| 数字滤波器 | Butterworth(低通 / 高通) | ✅ 已完成 |
| Bessel(低通 / 高通) | ✅ 已完成 | |
| Chebyshev I(低通 / 高通) | ✅ 已完成 | |
| Chebyshev II(低通 / 高通) | ✅ 已完成 | |
| Gaussian(低通) | ✅ 已完成 | |
| 带通 / 带阻支持 | 🚧 规划中 | |
| 平滑算法 | 中值滤波(Median filter) | ✅ 已完成 |
| SMA(Simple Moving Average) | ✅ 已完成 | |
| EMA(Exponential Moving Average) | ✅ 已完成 | |
| RMA(Running Moving Average) | ✅ 已完成 | |
| 频域分析 | FFT / IFFT | ✅ 已完成 |
| RFFT / IRFFT | 🚧 待实现 | |
| Hilbert 变换 | 🚧 规划中 | |
| 模态分解 | EMD(经验模态分解) | 🚧 规划中 |
| EEMD(集合经验模态分解) | 🚧 规划中 | |
| CEEMD(完全集合 EMD) | 🚧 规划中 | |
| 实用函数 | 极值点检测(find_peaks) | 🚧 规划中 |
| 样条插值器(Spline interpolation) | 🚧 规划中 |
当前所有滤波器仅实现了低通 / 高通功能,带通与带阻支持将于后续版本添加。
📦 使用说明
- 数字滤波器示例
use std::{f32::consts::PI, time::Instant};
use scientific_cal::{bessel, butter_worth, cheby1, cheby2, correlate1d, gaussian1d, Sosfit, BesselCriterion, FilterBand, FilterSelect};
#[test]
fn bessel_filter_test() -> Result<(), String>{
// 参数输入
let order = 4;
let fs = 1000.0;
let cutoff = 5.0;
// 仿真数据
let dt = 1.0 / fs as f32;
let raw_data: Vec<f32> = (0..fs as i32)
.map(|i| {
let t = i as f32 * dt;
(2.0 * PI * 2.0 * t).sin() + 0.5 * (2.0 * PI * 20.0 * t).sin()
})
.collect();
// 定义低通滤波器
let mut start = Instant::now();
let sos = if let Ok(s) = bessel(
order as usize, // 阶数
&mut vec![cutoff], // 截止频率为5hz
FilterBand::LowPass,
false,
FilterSelect::Bessel(BesselCriterion::Delay),
Some(fs) // 采样频率为1khz 可以为None 但是 截止频率 wn = cutoff / (fs / 2)
){
s
}else{
return Err("".to_string());
};
println!("滤波初始化参数耗时: {:?}", start.elapsed());
start = Instant::now();
// 开始计算
let output = &raw_data.sosfilt(&sos)?;
println!("滤波运行耗时: {:?}", start.elapsed());
println!("{:?}", &output[0..10]);
Ok(())
}
#[test]
fn butter_worth_filter_test() -> Result<(), String>{
// 参数输入
let order = 4;
let fs = 1000.0;
let cutoff = 5.0;
// 仿真数据
let dt = 1.0 / fs as f32;
let raw_data: Vec<f32> = (0..fs as i32)
.map(|i| {
let t = i as f32 * dt;
(2.0 * PI * 2.0 * t).sin() + 0.5 * (2.0 * PI * 20.0 * t).sin()
})
.collect();
// 定义低通滤波器
let mut start = Instant::now();
let sos = if let Ok(s) = butter_worth(
order as usize, // 阶数
&mut vec![cutoff], // 截止频率为5hz
FilterBand::LowPass,
false,
Some(fs) // 采样频率为1khz 可以为None 但是 截止频率 wn = cutoff / (fs / 2)
){
s
}else{
return Err("".to_string());
};
println!("滤波初始化参数耗时: {:?}", start.elapsed());
start = Instant::now();
// 开始计算
let output = &raw_data.sosfilt(&sos)?;
println!("滤波运行耗时: {:?}", start.elapsed());
println!("{:?}", &output[0..10]);
Ok(())
}
#[test]
fn cheby1_filter_test() -> Result<(), String>{
// 参数输入
let order = 4;
let fs = 1000.0;
let cutoff = 5.0;
let rp = 1.0;
// 仿真数据
let dt = 1.0 / fs as f32;
let raw_data: Vec<f32> = (0..fs as i32)
.map(|i| {
let t = i as f32 * dt;
(2.0 * PI * 2.0 * t).sin() + 0.5 * (2.0 * PI * 20.0 * t).sin()
})
.collect();
// 定义低通滤波器
let mut start = Instant::now();
let sos = if let Ok(s) = cheby1(
order as usize, // 阶数
&mut vec![cutoff], // 截止频率为5hz
FilterBand::LowPass,
false,
Some(fs), // 采样频率为1khz 可以为None 但是 截止频率 wn = cutoff / (fs / 2)
Some(rp),
None
){
s
}else{
return Err("".to_string());
};
println!("滤波初始化参数耗时: {:?}", start.elapsed());
start = Instant::now();
// 开始计算
let output = &raw_data.sosfilt(&sos)?;
println!("滤波运行耗时: {:?}", start.elapsed());
println!("{:?}", &output[0..10]);
Ok(())
}
#[test]
fn cheby2_filter_test() -> Result<(), String>{
// 参数输入
let order = 4;
let fs = 1000.0;
let cutoff = 5.0;
let rs = 20.0;
// 仿真数据
let dt = 1.0 / fs as f32;
let raw_data: Vec<f32> = (0..fs as i32)
.map(|i| {
let t = i as f32 * dt;
(2.0 * PI * 2.0 * t).sin() + 0.5 * (2.0 * PI * 20.0 * t).sin()
})
.collect();
// 定义低通滤波器
let mut start = Instant::now();
let sos = if let Ok(s) = cheby2(
order as usize, // 阶数
&mut vec![cutoff], // 截止频率为5hz
FilterBand::LowPass,
false,
Some(fs), // 采样频率为1khz 可以为None 但是 截止频率 wn = cutoff / (fs / 2)
None,
Some(rs)
){
s
}else{
return Err("".to_string());
};
println!("滤波初始化参数耗时: {:?}", start.elapsed());
start = Instant::now();
// 开始计算
let output = &raw_data.sosfilt(&sos)?;
println!("滤波运行耗时: {:?}", start.elapsed());
println!("{:?}", &output[0..10]);
Ok(())
}
#[test]
fn gauss_filter_test() -> Result<(), String>{
// 参数输入
let fs = 1000.0;
let cutoff = 5.0;
let truncate = 4.0;
// 仿真数据
let dt = 1.0 / fs as f32;
let raw_data: Vec<f32> = (0..fs as i32)
.map(|i| {
let t = i as f32 * dt;
(2.0 * PI * 2.0 * t).sin() + 0.5 * (2.0 * PI * 20.0 * t).sin()
})
.collect();
// 定义低通滤波器
let mut start = Instant::now();
let weights = if let Ok(s) = gaussian1d(
fs,
cutoff,
truncate,
None
){
s
}else{
return Err(String::from(""));
};
println!("滤波初始化参数耗时: {:?}", start.elapsed());
start = Instant::now();
// 开始计算
let output = if let Ok(result) = correlate1d(&raw_data, &weights, -1, "reflect", 0.0, 0) {
result
}else {
return Err(String::from(""));
};
println!("滤波运行耗时: {:?}", start.elapsed());
println!("{:?}", &output[0..10]);
Ok(())
}
- 平滑算法示例
use std::{f32::consts::PI, time::Instant};
use scientific_cal::{Ema, Rma, Sma, MedianSmooth};
#[test]
fn move_ema_filter_test() -> Result<(), String>{
// 参数输入
let window_size = 5;
let fs = 1000;
// 仿真数据
let dt = 1.0 / fs as f32;
let raw_data: Vec<f32> = (0..fs as i32)
.map(|i| {
let t = i as f32 * dt;
(2.0 * PI * 2.0 * t).sin() + 0.5 * (2.0 * PI * 20.0 * t).sin()
})
.collect();
// 开始计算
let start = Instant::now();
let output = &raw_data.ema_smooth(window_size as usize)?;
println!("滤波运行耗时: {:?}", start.elapsed());
println!("{:?}", &output[0..10]);
Ok(())
}
#[test]
fn move_rma_filter_test() -> Result<(), String>{
// 参数输入
let window_size = 5;
let fs = 1000;
// 仿真数据
let dt = 1.0 / fs as f32;
let raw_data: Vec<f32> = (0..fs as i32)
.map(|i| {
let t = i as f32 * dt;
(2.0 * PI * 2.0 * t).sin() + 0.5 * (2.0 * PI * 20.0 * t).sin()
})
.collect();
// 开始计算
let start = Instant::now();
let output = &raw_data.rma_smooth(window_size as usize)?;
println!("滤波运行耗时: {:?}", start.elapsed());
println!("{:?}", &output[0..10]);
Ok(())
}
#[test]
fn move_sma_filter_test() -> Result<(), String>{
// 参数输入
let window_size = 5;
let fs = 1000;
// 仿真数据
let dt = 1.0 / fs as f32;
let raw_data: Vec<f32> = (0..fs as i32)
.map(|i| {
let t = i as f32 * dt;
(2.0 * PI * 2.0 * t).sin() + 0.5 * (2.0 * PI * 20.0 * t).sin()
})
.collect();
// 开始计算
let start = Instant::now();
let output = &raw_data.sma_smooth(window_size as usize)?;
println!("滤波运行耗时: {:?}", start.elapsed());
println!("{:?}", &output[0..10]);
Ok(())
}
#[test]
fn move_median_filter_test() -> Result<(), String>{
// 参数输入
let window_size = 5;
let precision = 0.2;
let fs = 1000;
// 仿真数据
let dt = 1.0 / fs as f32;
let raw_data: Vec<f32> = (0..fs as i32)
.map(|i| {
let t = i as f32 * dt;
(2.0 * PI * 2.0 * t).sin() + 0.5 * (2.0 * PI * 20.0 * t).sin()
})
.collect();
// 开始计算
let start = Instant::now();
let output = &raw_data.median_smooth(window_size as usize, precision)?;
println!("滤波运行耗时: {:?}", start.elapsed());
println!("{:?}", &output[0..10]);
Ok(())
}
- 频谱分析示例
use std::{f32::consts::PI, time::Instant};
use scientific_cal::{Fft, Ifft};
#[test]
fn fft_test() -> Result<(), String>{
// 参数输入
let n = 8;
// 仿真数据
let raw_data: Vec<f32> = (0..n as i64)
.map(|i| {
(2.0 * PI * i as f32 / n as f32).sin()
})
.collect();
// 开始计算
let start = Instant::now();
let mut fft_result = raw_data.fft()?;
println!("fft_result: {:?}", fft_result);
// 幅值需要除以 N
let n = raw_data.len();
for f in fft_result.iter_mut(){
*f = *f / (n as f32)
}
// 可以自定义滤波
// 略
// 反fft
let ifft_result = &fft_result.ifft()?;
println!("fft运行耗时: {:?}", start.elapsed());
println!("ifft_result: {:?}", ifft_result);
Ok(())
}
#[test]
fn test(){
let ret = re_arrange(3, 3);
println!("{:?}",ret);
}
fn re_arrange(dat: usize, bitlength: usize) -> usize {
let mut ret = 0;
for i in 0..bitlength {
if (dat & (1 << i)) != 0 {
ret |= (1 << (bitlength - 1)) >> i;
}
}
ret
}
🚀 Quick Start
Add this to your Cargo.toml: