数字滤波器(3)——C语言的模拟及验证
图-1 滤波器的幅频响应(50Hz窄带带通)
图-2 模拟信号的滤波前后
图-3 模拟信号滤波前后的频谱图
相关python代码:
import numpy as np
from scipy.signal import firwin, freqz, lfilter
import matplotlib.pyplot as plt
fs = 1000.0 # Sample frequency (Hz)
f0 = 50.0 # Frequency to be removed from signal (Hz)
Q = 30.0 # Quality factor
w0 = f0/(fs/2) # Normalized Frequency
# Design band-pass filter
b = firwin(81, [w0 - 0.02, w0 + 0.02], pass_zero=False, window='hamming')
# Output coefficients, we got the coefficients from this step
b_string = ', '.join(str(coef) for i, coef in enumerate(b))
print('{', b_string, '}')
# Generate frequency response
w, h = freqz(b, [1], worN=1024)
# Convert to Hz
freq = w * fs / (2 * np.pi)
# Plot filter response
plt.plot(freq, abs(h))
plt.title('Filter Frequency Response')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Gain')
plt.grid(True)
plt.show()
# Create a test signal
t = np.arange(0, 1.0, 1/fs) # Time vector
# Test signal
signal = np.sin(2*np.pi*210*t) + np.sin(2*np.pi*50*t) + np.sin(2*np.pi*110*t)
# Apply filter to the test signal
filtered_signal = lfilter(b, [1], signal)
# Original signal & filtered signal
plt.figure(figsize=(12, 8))
plt.subplot(211)
plt.plot(t[:500], signal[:500], color='blue')
plt.title('Original Signal')
plt.xlabel('Time [s]')
plt.grid()
plt.subplot(212)
plt.plot(t[:500], filtered_signal[:500], color='red')
plt.title('Filtered Signal')
plt.xlabel('Time [s]')
plt.tight_layout()
plt.grid()
plt.show()
# Compute and plot the frequency spectrum of signals
N = len(signal)
T = 1/fs
xf = np.linspace(0.0, 1.0/(2.0*T), N//2) # Frequency vector
# Compute FFT of original and filtered signals
fft_signal = np.fft.fft(signal)
fft_filtered = np.fft.fft(filtered_signal)
# Plot FFT of original signal
plt.figure(figsize=(12, 8))
plt.subplot(211)
plt.plot(xf, 2.0/N * np.abs(fft_signal[0:N//2]), color='blue')
plt.title('Original Signal FFT')
plt.xlabel('Frequency [Hz]')
plt.grid()
# Plot FFT of filtered signal
plt.subplot(212)
plt.plot(xf, 2.0/N * np.abs(fft_filtered[0:N//2]), color='red')
plt.title('Filtered Signal FFT')
plt.xlabel('Frequency [Hz]')
plt.grid()
plt.tight_layout()
plt.show()
-
滤波器通过C++语言的功能复现和验证。
图-4 模拟信号经C++滤波器的前后波形(取部分,请对照图-2)
以下为滤波器的C++代码,大家可以再优化。直接上代码。
#include <stdio.h>
#include <iostream>
#include <vector>
#include <fstream>
#include <math.h>
#define SAMPLE_RATE 1000.0
using namespace std; // 声明使用std命名空间
const double pi = 3.14159265358979323846;
// 模拟信号函数
vector<double> generateSignal(int sampleRate, int seconds){
vector<double>signal(sampleRate * seconds); //定义模拟信号的数组长度
for (unsigned int i = 0; i < (unsigned int)(sampleRate * seconds); ++i){
// 包含50Hz,110Hz和210Hz信号
signal[i] = sin((2 * pi * i * 50) / sampleRate) + sin((2 * pi * i * 210) / sampleRate) + sin((2 * pi * i * 110) / sampleRate);
}
return signal;
}
// 滤波器函数
vector<double> filter(const vector<double>& b, const vector<double>& a, const vector<double> &signal){
vector<double> output(signal.size());
for (size_t i = 0; i < signal.size(); ++i)
{
for (size_t j = 0; j < b.size(); ++j){
if (i >= j){
output[i] += b[j] * signal[i - j];
}
}
for (size_t j = 1; j < a.size(); ++j){
if (i >= j){
output[i] -= a[j] * output[i - j];
}
}
output[i] /= a[0];
}
return output;
}
// 写入文件函数
void writeToFile(const vector<double>& signal, const vector<double>& filtered_signal, const string &filename)
{
ofstream file(filename);
for (std::size_t i = 0; i < signal.size(); i++)
{
file << i/SAMPLE_RATE << ", " << signal[i] <<", "<< filtered_signal[i]<< "\n";
}
}
// 主函数
int main()
{
// 系数
vector<double>b{0.0010175493084400998,0.0010954624020866333, 0.001080635650435545, 0.0009293052645812359,0.0005868808563577278, -8.138309855847798e-19, -0.0008644147524968251, -0.0019966389877814107, -0.003323586744207458, -0.004696461345361978, -0.005892320462621699, -0.006633249964255378, -0.006623614506478284, -0.005601944833604465, -0.0034001773970723163, -7.334366341273803e-18, 0.004425290874832446, 0.00949426225087417, 0.014634010415364655, 0.019132982942933127, 0.022226796444847933, 0.023207550009729024, 0.021541722692400025, 0.01697833945185371, 0.009628503914736117, -6.755395515820625e-18, -0.01102370844120733, -0.02226281209657117, -0.032372473621654914, -0.04001099412924139, -0.04402269970024527, -0.043609484958132556, -0.03846490807520255, -0.028848803480728435, -0.015588116829396594, -9.10410551538968e-18, 0.016255406162706088, 0.031374390998733945, 0.04363491329762711, 0.051616779739690075, 0.05438594145724075, 0.051616779739690075, 0.04363491329762711, 0.031374390998733945, 0.016255406162706088, -9.10410551538968e-18, -0.015588116829396594, -0.028848803480728435, -0.03846490807520255, -0.043609484958132556, -0.04402269970024527, -0.0400109941292414, -0.032372473621654914, -0.022262812096571168, -0.01102370844120733, -6.755395515820627e-18, 0.009628503914736117, 0.016978339451853702, 0.021541722692400025, 0.023207550009729034, 0.022226796444847933, 0.01913298294293312, 0.014634010415364655, 0.009494262250874175, 0.004425290874832446, -7.3343663412738e-18, -0.0034001773970723163, -0.005601944833604469, -0.006623614506478284, -0.006633249964255374, -0.005892320462621699, -0.00469646134536198, -0.003323586744207458, -0.001996638987781409, -0.0008644147524968251, -8.138309855847805e-19, 0.0005868808563577278, 0.0009293052645812359, 0.001080635650435545, 0.0010954624020866333, 0.0010175493084400998};
vector<double> a{1};
// 生成模拟信号
vector<double> signal = generateSignal(1000, 1); // 1秒的模拟信号
// 滤波处理
vector<double> output = filter(b, a, signal);
// 写入至csv文件
writeToFile(signal, output, "output.csv");
return 0;
}