C++ 带通滤波

Butterworth Filter Coefficients
The following files are for a library of functions to calculate Butterworth filter coefficients. There are functions for lowpass, bandpass, highpass, and bandstop filters. If you just want an efficient implementation of these filters then see the programs listed above.
liir.c - source code
iir.h - header file
此处的ButterWorthFIlter(巴特沃斯滤波器)只涉及到在c++的应用

bandpass filter coefficient 函数计算

void coeff_ab(int n, double lowcut, double highcut, int fs,vectord &acof_vec, vectord &bcof_vec) {

	double nyq = 0.5 * fs;
	double f1f = lowcut / nyq;
	double f2f = highcut / nyq;
	double sf;        // scaling factor

	double *acof;
	int *bcof;
	/* calculate the d coefficients */
	acof = dcof_bwbp(n, f1f, f2f);
	if (acof == NULL)
	{
		perror("Unable to calculate d coefficients");
	}

	/* calculate the c coefficients */
	bcof = ccof_bwbp(n);
	if (bcof == NULL)
	{
		perror("Unable to calculate c coefficients");
	}

	sf = sf_bwbp(n, f1f, f2f); /* scaling factor for the c coefficients */

							   /* create the filter coefficient file */
	for (int i = 0; i <= 2 * n; ++i){
		bcof_vec.push_back((double)bcof[i] * sf);
	}

	for (int i = 0; i <= 2 * n; ++i)
		acof_vec.push_back(acof[i]);

}

下面是来自hdw09的filtfilt函数的设计

#include <iostream>
#include <exception>
#include <algorithm>
#include "Eigen/Dense"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "iir.h"

typedef std::vector<int> vectori;
typedef std::vector<double> vectord;

using namespace Eigen;
using namespace std;

void add_index_range(vectori &indices, int beg, int end, int inc = 1)
{
	for (int i = beg; i <= end; i += inc)
		indices.push_back(i);
}

void add_index_const(vectori &indices, int value, size_t numel)
{
	while (numel--)
		indices.push_back(value);
}

void append_vector(vectord &vec, const vectord &tail)
{
	vec.insert(vec.end(), tail.begin(), tail.end());
}

vectord subvector_reverse(const vectord &vec, int idx_end, int idx_start)
{
	vectord result(&vec[idx_start], &vec[idx_end + 1]);
	std::reverse(result.begin(), result.end());
	return result;
}

inline int max_val(const vectori& vec)
{
	return std::max_element(vec.begin(), vec.end())[0];
}

void filtfilt(vectord B, vectord A, const vectord &X, vectord &Y);

void filter(vectord B, vectord A, const vectord &X, vectord &Y, vectord &Zi)
{
	if (A.empty())
		throw std::domain_error("The feedback filter coefficients are empty.");
	if (std::all_of(A.begin(), A.end(), [](double coef) { return coef == 0; }))
		throw std::domain_error("At least one of the feedback filter coefficients has to be non-zero.");
	if (A[0] == 0)
		throw std::domain_error("First feedback coefficient has to be non-zero.");

	// Normalize feedback coefficients if a[0] != 1;
	auto a0 = A[0];
	if (a0 != 1.0)
	{
		std::transform(A.begin(), A.end(), A.begin(), [a0](double v) { return v / a0; });
		std::transform(B.begin(), B.end(), B.begin(), [a0](double v) { return v / a0; });
	}

	size_t input_size = X.size();
	size_t filter_order = std::max(A.size(), B.size());
	B.resize(filter_order, 0);
	A.resize(filter_order, 0);
	Zi.resize(filter_order, 0);
	Y.resize(input_size);

	const double *x = &X[0];
	const double *b = &B[0];
	const double *a = &A[0];
	double *z = &Zi[0];
	double *y = &Y[0];

	for (size_t i = 0; i < input_size; ++i)
	{
		size_t order = filter_order - 1;
		while (order)
		{
			if (i >= order)
				z[order - 1] = b[order] * x[i - order] - a[order] * y[i - order] + z[order];
			--order;
		}
		y[i] = b[0] * x[i] + z[0];
	}
	Zi.resize(filter_order - 1);
}

void filtfilt(vectord B, vectord A, const vectord &X, vectord &Y)
{
	int len = X.size();     // length of input
	int na = A.size();
	int nb = B.size();
	int nfilt = (nb > na) ? nb : na;
	int nfact = 3 * (nfilt - 1); // length of edge transients

	if (len <= nfact)
		throw std::domain_error("Input data too short! Data must have length more than 3 times filter order.");

	// set up filter's initial conditions to remove DC offset problems at the
	// beginning and end of the sequence
	B.resize(nfilt, 0);
	A.resize(nfilt, 0);

	vectori rows, cols;
	//rows = [1:nfilt-1           2:nfilt-1             1:nfilt-2];
	add_index_range(rows, 0, nfilt - 2);
	if (nfilt > 2)
	{
		add_index_range(rows, 1, nfilt - 2);
		add_index_range(rows, 0, nfilt - 3);
	}
	//cols = [ones(1,nfilt-1)         2:nfilt-1          2:nfilt-1];
	add_index_const(cols, 0, nfilt - 1);
	if (nfilt > 2)
	{
		add_index_range(cols, 1, nfilt - 2);
		add_index_range(cols, 1, nfilt - 2);
	}
	// data = [1+a(2)         a(3:nfilt)        ones(1,nfilt-2)    -ones(1,nfilt-2)];

	auto klen = rows.size();
	vectord data;
	data.resize(klen);
	data[0] = 1 + A[1];  int j = 1;
	if (nfilt > 2)
	{
		for (int i = 2; i < nfilt; i++)
			data[j++] = A[i];
		for (int i = 0; i < nfilt - 2; i++)
			data[j++] = 1.0;
		for (int i = 0; i < nfilt - 2; i++)
			data[j++] = -1.0;
	}

	vectord leftpad = subvector_reverse(X, nfact, 1);
	double _2x0 = 2 * X[0];
	std::transform(leftpad.begin(), leftpad.end(), leftpad.begin(), [_2x0](double val) {return _2x0 - val; });

	vectord rightpad = subvector_reverse(X, len - 2, len - nfact - 1);
	double _2xl = 2 * X[len - 1];
	std::transform(rightpad.begin(), rightpad.end(), rightpad.begin(), [_2xl](double val) {return _2xl - val; });

	double y0;
	vectord signal1, signal2, zi;

	signal1.reserve(leftpad.size() + X.size() + rightpad.size());
	append_vector(signal1, leftpad);
	append_vector(signal1, X);
	append_vector(signal1, rightpad);

	// Calculate initial conditions
	MatrixXd sp = MatrixXd::Zero(max_val(rows) + 1, max_val(cols) + 1);
	for (size_t k = 0; k < klen; ++k)
		sp(rows[k], cols[k]) = data[k];
	auto bb = VectorXd::Map(B.data(), B.size());
	auto aa = VectorXd::Map(A.data(), A.size());
	MatrixXd zzi = (sp.inverse() * (bb.segment(1, nfilt - 1) - (bb(0) * aa.segment(1, nfilt - 1))));
	zi.resize(zzi.size());

	// Do the forward and backward filtering
	y0 = signal1[0];
	std::transform(zzi.data(), zzi.data() + zzi.size(), zi.begin(), [y0](double val) { return val*y0; });
	filter(B, A, signal1, signal2, zi);
	std::reverse(signal2.begin(), signal2.end());
	y0 = signal2[0];
	std::transform(zzi.data(), zzi.data() + zzi.size(), zi.begin(), [y0](double val) { return val*y0; });
	filter(B, A, signal2, signal1, zi);
	Y = subvector_reverse(signal1, signal1.size() - nfact - 1, nfact);
}


bool compare(const vectord &original, const vectord &expected, double tolerance = DBL_EPSILON)
{
	if (original.size() != expected.size())
		return false;
	size_t size = original.size();

	for (size_t i = 0; i < size; ++i)
	{
		auto diff = abs(original[i] - expected[i]);
		if (diff >= tolerance)
			return false;
	}
	return true;
}

经对比其滤波效果跟python的scipy的signal.butter函数与 signal.filtfilt函数一致。

资料参考
https://blog.csdn.net/zhoufan900428/article/details/9069475
http://www.exstrom.com/journal/sigproc/
https://github.com/hdw09/filtfilt
https://zh.wikipedia.org/wiki/%E5%B7%B4%E7%89%B9%E6%B2%83%E6%96%AF%E6%BB%A4%E6%B3%A2%E5%99%A8
https://www.cnblogs.com/xpvincent/p/5557659.html

  • 10
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
float DigFil(invar, setic) float invar; int setic; /******************************************************************************/ /* Filter Solutions Version 2009 Nuhertz Technologies, L.L.C. */ /* www.nuhertz.com */ /* +1 602-279-2448 */ /* 3rd Order Band Pass Butterworth */ /* Bilinear Transformation with Prewarping */ /* Sample Frequency = 5.000 KHz */ /* Standard Form */ /* Arithmetic Precision = 4 Digits */ /* */ /* Center Frequency = 300.0 Rad/Sec */ /* Pass Band Width = 20.00 Rad/Sec */ /* */ /******************************************************************************/ /* */ /* Input Variable Definitions: */ /* Inputs: */ /* invar float The input to the filter */ /* setic int 1 to initialize the filter to zero */ /* */ /* Option Selections: */ /* Standard C; Initializable; Internal States; Not Optimized; */ /* */ /* There is no requirement to ever initialize the filter. */ /* The default initialization is zero when the filter is first called */ /* */ /******************************************************************************/ /* */ /* This software is automatically generated by Filter Solutions */ /* no restrictions from Nuhertz Technologies, L.L.C. regarding the use and */ /* distributions of this software. */ /* */ /******************************************************************************/ { float sumnum=0.0, sumden=0.0; int i=0; static float states[6] = {0.0,0.0,0.0,0.0,0.0,0.0}; static float znum[7] = { -7.968e-09, 0.0, 2.39e-08, 0.0, -2.39e-08, 0.0, 7.968e-09 }; static float zden[6] = { .992, -5.949, 14.88, -19.86, 14.92, -5.981 }; if (setic==1){ for (i=0;i<6;i++) states[i] = [i] = [i]*invar; return 0.0; } else{ sumnum = sumden = 0.0; for (i=0;i<6;i++){ sumden += states[i]*zden[i]; sumnum += states[i]*znum[i]; if (i<5) states[i] = states[i+1]; } states[5] = invar-sumden; sumnum += states[5]*znum[6]; return sumnum; } }
引用\[1\]中提到了一个库函数用于计算巴特沃斯滤波器的系数,包括低通、带通、高通和带阻滤波器。而引用\[2\]和\[3\]是关于Python实现高通和低通滤波的示例代码。 要实现带通滤波算法,可以结合高通和低通滤波的思想。首先,使用高通滤波器去除低频成分,然后使用低通滤波器去除高频成分,从而得到带通滤波效果。 以下是一个简单的Python示例代码,演示了如何实现带通滤波算法: ```python import cv2 import numpy as np from matplotlib import pyplot as plt # 读取图像 img = cv2.imread('../paojie_g.jpg', 0) # 傅里叶变换 dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT) fshift = np.fft.fftshift(dft) # 设置带通滤波器 rows, cols = img.shape crow, ccol = int(rows/2), int(cols/2) mask = np.zeros((rows, cols, 2), np.uint8) mask\[crow-30:crow+30, ccol-30:ccol+30\] = 1 # 掩膜图像和频谱图像乘积 f = fshift * mask # 傅里叶逆变换 ishift = np.fft.ifftshift(f) iimg = cv2.idft(ishift) res = cv2.magnitude(iimg\[:,:,0\], iimg\[:,:,1\]) # 显示原始图像和带通滤波处理图像 plt.subplot(121), plt.imshow(img, 'gray'), plt.title('Original Image') plt.axis('off') plt.subplot(122), plt.imshow(res, 'gray'), plt.title('Band Pass Filter Image') plt.axis('off') plt.show() ``` 这段代码首先读取图像,然后进行傅里叶变换。接下来,根据图像大小设置中心位置,并创建一个带通滤波器的掩膜。然后,将频谱图像与掩膜相乘,再进行傅里叶逆变换,最后计算幅度谱并显示原始图像和带通滤波处理后的图像。 请注意,这只是一个简单的示例代码,实际应用中可能需要根据具体需求进行调整和优化。 #### 引用[.reference_title] - *1* [C++ 带通滤波](https://blog.csdn.net/hensonwells/article/details/109179909)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [python源码 高通滤波、低通滤波、带通滤波](https://blog.csdn.net/Ibelievesunshine/article/details/104987792)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值