使用C++设计滤波器(低通滤波器,高通滤波器,带通滤波器)

简单低通滤波器

以下是一个使用C++语言编写的基本低通滤波器的示例代码,它可以对输入信号进行滤波以降低高频成分:

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

// 低通滤波器类
class LowPassFilter {
public:
    LowPassFilter(double sample_rate, double cutoff_frequency) {
        double dt = 1.0 / sample_rate;
        double RC = 1.0 / (cutoff_frequency * 2.0 * M_PI);
        alpha_ = dt / (dt + RC);
        prev_output_ = 0.0;
    }

    // 更新滤波器输出
    double update(double input) {
        double output = alpha_ * input + (1.0 - alpha_) * prev_output_;
        prev_output_ = output;
        return output;
    }

private:
    double alpha_;
    double prev_output_;
};

int main() {
    // 输入信号
    vector<double> input_signal = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};

    // 采样率和截止频率
    double sample_rate = 100.0;
    double cutoff_frequency = 10.0;

    // 创建低通滤波器
    LowPassFilter filter(sample_rate, cutoff_frequency);

    // 对输入信号进行滤波
    vector<double> output_signal;
    for (double input : input_signal) {
        double output = filter.update(input);
        output_signal.push_back(output);
    }

    // 输出滤波结果
    for (double output : output_signal) {
        cout << output << " ";
    }
    cout << endl;

    return 0;
}

在这个示例中,我们使用一个一阶滤波器来实现低通滤波器。该滤波器具有一个截止频率,所有高于该频率的信号成分都会被过滤掉。在构造函数中,我们根据采样率和截止频率计算出滤波器的alpha系数,这个系数用于控制信号在输入和输出之间的平衡。然后,我们在update函数中使用输入信号和alpha系数来计算滤波器的输出,并且将输出保存在prev_output_中,以便在下一次更新时使用。

在主函数中,我们创建了一个输入信号向量,并且创建了一个低通滤波器对象。然后,我们使用for循环将输入信号中的每个元素传递给滤波器进行处理,并且将输出保存在一个新的向量中。最后,我们将滤波后的输出向量输出到控制台。

FIR低通滤波器

以下是一个使用C++语言编写的基本FIR滤波器的示例代码,它可以对输入信号进行滤波以实现频率选择性:

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

// 创建一个函数,用于生成低通滤波器的系数
vector<double> createLowpassFilter(int M, double fc, double fs) {
    vector<double> h(M + 1);
    for (int n = 0; n <= M; ++n) {
        if (n == M / 2) {
            h[n] = 2.0 * fc / fs;
        } else {
            h[n] = sin(2.0 * M_PI * fc * (n - M / 2.0) / fs) / (M_PI * (n - M / 2.0));
        }
        h[n] *= 0.54 - 0.46 * cos(2.0 * M_PI * n / M);
    }
    return h;
}

// FIR滤波器类
class FirFilter {
public:
    FirFilter(const vector<double>& taps) : taps_(taps), buffer_(taps.size(), 0.0) {}

    // 更新滤波器输出
    double update(double input) {
        // 将新的输入添加到环形缓冲区中
        buffer_.insert(buffer_.begin(), input);
        buffer_.pop_back();

        // 计算输出值
        double output = 0.0;
        for (int i = 0; i < taps_.size(); ++i) {
            output += taps_[i] * buffer_[i];
        }
        return output;
    }

private:
    vector<double> taps_;  // 滤波器系数
    vector<double> buffer_;  // 环形缓冲区
};

int main() {
    // 创建低通滤波器系数
    int M = 31;  // 系数数量
    double fc = 1000.0;  // 截止频率
    double fs = 44100.0;  // 采样率
    vector<double> taps = createLowpassFilter(M, fc, fs);

    // 输入信号
    vector<double> input_signal = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};

    // 创建FIR滤波器
    FirFilter filter(taps);

    // 对输入信号进行滤波
    vector<double> output_signal;
    for (double input : input_signal) {
        double output = filter.update(input);
        output_signal.push_back(output);
    }

    // 输出滤波结果
    for (double output : output_signal) {
        cout << output << " ";
    }
    cout << endl;

    return 0;
}

在这个示例中,我们创建了一个名为createLowpassFilter的函数来生成FIR低通滤波器的系数。该函数接受三个参数:滤波器的长度M,截止频率fc和采样率fs

IIR低通滤波器

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

class IirFilter {
public:
    IirFilter(double a0, double a1, double a2, double b1, double b2) : a0_(a0), a1_(a1), a2_(a2), b1_(b1), b2_(b2), x1_(0), x2_(0), y1_(0), y2_(0) {}

    // 更新滤波器输出
    double update(double input) {
        double output = a0_ * input + a1_ * x1_ + a2_ * x2_ - b1_ * y1_ - b2_ * y2_;
        x2_ = x1_;
        x1_ = input;
        y2_ = y1_;
        y1_ = output;
        return output;
    }

private:
    double a0_, a1_, a2_, b1_, b2_;  // 滤波器系数
    double x1_, x2_, y1_, y2_;  // 状态变量
};

int main() {
    // 设计IIR低通滤波器
    double fc = 1000.0;  // 截止频率
    double fs = 44100.0;  // 采样率
    double wc = 2.0 * M_PI * fc / fs;
    double Q = 0.707;  // 品质因数
    double alpha = sin(wc) / (2.0 * Q);
    double a0 = 1.0 + alpha;
    double a1 = -2.0 * cos(wc);
    double a2 = 1.0 - alpha;
    double b0 = (1.0 - cos(wc)) / 2.0;
    double b1 = 1.0 - cos(wc);
    double b2 = (1.0 - cos(wc)) / 2.0;

    // 创建IIR低通滤波器
    IirFilter filter(a0, a1, a2, b1, b2);

    // 输入信号
    vector<double> input_signal = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};

    // 对输入信号进行滤波
    vector<double> output_signal;
    for (double input : input_signal) {
        double output = filter.update(input);
        output_signal.push_back(output);
    }

    // 输出滤波结果
    for (double output : output_signal) {
        cout << output << " ";
    }
    cout << endl;

    return 0;
}

在这个示例中,我们使用IirFilter类来实现IIR低通滤波器。该类接受五个参数,分别是系数a0a1a2b1b2

简单带通滤波器

以下是一个简单的C++实现带通滤波器的例子。该代码使用了离散傅里叶变换(DFT)来计算信号的频谱,然后对频谱进行滤波。

#include <cmath>
#include <vector>

using namespace std;

const double PI = 3.14159265358979323846;

// 计算离散傅里叶变换
void dft(const vector<double>& input, vector<complex<double>>& output) {
    int n = input.size();
    output.resize(n);
    for (int k = 0; k < n; k++) {
        complex<double> sum(0, 0);
        for (int j = 0; j < n; j++) {
            double angle = 2 * PI * k * j / n;
            sum += input[j] * exp(complex<double>(0, -angle));
        }
        output[k] = sum;
    }
}

// 计算滤波器的频率响应
void filter(vector<double>& spectrum, double f1, double f2, double fs) {
    int n = spectrum.size();
    for (int k = 0; k < n; k++) {
        double freq = k * fs / n;
        if (freq < f1 || freq > f2) {
            spectrum[k] = 0;
        }
    }
}

// 带通滤波器
void bandpass_filter(vector<double>& signal, double f1, double f2, double fs) {
    int n = signal.size();

    // 计算信号的频谱
    vector<complex<double>> spectrum;
    dft(signal, spectrum);

    // 对频谱进行滤波
    filter(spectrum, f1, f2, fs);

    // 计算滤波后的信号
    vector<double> filtered_signal;
    filtered_signal.resize(n);
    for (int i = 0; i < n; i++) {
        double sum = 0;
        for (int k = 0; k < n; k++) {
            double angle = 2 * PI * i * k / n;
            sum += spectrum[k].real() * cos(angle) - spectrum[k].imag() * sin(angle);
        }
        filtered_signal[i] = sum / n;
    }

    // 将滤波后的信号复制回原信号
    for (int i = 0; i < n; i++) {
        signal[i] = filtered_signal[i];
    }
}

这个实现中,带通滤波器被定义为 bandpass_filter 函数。它接受三个参数:输入信号 signal、截止频率 f1f2,以及采样频率 fs。函数将修改输入信号的值,以使其成为经过带通滤波后的信号。

其中,dft 函数计算信号的离散傅里叶变换,filter 函数计算滤波器的频率响应,filtered_signal 数组存储滤波后的信号。

FIR带通滤波器

FIR滤波器是一种常用的数字滤波器类型,它在离散时间域内使用有限数量的系数(即有限冲击响应)来实现滤波器的功能。FIR带通滤波器可以通过在传递函数的频域上选择一个带通区域的方式来实现。以下是一个简单的C++实现FIR带通滤波器的例子:

#include <cmath>
#include <vector>

using namespace std;

const double PI = 3.14159265358979323846;

// FIR带通滤波器
void bandpass_filter(vector<double>& signal, double f1, double f2, double fs, int num_taps) {
    int n = signal.size();

    // 计算滤波器系数
    vector<double> h;
    h.resize(num_taps);
    double hsum = 0;
    for (int i = 0; i < num_taps; i++) {
        double freq = (double)i / num_taps * fs;
        if (freq >= f1 && freq <= f2) {
            h[i] = 2 * (f2 - f1) / fs * cos(2 * PI * (f1 + f2) / 2 / fs * (i - (num_taps - 1) / 2.0)) / PI;
        } else {
            h[i] = 0;
        }
        hsum += h[i];
    }
    for (int i = 0; i < num_taps; i++) {
        h[i] /= hsum;
    }

    // 对信号进行滤波
    vector<double> filtered_signal;
    filtered_signal.resize(n);
    for (int i = 0; i < n; i++) {
        double sum = 0;
        for (int j = 0; j < num_taps; j++) {
            if (i >= j) {
                sum += h[j] * signal[i - j];
            }
        }
        filtered_signal[i] = sum;
    }

    // 将滤波后的信号复制回原信号
    for (int i = 0; i < n; i++) {
        signal[i] = filtered_signal[i];
    }
}

这个实现中,FIR带通滤波器被定义为 bandpass_filter 函数。它接受四个参数:输入信号 signal、截止频率 f1f2,以及采样频率 fs,还有滤波器的阶数(即系数数量)num_taps。函数将修改输入信号的值,以使其成为经过带通滤波后的信号。

其中,h 数组存储滤波器的系数,filtered_signal 数组存储滤波后的信号。对于一个给定的阶数 num_tapsh 数组的值通过选择一个带通区域来计算。filtered_signal 数组的值是通过将信号与滤波器系数进行卷积来计算的。

IIR带通滤波器

IIR滤波器是一种数字滤波器类型,它在离散时间域内使用递归的系数来实现滤波器的功能。相对于FIR滤波器,IIR滤波器具有更小的阶数,更快的计算速度和更平滑的滤波特性。以下是一个简单的C++实现IIR带通滤波器的例子:

#include <cmath>
#include <vector>

using namespace std;

const double PI = 3.14159265358979323846;

// IIR带通滤波器
void bandpass_filter(vector<double>& signal, double f1, double f2, double fs, double Q) {
    int n = signal.size();

    // 计算滤波器系数
    double w1 = 2 * PI * f1 / fs;
    double w2 = 2 * PI * f2 / fs;
    double bw = w2 - w1;
    double wc = sqrt(w1 * w2);
    double alpha = sin(bw) / (2 * Q);
    double b0 = alpha;
    double b1 = 0;
    double b2 = -alpha;
    double a0 = 1 + alpha;
    double a1 = -2 * cos(wc);
    double a2 = 1 - alpha;

    // 对信号进行滤波
    double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
    for (int i = 0; i < n; i++) {
        double x0 = signal[i];
        double y0 = (b0 * x0 + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2) / a0;
        signal[i] = y0;
        x2 = x1;
        x1 = x0;
        y2 = y1;
        y1 = y0;
    }
}

这个实现中,IIR带通滤波器被定义为 bandpass_filter 函数。它接受四个参数:输入信号 signal、截止频率 f1f2,以及采样频率 fs,还有滤波器的品质因数 Q。函数将修改输入信号的值,以使其成为经过带通滤波后的信号。

其中,b0b1b2a0a1a2 分别是IIR滤波器的递归和非递归系数,它们的值通过选择一个带通区域来计算。x1x2y1y2 是IIR滤波器的历史输入和输出样本,它们用于实现滤波器的递归过程。signal[i] 是当前输入样本的输出样本,由递归和非递归系数和历史输入和输出样本计算而来。

猜你喜欢

转载自blog.csdn.net/Q_Linfeng/article/details/129120537