C++开发基础之使用FFTW实现高效的信号滤波(含低通、高通与带通滤波器示例)

在这里插入图片描述

前言

在信号处理中,滤波器是不可或缺的工具。通过过滤掉特定频率的信号成分,我们可以获得更清晰、更有用的数据。在本文中,我们将展示如何在Windows平台下,使用Visual Studio(VS)集成开发环境(IDE),借助FFTW库实现高效的信号滤波。我们将涵盖低通、高通和带通滤波器的实现。

1. 为什么选择FFTW库?

FFTW(Fastest Fourier Transform in the West)是一个广泛使用的C库,专门用于计算离散傅里叶变换(FFT)。FFT将时域信号转换到频域,在频域中,我们可以轻松地对信号进行滤波处理。FFTW提供了高效的实现,能够在大多数平台上运行,并且支持多种变换类型。

2. 安装FFTW库

在Windows平台下,安装FFTW库的过程稍微复杂一些。我们将通过以下步骤来安装FFTW并在Visual Studio中配置它。

步骤 1:下载FFTW库
  • 访问FFTW官方网站:FFTW官网
    在这里插入图片描述
  • 下载Windows版的FFTW库(通常是一个压缩文件)。选择适合Visual Studio版本(如VS 2019或VS 2022)的预编译版本。

在这里插入图片描述

  • 找到对应的版本,进行下载
    在这里插入图片描述

  • 解压下载的文件,将其保存到选择的文件夹中。发现没有lib库,需要本地编译处理,找到 lib.exe的目录 加入环境变量

# D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\bin\Hostx64\x64\lib.exe
C:\Users\DN0>lib
Microsoft (R) Library Manager Version 14.42.34433.0
Copyright (C) Microsoft Corporation.  All rights reserved.
用法: LIB [选项] [文件]
选项:
/DEF[:文件名]
/ERRORREPORT:{NONE|PROMPT|QUEUE|SEND}
/EXPORT:符号
/EXTRACT:成员名
/INCLUDE:符号
/LIBPATH:目录
/LINKREPRO:dir
/LINKREPROFULLPATHRSP:filename
/LINKREPROTARGET:filename
/LIST[:文件名]
/LTCG
/MACHINE:{ARM|ARM64|ARM64X|EBC|X64|X86}
/NAME:文件名
/NODEFAULTLIB[:库]
/NOLOGO
/OUT:文件名
/REMOVE:成员名
/SUBSYSTEM:{BOOT_APPLICATION|CONSOLE|EFI_APPLICATION|
EFI_BOOT_SERVICE_DRIVER|EFI_ROM|EFI_RUNTIME_DRIVER|
NATIVE|POSIX|WINDOWS|WINDOWSCE}[,#[.##]]
/VERBOSE
/WX[:NO]
/WX[:nnnn[,nnnn...]]
C:\Users\DN0>
  • cd到解压目录执行编译
lib /machine:x64 /def:libfftw3-3.def
lib /machine:x64 /def:libfftw3f-3.def
lib /machine:x64 /def:libfftw3l-3.def
  • 生成我们需要的
libfftw3-3.lib
libfftw3f-3.lib
libfftw3l-3.lib
步骤 2:配置Visual Studio
  1. 打开Visual Studio。

  2. 创建一个新的C++控制台应用程序项目 FFTWCpp,拷贝fftw-3.3.5-dll64到项目下。

  3. 配置FFTW库:

    1. 右键点击项目,选择“属性”。

    2. 在“C/C++” -> “常规” -> “附加包含目录”中,添加FFTW的头文件目录(例如:fftw-3.3.5-dll64)。

    3. 在“链接器” -> “常规” -> “附加库目录”中,添加FFTW的库文件目录(例如:fftw-3.3.5-dll64)。

    4. 在“链接器” -> “输入” -> “附加依赖项”中,添加FFTW的静态库文件(例如:fftw-3.3.5-dll64中的lib文件libfftw3-3.lib 、libfftw3l-3.lib、 libfftw3f-3.lib)。

步骤 3:添加FFTW的DLL文件(如果使用动态链接)
  • 如果使用动态链接版本的FFTW库,需要确保将相应的.dll文件放到可执行文件的目录中。通常,这些文件位于FFTW库的bin目录中(例如:libfftw3-3.dll)。可以使用生成后事件。
xcopy /Y /E /I "$(SolutionDir)fftw-3.3.5-dll64\*.dll" "$(OutDir)"

3. 创建滤波器程序

现在我们已经配置好了环境,可以开始编写代码来实现不同类型的滤波器:低通滤波器、高通滤波器和带通滤波器。

步骤 1:导入头文件并设置FFTW计划

我们需要包括fftw3.h头文件,并定义FFT和IFFT的处理函数。首先,确保在代码开头包含以下头文件:

#include <iostream>
#include <fftw3.h>
#include <vector>
#include <cmath>
#include <complex>
步骤 2:FFT与IFFT实现

在进行滤波之前,我们需要将时域信号转换到频域,并且在滤波处理之后将其转换回时域。

// FFT 处理
void fft_process(const std::vector<double>& signal, std::vector<std::complex<double>>& frequency_domain) {
    int N = signal.size();
    fftw_complex *in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
    fftw_complex *out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
    fftw_plan plan = fftw_plan_dft_r2c_1d(N, (double*)signal.data(), out, FFTW_ESTIMATE);
    fftw_execute(plan);
    // 将频域信号保存为复数形式
    for (int i = 0; i < N; ++i) {
        frequency_domain[i] = std::complex<double>(out[i][0], out[i][1]);
    }
    fftw_destroy_plan(plan);
    fftw_free(in);
    fftw_free(out);
}
// IFFT 处理
void ifft_process(std::vector<double>& signal, const std::vector<std::complex<double>>& frequency_domain) {
    int N = signal.size();
    fftw_complex *in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
    fftw_complex *out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
    fftw_plan plan = fftw_plan_dft_c2r_1d(N, in, (double*)out, FFTW_ESTIMATE);
    for (int i = 0; i < N; ++i) {
        in[i][0] = frequency_domain[i].real();
        in[i][1] = frequency_domain[i].imag();
    }
    fftw_execute(plan);
    // 归一化并保存回时域信号
    for (int i = 0; i < N; ++i) {
        signal[i] = out[i][0] / N;
    }
    fftw_destroy_plan(plan);
    fftw_free(in);
    fftw_free(out);
}
步骤 3:实现滤波器
低通滤波器

低通滤波器允许低频通过,抑制高频。我们将频域中的高于某个截止频率的部分置为零。

void low_pass_filter(std::vector<std::complex<double>>& frequency_domain, double cutoff_frequency, int sample_rate) {
    int N = frequency_domain.size();
    int cutoff_index = static_cast<int>(cutoff_frequency * N / sample_rate);
    for (int i = cutoff_index; i < N - cutoff_index; ++i) {
        frequency_domain[i] = std::complex<double>(0, 0);
    }
}
高通滤波器

高通滤波器允许高频通过,抑制低频。我们将频域中的低于某个截止频率的部分置为零。

void high_pass_filter(std::vector<std::complex<double>>& frequency_domain, double cutoff_frequency, int sample_rate) {
    int N = frequency_domain.size();
    int cutoff_index = static_cast<int>(cutoff_frequency * N / sample_rate);
    for (int i = 0; i < cutoff_index; ++i) {
        frequency_domain[i] = std::complex<double>(0, 0);
    }
}
带通滤波器

带通滤波器允许一定频段内的信号通过,抑制低频和高频。我们需要设置一个低频和高频的截止频率。

void band_pass_filter(std::vector<std::complex<double>>& frequency_domain, double low_cutoff, double high_cutoff, int sample_rate) {
    int N = frequency_domain.size();
    int low_cutoff_index = static_cast<int>(low_cutoff * N / sample_rate);
    int high_cutoff_index = static_cast<int>(high_cutoff * N / sample_rate);
    for (int i = 0; i < low_cutoff_index; ++i) {
        frequency_domain[i] = std::complex<double>(0, 0);
    }
    for (int i = high_cutoff_index; i < N - high_cutoff_index; ++i) {
        frequency_domain[i] = std::complex<double>(0, 0);
    }
}
步骤 4:主函数

在主函数中,我们将创建一个简单的示例信号,并对其应用滤波器。

int main() {
    // 信号参数
    int N = 16;  // 信号长度
    int sample_rate = 100;  // 采样率
    double cutoff_frequency = 20.0;  // 截止频率(低通、高通)
    // 示例信号(时域)
    std::vector<double> signal = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 90, 80, 70, 60, 50, 40};
    std::vector<std::complex<double>> frequency_domain(N);
    // FFT:从时域转换到频域
    fft_process(signal, frequency_domain);
    // 低通滤波器处理
    low_pass_filter(frequency_domain, cutoff_frequency, sample_rate);
    // IFFT:从频域转换回时域
    std::vector<double> filtered_signal(N);
    ifft_process(filtered_signal, frequency_domain);
    // 打印处理后的时域信号
    std::cout << "Filtered Time Domain Signal: ";
    for (const auto& val : filtered_signal) {
        std::cout << val << " ";
    }
    std::cout << std::endl;
    return 0;
}

4. 总结

在这篇文章中,我们展示了如何在Windows平台下,使用Visual Studio和FFTW库实现低通、高通和带通滤波器。通过FFT和IFFT转换,我们能够有效地从时域信号中提取或抑制特定频率的成分,从而达到滤波的目的。这些滤波技术在音频、图像和其他信号处理应用中非常常见和有用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dotnet研习社

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值