一阶低通滤波的C语言实现
一阶低通滤波器(Low Pass Filter,LPF),核心参数为截止频率fc,该算法可以保留截止频率以内的信号,而衰减截止频率之外的信号。主要用于去除高频噪声。
一阶低通滤波公式如下:

也可以写作:

其中:

参数说明:y(n)为本次滤波输出值,y(n-1)为上次滤波输出值,x(n)为本次采样值。Ts为采样周期,fc为截止频率。α范围为[0,1]
我们假设,现在有一个信号,它包含了频率为1Hz(幅值为3)和4Hz(幅值为1)的两个正弦波。


如图所示:黄色为叠加后的信号。
我们假定采样周期为0.02s,且需要保留1Hz的信号(那么截止频率应该在1Hz~4Hz之间,先取1Hz)。
则

即

t=(0:0.02:5);
x=3*sin(2*pi*1*t)+1*sin(2*pi*4*t);%采集的混合信号
plot(t,x);
hold on
fc=2;%截止频率
Ts=0.02;%采样周期
b=2*pi*fc*Ts;
alpha=b/(b+1);%alpha
y=zeros(1,251);
y(1)=x(1)
for n= 2:251
y(n)=y(n-1)+alpha*(x(n)-y(n-1));%一阶滤波
end
plot(t,y);

我们将滤波后的波形和理论的1Hz的波形对比:

你会发现:
因此,一阶低通滤波,存在滞后的现象。那么我们可以适当修改一下α,比如,将截止频率设置为2Hz,再看看效果。

你会发现:
对于一阶低通滤波器,截止频率应在有效信号频率和杂波频率之间。
越接近有效信号频率,则滤波效果越强,但存在相位更加滞后,幅度衰减越厉害的情况。
因此,应该多次设值,从而寻找一个能够兼顾响应速度与滤波效果的值。
虽然在网上看到别人写的c语言实现,但基本是原理说明,搬过来没办法直接使用,还要修修改改的,就很难受。
我这里模拟采集信号的过程,写一个c语言的实现。主要添加了一个模拟输入的效果,数据其实就是从matlab里面复制出来的:x=3*sin(2*pi*1*t)+1*sin(2*pi*4*t)。
#include <stdio.h>
#include <string.h>
/*************************** 模拟输入数据 ********************************/
float input_data[251] = {
0.00, 0.86, 1.59, 2.10, 2.35, 2.35, 2.18, 1.94, 1.76, 1.73, 1.90, 2.26, 2.75,
3.24, 3.63, 3.80, 3.70, 3.30, 2.68, 1.93, 1.18, 0.54, 0.11, -0.10, -0.11,
0.00, 0.11, 0.10, -0.11, -0.54, -1.18, -1.93, -2.68, -3.30, -3.70, -3.80,
-3.63, -3.24, -2.75, -2.26, -1.90, -1.73, -1.76, -1.94, -2.18, -2.35, -2.35,
-2.10, -1.59, -0.86, 0.00, 0.86, 1.59, 2.10, 2.35, 2.35, 2.18, 1.94, 1.76,
1.73, 1.90, 2.26, 2.75, 3.24, 3.63, 3.80, 3.70, 3.30, 2.68, 1.93, 1.18,
0.54, 0.11, -0.10, -0.11, 0.00, 0.11, 0.10, -0.11, -0.54, -1.18, -1.93,
-2.68, -3.30, -3.70, -3.80, -3.63, -3.24, -2.75, -2.26, -1.90, -1.73,
-1.76, -1.94, -2.18, -2.35, -2.35, -2.10, -1.59, -0.86, 0.00, 0.86, 1.59,
2.10, 2.35, 2.35, 2.18, 1.94, 1.76, 1.73, 1.90, 2.26, 2.75, 3.24, 3.63,
3.80, 3.70, 3.30, 2.68, 1.93, 1.18, 0.54, 0.11, -0.10, -0.11, 0.00, 0.11,
0.10, -0.11, -0.54, -1.18, -1.93, -2.68, -3.30, -3.70, -3.80, -3.63, -3.24,
-2.75, -2.26, -1.90, -1.73, -1.76, -1.94, -2.18, -2.35, -2.35, -2.10, -1.59,
-0.86, 0.00, 0.86, 1.59, 2.10, 2.35, 2.35, 2.18, 1.94, 1.76, 1.73, 1.90, 2.26,
2.75, 3.24, 3.63, 3.80, 3.70, 3.30, 2.68, 1.93, 1.18, 0.54, 0.11, -0.10, -0.11,
0.00, 0.11, 0.10, -0.11, -0.54, -1.18, -1.93, -2.68, -3.30, -3.70, -3.80, -3.63,
-3.24, -2.75, -2.26, -1.90, -1.73, -1.76, -1.94, -2.18, -2.35, -2.35, -2.10, -1.59,
-0.86, 0.00, 0.86, 1.59, 2.10, 2.35, 2.35, 2.18, 1.94, 1.76, 1.73, 1.90, 2.26, 2.75,
3.24, 3.63, 3.80, 3.70, 3.30, 2.68, 1.93, 1.18, 0.54, 0.11, -0.10, -0.11, 0.00, 0.11,
0.10, -0.11, -0.54, -1.18, -1.93, -2.68, -3.30, -3.70, -3.80, -3.63, -3.24, -2.75,
-2.26, -1.90, -1.73, -1.76, -1.94, -2.18, -2.35, -2.35, -2.10, -1.59, -0.86, 0.00};
float get_data(void)
{
static int i = 0;
return (input_data[i++]);
if (i == 251) //轮回
i = 0;
}
float fc = 2.0f; //截止频率
float Ts = 0.02f; //采样周期
float pi = 3.14159f; //π
float alpha = 0; //滤波系数
/************************ 滤波器初始化 alpha *****************************/
void low_pass_filter_init(void)
{
float b = 2.0 * pi * fc * Ts;
alpha = b / (b + 1);
}
float low_pass_filter(float value)
{
static float out_last = 0; //上一次滤波值
float out;
/***************** 如果第一次进入,则给 out_last 赋值 ******************/
static char fisrt_flag = 1;
if (fisrt_flag == 1)
{
fisrt_flag = 0;
out_last = value;
}
/*************************** 一阶滤波 *********************************/
out = out_last + alpha * (value - out_last);
out_last = out;
return out;
}
void main(void)
{
float result[251];
low_pass_filter_init();
for (int i = 0; i < 251; i++)
{
result[i] = low_pass_filter(get_data());
printf("%f,", result[i]);
}
}
我这里使用的是VSCode,将终端输出的数据直接复制到matlab加点代码就可以观察了。(excel也行,但插入数据后会坨在一格里,要点击分列)。
效果如下:


有时候,我们想先分析我们的数据的频率组成,或者观察滤波效果,我们可以观察他们的频率。这里用的是快速傅里叶变换。
这里分析X=3*sin(2*pi*1*t)+1*sin(2*pi*4*t),代码如下:
t=(0:0.02:5);% 时间向量
X=3*sin(2*pi*1*t)+1*sin(2*pi*4*t);%采集的混合信号
Ts = 0.02; % 采样周期
Fs = 1/Ts; % 采样频率
L = length(t); % 获取信号长度
n = 2^nextpow2(L);%首先从原始信号长度确定下一个 2 次幂的新输入长度。这将用尾随零填充信号 X 以改善 fft 的性能。
%%%%%%%%%%%%%%%%%%%%%%% 快速傅里叶变换 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Y = fft(X,n);%信号的傅里叶变换
P2 = abs(Y/n);%计算双侧频谱 P2
P1 = P2(1:n/2+1);%基于 P2 和偶数信号长度 L 计算单侧频谱 P1。
P1(2:end-1) = 2*P1(2:end-1);%双侧边变成单侧侧边,幅度叠加
f = Fs*(0:(n/2))/n;%定义频域 f
plot(f,P1)
title('Single-Sided Amplitude Spectrum of X(t)')
xlabel('f (Hz)')
ylabel('|P1(f)|')

我们将之前代码的滤波输出(fc=2)直接赋值给X,进行观察:


可以看到,频率为4Hz的信号幅度衰减超过一半,而1Hz的衰减非常少。说明效果还是不错的。
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。
我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来