数字滤波器(6)—FIR频域连续滤波“重叠相加法”C++源码
[编者按]传感器和信号处理仅一线之隔,信号的前后端合理搭配,是我们更准确地感知这个世界的一种基本态度和方式。
FIR频域重叠相加法
还记得我们(此处有重复之嫌)之前的发文《FIR连续采样分段卷积时域重叠相加法》?不过那是在时域处理的模拟和仿真。这次我们的内容是用C++在频域实现的滤波卷积法,仍然是重叠相加法,届时大家可以比较一下两种方式的差异。
基本是通过两个处理过程。
(1)频域的重叠相加法示意图再拿来用一下。如下图所示[1]。
(2)再借用一下的时域卷积经傅里叶FFT变换后,在频域成为对应的相乘;然后再通过IFFT将中间结果转换回时域时序结果。
让我们直接跳进话题,先看模拟测试结果,后看C++源码。
模拟情节设定
50Hz选频滤波,信号中混有110Hz和210H在的干扰信号和幅值为1的直流DC。
模拟信号及其频谱的输出请查看我们前面的文章。这里的代码只提供将模拟信号进行了频域重叠相加处理,生成的滤波前后模拟信号和被滤波处理后的数据波形的比较(见下图)。
还记得我们(此处重复)之前用C++来模拟时域处理的滤波模拟程序吗?
你又猜对了,又是那个滤波器,又被用上了!但,是不同的实现处理方式。
滤波处理之前的波形和频谱图
滤波之后,直流和其他频率的信号已经不见,只留下50Hz的正弦波(见下图)。
频域重叠相加滤波前后的波形比较
图由csv文件处理后生成。又见此图,是不是有熟悉的感觉?
频域连续滤波模拟和验证C++源码
/*
Project Name: Demonstration & Validation for signal filtering via the
"Overlap-Add" method implemented through FFT/IFFT based on Fast Fourier Transform (FFT)
based on the Cooley-Tukey algorithm.
Copyright (c) 2024 Amphenol Sensors
Author: L.L.
This software is provided 'as-is', without any express or implied
warranty and for simulation/demostration purpose. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
*/
#include <complex>
#include <cmath>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <fstream>
#include <math.h>
#include <algorithm>
const double PI = 3.1415926535897932384;
const double SAMPLE_RATE = 1000.0; // 1000Hz
const int N = 1024; // 假设采样分段数为1024
using namespace std; // 声明使用std命名空间
#define SEL_FFT 0
#define SEL_IFFT 1
#define SEL_FFTIFFT 2
#define SIM_CYCLE_CNT 3.0
// 模拟信号函数
vector<complex<double>> generateSignal(double sampleRate, double seconds)
{
size_t signal_len = (size_t)(sampleRate * seconds);
vector<complex<double>> signal(signal_len); // 定义模拟信号的数组长度
for (size_t i = 0; i < signal_len; ++i)
{
// 包含50Hz和110Hz,210Hz信号,DC
signal[i].real(1+ sin((2 * PI * (double)i * 50) / sampleRate) + sin((2 * PI * (double)i * 210) / sampleRate) + sin((2 * PI * (double)i * 110) / sampleRate));
signal[i].imag(0);
}
return signal;
}
// 基于Cooley-Tukey算法的FFT
void fft2(vector<complex<double>> &x)
{
size_t n = x.size();
if (n <= 1)
return;
// 把序列分为奇偶两部分
vector<complex<double>> even(n / 2), odd(n / 2);
for (size_t i = 0; 2 * i < n; i++)
{
even[i] = x[i * 2];
odd[i] = x[i * 2 + 1];
}
// 递归解决每一个序列
fft2(even);
fft2(odd);
// 结合步骤
for (size_t i = 0; 2 * i < n; i++)
{
complex<double> t = polar(1.0, -2 * PI * (double)i / (double)n) * odd[i];
x[i] = even[i] + t;
x[i + n / 2] = even[i] - t;
}
}
// 基于Cooley-Tukey算法的IFFT
void ifft2(vector<complex<double>> &x)
{
size_t n = x.size();
if (n <= 1)
return;
vector<complex<double>> even(n / 2), odd(n / 2);
for (size_t i = 0; 2 * i < n; i++)
{
even[i] = x[i * 2];
odd[i] = x[i * 2 + 1];
}
ifft2(even);
ifft2(odd);
for (size_t i = 0; 2 * i < n; i++)
{
complex<double> t = polar(1.0, 2 * PI * (double)i /(double) n) * odd[i];
x[i] = even[i] + t;
x[i + n / 2] = even[i] - t;
}
// 最后除以n
if (n > 1)
{
for (size_t i = 0; i < n; i++)
{
x[i] /= 2;
}
}
}
// 将数据写入文件
void writeToFile(const vector<complex<double>> &Original_signal, const vector<complex<double>> &Proceeded_Signal, const string &filename, int Type_sel)
{
ofstream file(filename);
if (Type_sel==SEL_FFTIFFT)
{
file << "time(s)" << ", " << "Original Signal"<< ", " << "Filtered Signal" << "\n";
for (size_t i = 0; i < Original_signal.size(); i++)
{
file << (double)i / SAMPLE_RATE << ", " <<Original_signal[i].real() << ", "<< Proceeded_Signal[i].real() << "\n";
}
}
file.close();
}
// 测试模拟程序
int main()
{
//FIR filter:50Hz选频FIR滤波器
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};
// (1) Resize filter coefficients
vector<complex<double>> H(b.size());
for(size_t i=0; i< b.size(); i++)
{
H[i] = complex<double>(b[i],0);
}
H.resize(N, complex<double>(0.0, 0.0));
// (2)Generate simulation data sequences
size_t DataSeg_len_L = N - b.size() + 1; // Data segmeng Length = L
double daq_duration = (double)DataSeg_len_L * SIM_CYCLE_CNT / SAMPLE_RATE;
vector<complex<double>>Original_signal = generateSignal(SAMPLE_RATE, daq_duration); // Generate data sequence, L * 3
// (3-1) Define a 2-D vector,3 columns, to simulate DAQ and filtering process for 3 rounds
vector<vector<complex<double>>> seg_Dates(3);
// (3-2) Initialize data segment
for (size_t i = 0; i < seg_Dates.size(); i++)
{
seg_Dates[i].resize(DataSeg_len_L,complex<double>(0.0, 0.0));
// devide Original_signal into 3 parts to simulate consequent DAQ for 3 cycles
for(size_t j=0; j<DataSeg_len_L;j++)
{
seg_Dates[i][j] = Original_signal[i * DataSeg_len_L + j];
}
seg_Dates[i].resize(N, complex<double>(0.0, 0.0)); // resize each data segment to N = L + M - 1
}
// (4) Start to FFT/IFFT and generate involution result
vector<complex<double>> Filtered_signal(DataSeg_len_L * (size_t)(SIM_CYCLE_CNT) + b.size() -1 ); //L * 3 + (M - 1)
fft2(H);
// (4-1) Simulate 3 cycles of involution: L * 3
for(size_t i=0; i< seg_Dates.size(); i++)
{
fft2(seg_Dates[i]);
for(size_t j = 0; j< seg_Dates[i].size(); j++)
{
seg_Dates[i][j] = seg_Dates[i][j] * H[j];
}
ifft2(seg_Dates[i]);
for(size_t k = 0; k< seg_Dates[i].size(); k++)
{
Filtered_signal[i*DataSeg_len_L + k] += seg_Dates[i][k];
}
}
// (5) Save Origianl signal & result (data after filtering) into csv file
writeToFile(Original_signal, Filtered_signal,"output_Filtered2.csv", SEL_FFTIFFT);
return 0;
}
时间仓促,有些功能和细节并没有考虑太多,这里功能验证是第一。
FFT/IFFT是基于库里-图基的算法,各位可以选用其他的来优化替代;
有些参数可以单独变,有些参数却是关联的。
[1]《数字信号处理—原理、算法与应用》,第四版,普鲁克斯著,方艳梅等译,北京电子工业出版社,2014.8
- |
- +1 赞 0
- 收藏
- 评论 0
本文由赵优秀转载自AMPHENOL SENSORS 微信公众号,原文标题为:数字滤波器(6)—FIR频域连续滤波“重叠相加法”C++源码,本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。
相关研发服务和供应服务
相关推荐
【经验】SGX传感器技术电化学气体传感器用电子电路的设计提供指导
本文为Amphenol Sensors旗下SGX传感器技术电化学气体传感器的电子电路设计提供指导。
流量传感器(2)超声流量传感器—相位差和信号相关性原理
之前我们简单介绍了基于差压的流量传感器,这次我们要开始基于超声的流量计。超声流量计是一种测量液体或气体流量的仪器,其工作原理基于超声波在介质中传播的特性。这种流量计可以在无需接触或干扰流体本身的情况下进行测量,因此被广泛应用于各种工业环境,尤其是在需要无接触或无损测量的场合。
数字滤波器C语言的模拟及验证
本文通过一个带通滤波器的Python验证,再转换到C++代码模拟验证的实现过程说明数字滤波器是如何工作的。我们先通过Python测试验证,并生成滤波器的参数数据。然后将获取的参数用到C程序中重现滤波器。
解析数字滤波器(1)——陷波滤波器
有鉴于数字信号处理涉及的面太多,我们必须要把话题收缩。数字滤波的种类也是五花八门,因此再选一个小的类型,AMPHENOL SENSORS将围绕离散线性时不变系统来简单讨论一下陷波滤波器(Notch Filter)和梳状滤波器(Comb Filter),通过代码的演示和输出,我们可以比较一下这两类滤波器的特点。在本文中先以陷波滤波器为题来讨论相关的内容。
解析数字滤波器(2)——梳状滤波器及相关话题
本文AMPHENOL SENSORS将围绕但不限于梳状滤波器进行展开。其中,梳状滤波器,一方面可以滤除特定的频率(尤其是特定频率的谐波),另一方面也可以在信号中对指定频率及其倍频的信号进行拣选。例如图-1所示的滤除指定谐波成分的梳状滤波器的幅频图。
Amphenol Sensors(安费诺)/All Sensors 压力传感器选型指南(简版)
目录- 传感器解决方案及产品优势介绍 传感器技术介绍 单芯片压力传感器 双芯电路交叉耦合补偿压力传感器 双芯电路和气路交叉耦合补偿压力传感器 传感器应用领域介绍 压力单位换算 传感器通用名词解释
型号- DLH,ADCX,ACPC-C,AXCA,ACPC,BLV,DLV,ACPC-H,AXCA-PRIME,AXCA-MIDDLE,MAMP,MLV,SAMP,ACPC-P,BLC,ADUX,BLVR,MAMP-/P,ADCA,DLH,DLVR,DLVR,BLCR,MAMP-P,MDCX,ADO,BLV,AXCX-PRIME-INCH,DLHR,DLHR,AXCX,MLV,AXCA-MIL,BLC,DLC,ADO-MIL
Amphenol Sensors(安费诺) 汽车传感器选型指南
目录- 汽车传感器解决方案介绍 车厢空气质量系列传感器 排放处理系列传感器 新能源汽车传感器应用 测量汽车应用中最为关键的参数
型号- SM-UART-01L,PT200,T6703,TPMS,DPS,G-CAP2,SM-UART-01D,A2103,NPI-19,T6713,A-2102,EGR,A-2103,NPP-301,GE-1935,A-2121,ZTP,DPF,SM-UART-01L+,SM-PWM-01C,NPX1
Amphenol Sensors(安费诺)/Nova Sensor 压力传感器及敏感元件选型指南
目录- P1300低压硅压力传感器芯片 P1302低压硅压力传感器芯片 P111中压硅压力传感器芯片 P883(5~15000 PSI)硅压力传感器芯片 P1602硅压力传感器芯片 P122 高压硅压力传感器芯片 NPC-100系列一次性医疗压力传感器 NPC-1210系列低压系列固态压力传感器 NPC-1220系列中压传感器 NPH系列固态压力传感器(中低压) NPI-12卫生型压力传感器、不锈钢介质隔离压力传感器 NPI-15VC系列电压激励、高压、介质隔离压力传感器 NPI-15系列电流激励高压、介质隔离压力传感器 NPI-19系列电压激励、中压、介质隔离压力传感器 NPI-19系列电流激励、中压、介质隔离压力传感器 NPI-19低压不锈钢介质隔离压力传感器 NPP-301系列贴片封装压力传感器 NPA贴片式压力传感器 NPR-101系列复杂介质压力传感器 Modus T系列微差压力传感器 压力变送器IPT1000/2000系列
型号- NPP-301B-700AT,IPT1000,51243,51245,51003,51244,NPP-301A-100AT,51005,51367,51004,51007,51006,51009,NPI-19X-YYYZZ,51008,51407,51406,NPI-15X-YYYZZ,51409,51408,NPP-301A-200A,NPH-XYYY-ZZ,51010,51012,51254,51011,51253,51013,NPA-300,NPR-101,51137,NPA-700,NPH系列,NPP-301B-200A,NPI-12,NPI-19X-XXXXV,P1602,NPI-15,NPP-301B-200AT,NPI-19,NPA100,NPI-15X-XXXXX,51142,MODUS T,51421,NPI-15X-XXXXXX,51304,51303,NPI-15C-C00903,NPP-301B-700A,51391,NPC-1210XXXX-YZ,51151,51393,51392,51395,NPI-19A-031GH,T10,51394,51031,51397,51399,51313,51433,51314,NPC-100T,51317,51318,NPP-301A-100A,P1302,NPC-100,P1300,51041,51283,NPI-19A-021GH,51282,T20,51045,51322,51046,51445,51324,51444,51323,51326,51325,51328,51327,51329,NPI-19A-002GV,NPI-15VC,NPP-301A-200AT,IPT2000,T30,NPC-1220XXXX-YZ,51298,51331,NPA-500,51330,51333,51299,51332,51335,51334,NPI-19X-XXXXXV,51337,51336,51339,51338,NPP-301B-100A,NPP-301B-100AT,NPA,T系列,P122,P883,NPH,NPI-19A-C01841,NPI-19A-C01840,NPP-301A-700A,T40,51340,NPP-301,51342,51187,51341,NPI-12-101GH,NPI-1,NPC-1220,NPP-301A-700AT,P111,51076,NPC-1210,51114
代理传感器顶尖品牌:TE、安费诺、IDT、迈来芯、ROHM、可天士、SMI等15家
为满足工程师在研发过程中对不同品类产品的需求,世强元件电商不断为客户引进顶级的品牌、多样的产品品类。截至目前,平台授权代理的传感器品牌已有15家。平台VIP用户可免费获取来自原厂的最新产品和技术资讯、官方资料库,以低于行业的价格,购买原厂最新元器件和零件产品,享受供货保障。
Wilcoxon 振动传感器产品
描述- 本资料介绍了Amphenol Sensors提供的多种振动监测传感器产品,包括安装在旋转设备轴承箱上的振动传感器、加速度传感器、速度传感器和双输出传感器等。涵盖了不同型号的产品特性,如灵敏度、频率响应范围、共振频率、电器噪音、最高工作温度等参数,并提供相应的应用场景和建议。此外,还介绍了4-20mA变送器和智能振动信号传输模块等产品,旨在为用户提供全面的振动监测解决方案。
型号- 787T,LPA100T,786LF,PC420A,PCC421A,787A,731A,PC420DPP-40,797T-1,793V-5,PC420V,PCC420V,893V,793T-3,786T,IT300,IT301,780B,780A,780C,799LF,PCC420A,786LF-500,786A,797V,731P31,LPA100T-D2,787-500,793V,PCC421V
安费诺先进传感器的MEMS传感器提供最先进的高性能、高性价比的传感器解决方案
NovaSensor(Amphenol Advanced Sensors的子品牌)的MEMS传感器其准确度、可靠性和尺寸大小而闻名于世,NovaSensor的传感器在医疗、运输和工业等领域的应用中提供最佳性能解决方案。
电子商城
品牌:AMPHENOL SENSORS
品类:Assembly NTC temperature sensor
价格:¥5.0624
现货: 2,000
品牌:AMPHENOL SENSORS
品类:Surface Mount Pressure Sensors
价格:¥97.5000
现货: 51
品牌:AMPHENOL SENSORS
品类:Air Quality Sensors IR LED Dust Sensor
价格:¥40.5000
现货: 35
品牌:AMPHENOL SENSORS
品类:Board Mount Pressure Sensors
价格:¥253.8839
现货: 30
品牌:AMPHENOL SENSORS
品类:Board Mount Pressure Sensors
价格:¥253.8839
现货: 25
品牌:AMPHENOL SENSORS
品类:Board Mount Pressure Sensors
价格:¥227.5314
现货: 25
品牌:AMPHENOL SENSORS
品类:Low Pressure Compact Sensors
价格:¥125.9778
现货: 25
品牌:AMPHENOL SENSORS
品类:Board Mount Pressure Sensors
价格:¥227.5314
现货: 25
现货市场
品牌:SILICON LABS
品类:Switch Hall Effect Magnetic Position Sensor
价格:¥2.2924
现货:126,000
服务
可定制板装式压力传感器支持产品量程从5inch水柱到100 psi气压;数字输出压力传感器压力范围0.5~60inH2O,温度补偿范围-20~85ºС;模拟和数字低压传感器可以直接与微控制器通信,具备多种小型SIP和DIP封装可选择。
提交需求>
可定制温度范围-230℃~1150℃、精度可达±0.1°C;支持NTC传感器、PTC传感器、数字式温度传感器、热电堆温度传感器的额定量程和输出/外形尺寸/工作温度范围等参数定制。
提交需求>
登录 | 立即注册
提交评论