#filter #编译时 #分阶段 #编程 #参数 #simd #萨维茨基-戈拉

bin+lib staged-sg-filter

萨维茨基-戈拉滤波器的分阶段编程实现。循环速度飞快。

5 个版本

0.2.3 2024年7月22日
0.2.2 2024年6月6日
0.2.1 2024年6月6日
0.2.0 2024年6月6日
0.1.0 2024年6月6日

编程语言 中排名第 139

Download history 294/week @ 2024-06-03 5/week @ 2024-06-10 18/week @ 2024-07-01 103/week @ 2024-07-22 28/week @ 2024-07-29

每月下载量 131

MIT 许可证

320KB
942

分阶段滤波器

  • 一个快速萨维茨基-戈拉滤波器。

  • 所有 (N,M) 参数都在编译时预先计算并加载。

  • 通过 rayon 功能标志提供 rayon 支持

  • 还有一些 SIMD 性能待提高 - 新版本将专注于性能

  • 请记住使用以下命令编译此程序以获得最佳性能:RUSTFLAGS="-C target-cpu=native".

此代码基于我在 Julia 中修改的另一个代码,得到了许多人的帮助,请参阅 StagedFilters.jl.

示例

基准测试

其他 savgol-rs 实现提供此速度

use savgol_rs::*;
fn main() {
    let input = SavGolInput {
        data: &vec![10.0; 500_000],
        window_length: 3,
        poly_order: 1,
        derivative: 0,
    };
    let result = savgol_filter(&input);
    let data = result.unwrap();
    println!("{:?}", &data[0..10]);
}

大约需要 52s,而此包

use staged_sg_filter::sav_gol;

fn main() {
    let n = 100_000_000;
    let v = vec![10.0; n];
    let mut buf = vec![0.0; n];
    sav_gol::<1, 1>(&mut buf, &v);

    println!("{:?}", &buf[0..10]);
}

在 20 倍数据大小的情况下运行时间约为 200ms。我们大约每秒处理约 100_000_000/0.2 ≈ 5e8 个元素或 5e8 * 10^-90.5 个元素每纳秒。

这还可以通过约 4 倍的因子进行改进,这是 Julia 代码的当前速度。

注意

之所以称为“分阶段”,是因为计算是在“阶段”中进行的,这使得编译器能够大量优化代码 - 也就是说,Rust 中的 const 泛型提供了更多循环展开和正确 SIMD 通道宽度的机会。

您需要具有 FMA 和 AVX2 兼容的硬件(至少)。请使用以下命令编译以获得最佳性能:RUSTFLAGS="-C target-cpu=native" cargo run --release

已经做出了相当大的努力来确保

  • 最小化依赖关系和快速构建
  • 自动向量化通过 cargo-remark 实现
  • 使用预计算系数和 const 泛型将尽可能多的计算推到编译时
  • 热路径是分配和无恐慌的

算法

  1. 在 Julia 中计算感兴趣的系数,将它们复制/粘贴到 coeffs/_f32.rs 中适当的位置,并声明为 const
  2. 使用之前获得的 coeffs 作为一半元素大小进行固定大小的滚动窗口 dot_product。
  3. 更新 buffer 的每个元素
  4. 使用 Rayon 并行化

待办事项

  • rayon 支持
  • 仅计算 12x12 以内的 NxM 并将其缓存
  • 支持 fma
  • 支持 f32/f64 浮点数
  • 支持 SIMD
  • 支持 GPU / ping Manuel Drehwald
  • no_std 支持 see(Effective Rust 链接)
  • 支持导数(目标 - 赞助我?)

依赖项

~0–265KB