我是靠谱客的博主 单身心锁,最近开发中收集的这篇文章主要介绍java 移动平均_手把手教系列之移动平均滤波器实现,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

[导读]:前面一篇文章关于IIR设计的文章,还是有朋友点开来阅读。虽不知看官们的感想如何,但想着总还是有赏光一读,所以决定继续这个系列。本文来聊一聊平均滤波器,这题目咋一看非常容易。但个人觉得里面一些关键要点未必都明了,本文主要关注xx一维平均滤波器设计内在机理、应用场景。

注:尽量在每篇文章写写摘要,方便阅读。信息时代,大家时间都很宝贵,如此亦可节约粉丝们的宝贵时间。

理论理解

学习一样东西,个人建议须从三个维度进行:What Why How

这里的内容主要参考胡广书编写的<>7.5.1节,加了一些自己的理解。

提到平均滤波器,做过单片机应用开发的朋友,马上能想到将一些采样数据进行加和求平均。诚然如此,从其时域数学描述而言也很直观:

$$

begin{align*}

y(n)&=frac{1}{N}sum_{k=0}^Nx(n-k)&=frac{1}{N}[x(n)+...+x(n-N+1)]

end{align*}

$$

其中$x(n)$代表当前测量值,对于单片机应用而言,可以是当前ADC的采样值或者当前传感器经过一系列处理的物理量(比如在工业控制领域中的温度、压力、流量等测量值),而$x(n-1)$表示上一次的测量值,以此类推,$x(n-N+1)$则是前第N-1次测量值。

为了揭示其更深层次的机理,这里用Z传递函数将上述公式进一步描述:

$$

begin{align*}

H(Z)&=frac{1}{N}sum_{k=0}^NZ^{-N}&=frac{1}{N}frac{1-Z^{-N}}{1-Z^{-1}}

end{align*}

$$

对于傅立叶变换而言:

$$

X(omega)=sum_{k=-infty}^{infty}x(n)e^{-jomega{n}}

$$

Z变换的本质是拉普拉斯变换的离散化形式,$Z=e^{sigma+jomega}=e^{sigma}e^{jomega}$,令$e^{sigma}=r$,则

$$

X(Z)=sum_{k=-infty}^{infty}x(n)(re^{jomega})^{-n}

$$

令$r=1$,则

$$

X(Z)=sum_{k=-infty}^{infty}x(n)e^{jomega{n}}

$$

所以,平均滤波器的频率响应为:

$$

begin{align*}

H(e^{jomega})&=frac{1}{N}frac{1-e^{-j{omega}N}}{1-e^{-jomega}}&=frac{1}{N}e^{-jfrac{omega(N-1)}{2}}frac{sinomega{N}{/2}}{sin{omega/2}}

end{align*}

$$

幅频相频分析

利用下面的python代码,来分析一下

# encoding: UTF-8

from scipy.optimize import newton

from scipy.signal import freqz, dimpulse, dstep

from math import sin, cos, sqrt, pi

import numpy as np

import matplotlib.pyplot as plt

import sys

reload(sys)

sys.setdefaultencoding('utf8')

#函数用于计算移动平均滤波器的截止频率

def get_filter_cutoff(N, **kwargs):

func = lambda w: sin(N*w/2) - N/sqrt(2) * sin(w/2)

deriv = lambda w: cos(N*w/2) * N/2 - N/sqrt(2) * cos(w/2) / 2

omega_0 = pi/N # Starting condition: halfway the first period of sin

return newton(func, omega_0, deriv, **kwargs)

#设置采样率

sample_rate = 200 #Hz

N = 7

# 计算截止频率

w_c = get_filter_cutoff(N)

cutoff_freq = w_c * sample_rate / (2 * pi)

# 滤波器参数

b = np.ones(N)

a = np.array([N] + [0]*(N-1))

#频率响应

w, h = freqz(b, a, worN=4096)

#转为频率

w *= sample_rate / (2 * pi)

#绘制波特图

plt.subplot(2, 1, 1)

plt.suptitle("Bode")

#转换为分贝

plt.plot(w, 20 * np.log10(abs(h)))

plt.ylabel('Magnitude [dB]')

plt.xlim(0, sample_rate / 2)

plt.ylim(-60, 10)

plt.axvline(cutoff_freq, color='red')

plt.axhline(-3.01, linewidth=0.8, color='black', linestyle=':')

# 相频响应

plt.subplot(2, 1, 2)

plt.plot(w, 180 * np.angle(h) / pi)

plt.xlabel('Frequency [Hz]')

plt.ylabel('Phase [°]')

plt.xlim(0, sample_rate / 2)

plt.ylim(-180, 90)

plt.yticks([-180, -135, -90, -45, 0, 45, 90])

plt.axvline(cutoff_freq, color='red')

plt.show()

取采样率为200Hz,滤波器长度为7可得下面的幅频、相频响应曲线。从其主瓣可见其幅频响应为一低通滤波器。幅频响应略有不平,随频率上升而衰减。其相频响应线性。如果对滤波器有经验的朋友会知道FIR滤波器的相频响应是线性的,而移动平均滤波器刚好是FIR的一种特例。

25b1a1656c0304a746a2f0668a796808.png

当改变滤波器长度为3/7/21时,仅观察其幅频响应:

f599f2611635784f1c992cf9987d1647.png

可见,随着滤波器的长度变长,其截止频率变小,其通带变窄。滤波器的响应变慢,延迟变大。所以实际使用的时候,须根据有用频率带宽合理选择滤波器的长度。有用信号的带宽可以通过按采样率采集一定的点进行傅立叶分析可得。如果有带FFT功能的示波器,也可以直接测量得到。

滤波器的C实现

滤波器的C语言实现,比较容易。这里将代码共享再此:

#define MVF_LENGTH 5

typedef float E_SAMPLE;

/*定义移动平均寄存器历史状态*/

typedef struct _t_MAF

{

E_SAMPLE buffer[MVF_LENGTH];

E_SAMPLE sum;

int index;

}t_MAF;

void moving_average_filter_init(t_MAF * pMaf)

{

pMaf->index = -1;

pMaf->sum = 0;

}

E_SAMPLE moving_average_filter(t_MAF * pMaf,E_SAMPLE xn)

{

E_SAMPLE yn=0;

int i=0;

if(pMaf->index == -1)

{

for(i = 0; i < MVF_LENGTH; i++)

{

pMaf->buffer[i] = xn;

}

pMaf->sum = xn*MVF_LENGTH;

pMaf->index = 0;

}

else

{

if(xn>100)

xn = xn+0.1;

pMaf->sum -= pMaf->buffer[pMaf->index];

pMaf->buffer[pMaf->index] = xn;

pMaf->sum += xn;

pMaf->index++;

if(pMaf->index>=MVF_LENGTH)

pMaf->index = 0;

}

yn = pMaf->sum/MVF_LENGTH;

return yn;

}

测试代码:

#define SAMPLE_RATE 500.0f

#define SAMPLE_SIZE 256

#define PI 3.415926f

int main()

{

E_SAMPLE rawSin[SAMPLE_SIZE];

E_SAMPLE outSin[SAMPLE_SIZE];

E_SAMPLE rawSquare[SAMPLE_SIZE];

E_SAMPLE outSquare[SAMPLE_SIZE];

t_MAF mvf;

FILE *pFile=fopen("./simulationSin.csv","wt+");

/*正弦信号测试*/

if(pFile==NULL)

{

printf("simulationSin.csv opened failed");

return -1;

}

for(int i=0;i

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[手把手教系列之移动平均滤波器实现]http://www.zyiz.net/tech/detail-135430.html

最后

以上就是单身心锁为你收集整理的java 移动平均_手把手教系列之移动平均滤波器实现的全部内容,希望文章能够帮你解决java 移动平均_手把手教系列之移动平均滤波器实现所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部