首页 > 其他分享 >【安富莱二代示波器教程】第10章 示波器设计—数字信号处理

【安富莱二代示波器教程】第10章 示波器设计—数字信号处理

时间:2022-10-13 10:33:09浏览次数:87  
标签:FIR 10 DSO1 FFT 2048 示波器 f32 安富 arm

第10章      示波器设计—数字信号处理

本章节为大家讲解二代示波器中用到的FFT和FIR。单纯从应用上来说,比较省事,调用API函数即可,从学习的角度来说,需要大家花点精力。

10.1     FFT快速傅里叶变变换

10.2     FIR有限冲击响应滤波器

10.3      总结

 

 

10.1  FFT快速傅里叶变换

二代示波器中做了2048点的浮点FFT。具体实现是采用ARM的DSP库函数arm_rfft_fast_f32。

/*

*********************************************************************************************************

* 函 数 名: DSO1_WaveProcess

* 功能说明: 波形通道1的FFT,FIR,最大值,最小值,平均值,峰峰值,频率和RMS的计算

* 形 参: 无。

* 返 回 值: 无

*********************************************************************************************************

*/

void DSO1_WaveProcess(void)

{

uint16_t i;

uint32_t uiCycle, uiCount = 0;



/* 省略其它 */



/* 自动触发模式才计算FFT */

if(TriggerFlag == 0)

{

/* 前10种采样率计算FFT */

if(TimeBaseId < 10)

{

/* 执行2048点浮点FFT运算 */

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

{

testInput_fft_2048[i] = g_DSO1->usWaveBufTemp[i];

}



/* 2048点实序列快速FFT, 浮点 */

arm_rfft_fast_f32(&S, testInput_fft_2048, testOutput_fft_2048, ifftFlag);



/* 求1204点的幅值 */

arm_cmplx_mag_f32(testOutput_fft_2048, testInput_fft_2048, 1024);



/* 获得最大的幅值和所在的位置 */

uiCycle = testInput_fft_2048[1];



for(i = 2; i < 1024; i++)

{

if(uiCycle < testInput_fft_2048[i])

{

uiCycle =testInput_fft_2048[i];

uiCount = i;

}

}



/* 估算频率 */

g_DSO1->uiFreq = uiCount * g_SampleFreqTable[TimeBaseId][0] / 2048;

}

/* 省略其它 */

}

/* 省略其它 */

}

上面的代码中对采集的2048点数据做浮点FFT处理,并求出幅频响应,方便示波器上频谱的展示。同时代码中也做了一个简单的波形频率估计,这个估计仅适合周期性的正弦波,方波。

(1)对于正弦波而言,它经过FFT后,理想的幅频响应就是一根线,所以根据这个特性,只要找出幅频响应中幅值最大的值即可,它所对应的频率位置就是波形的频率。

(2)对于方波而言,它经过FFT后,理想的幅频响应就跟手机信号一样(中间有间隔),方波是由无限多个正弦波叠加而成的,其中第一个幅值最高的就是基波,也是方波的频率。

当前提供的方法仅适合估算,要提高精度的话需要对更多的点做FFT,或者采样率正好是波形频率的整数倍,这样可以有效降低频谱泄露,准确率较高。当然,这种方法的操作难度有点大,因为我们不知道波形频率是多少,求得就是波形频率。

关于FFT的计算,大家可以直接看我们的DSP教程,有详细讲解,务必优先看第25章,对FFT变换结果的物理意义有个认识,然后再看其它章节:​​http://forum.armfly.com/forum.php?mod=viewthread&tid=3886​​ 。

 

10.2  FIR有限冲击响应滤波器

二代示波器的FIR滤波控制界面如下:

 

【安富莱二代示波器教程】第10章 示波器设计—数字信号处理_数据

做了一个80阶低通FIR滤波器,分别可以在2Msps采样率,200Ksps采样率和20Ksps采样率下工作。每个采样率下做了7种截止频率。

FIR滤波在信号处理任务里面被调用:

/*

*********************************************************************************************************

* 函 数 名: DSO1_WaveProcess

* 功能说明: 波形通道1的FFT,FIR,最大值,最小值,平均值,峰峰值,频率和RMS的计算

* 形 参: 无。

* 返 回 值: 无

*********************************************************************************************************

*/

void DSO1_WaveProcess(void)

{

uint16_t i;

uint32_t uiCycle, uiCount = 0;





/* 省略其它 */



/* 自动触发模式才计算FFT */

if(TriggerFlag == 0)

{

/* 省略其它 */



/* 前10种采样率计算FFT */

if(TimeBaseId < 10)

{

/* 执行650点,80阶Fir滤波器 */

/* 单通道2Msps */

if((TimeBaseId == 1)&&(g_DSO1->ucFirFlter_Step100KHz !=0 ))

{

DSO_FirFilter_Step100KHz();

}



/* 单通道200Ksps */

if((TimeBaseId == 4)&&(g_DSO1->ucFirFlter_Step10KHz !=0 ))

{

DSO_FirFilter_Step10KHz();

}



/* 单通道20Ksps */

if((TimeBaseId == 7)&&(g_DSO1->ucFirFlter_Step1KHz !=0 ))

{

DSO_FirFilter_Step1KHz();

}

}

}

/* 省略其它 */

}

根据不同的采样率,分别做了个处理,我们这里以函数DSO_FirFilter_Step100KHz()为例进行说明。这个函数的实现如下:

#define FIR_LENGTH_SAMPLES   650    /* 采样点数 */

#define BLOCK_SIZE 650 /* 调用一次arm_fir_f32处理的采样点个数 */

#define NUM_TAPS 81 /* 滤波器系数个数 */

#define FIR_StateBufSize BLOCK_SIZE + NUM_TAPS - 1



/*

*********************************************************************************************************

* 滤波器系数

*********************************************************************************************************

*/

/* 80阶FIR低通滤波器系数 通过fadtool获取系数 Fs = 2Msps, Fc = 100KHz */

const float32_t firCoeffs32LP_100KHz[NUM_TAPS] = {

-3.126438727e-19f,-0.0002058673272f,-0.0004228431499f,-0.0006468905485f,-0.0008642434841f,

-0.001048665727f,-0.001161655295f,-0.001156177954f,-0.0009838859551f,-0.0006050768425f,

8.391786605e-19f,0.0008203662583f, 0.00180617522f, 0.002865221584f, 0.003865677863f,

0.004645895679f, 0.005031134468f, 0.004856021609f, 0.00399050815f, 0.002366269007f,

-2.110346192e-18f,-0.002989985514f,-0.006377025973f,-0.009831513278f, -0.01293939352f,

-0.0152332196f, -0.01623356342f, -0.01549717132f, -0.01266706176f, -0.007519159f,

3.381513724e-18f, 0.009749332443f, 0.0213866625f, 0.03438147902f, 0.04804687202f,

0.06158847734f, 0.07416618615f, 0.08496309072f, 0.09325480461f, 0.09847255051f,

0.1002533659f, 0.09847255051f, 0.09325480461f, 0.08496309072f, 0.07416618615f,

0.06158847734f, 0.04804687202f, 0.03438147902f, 0.0213866625f, 0.009749332443f,

3.381513724e-18f, -0.007519159f, -0.01266706176f, -0.01549717132f, -0.01623356342f,

-0.0152332196f, -0.01293939352f,-0.009831513278f,-0.006377025973f,-0.002989985514f,

-2.110346192e-18f, 0.002366269007f, 0.00399050815f, 0.004856021609f, 0.005031134468f,

0.004645895679f, 0.003865677863f, 0.002865221584f, 0.00180617522f,0.0008203662583f,

8.391786605e-19f,-0.0006050768425f,-0.0009838859551f,-0.001156177954f,-0.001161655295f,

-0.001048665727f,-0.0008642434841f,-0.0006468905485f,-0.0004228431499f,-0.0002058673272f,

-3.126438727e-19f

};



/* 其它截止频率对应的系数未贴出 */



/*

*********************************************************************************************************

* 函 数 名: DSO_FirFilter_Step100KHz

* 功能说明: FIR滤波器。

* 形 参: 无

* 返 回 值: 无

*********************************************************************************************************

*/

void DSO_FirFilter_Step100KHz(void)

{

arm_fir_instance_f32 S;

uint16_t i;



/* 获取要滤波的数值 */

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

{

FirDataInput[i] =g_DSO1->usWaveBufTemp[i+g_DSO1->sCurTriPos+g_DSO1->sCurTriStep];

}



/* FIR低通滤波器,截止频率100KHz */

if(g_DSO1->ucFirFlter_Step100KHz == 1)

{

arm_fir_init_f32(&S, NUM_TAPS, (float32_t *)&firCoeffs32LP_100KHz[0], &firStateF32[0], BLOCK_SIZE);

}

/* FIR低通滤波器,截止频率200KHz */

else if(g_DSO1->ucFirFlter_Step100KHz == 2)

{

arm_fir_init_f32(&S, NUM_TAPS, (float32_t *)&firCoeffs32LP_200KHz[0], &firStateF32[0], BLOCK_SIZE);

}

/* FIR低通滤波器,截止频率300KHz */

else if(g_DSO1->ucFirFlter_Step100KHz == 3)

{

arm_fir_init_f32(&S, NUM_TAPS, (float32_t *)&firCoeffs32LP_300KHz[0], &firStateF32[0], BLOCK_SIZE);

}

/* FIR低通滤波器,截止频率400KHz */

else if(g_DSO1->ucFirFlter_Step100KHz == 4)

{

arm_fir_init_f32(&S, NUM_TAPS, (float32_t *)&firCoeffs32LP_400KHz[0], &firStateF32[0], BLOCK_SIZE);

}

/* FIR低通滤波器,截止频率500KHz */

else if(g_DSO1->ucFirFlter_Step100KHz == 5)

{

arm_fir_init_f32(&S, NUM_TAPS, (float32_t *)&firCoeffs32LP_500KHz[0], &firStateF32[0], BLOCK_SIZE);

}

/* FIR低通滤波器,截止频率600KHz */

else if(g_DSO1->ucFirFlter_Step100KHz == 6)

{

arm_fir_init_f32(&S, NUM_TAPS, (float32_t *)&firCoeffs32LP_600KHz[0], &firStateF32[0], BLOCK_SIZE);

}

/* FIR低通滤波器,截止频率700KHz */

else if(g_DSO1->ucFirFlter_Step100KHz == 7)

{

arm_fir_init_f32(&S, NUM_TAPS, (float32_t *)&firCoeffs32LP_700KHz[0], &firStateF32[0], BLOCK_SIZE);

}



/* 80阶FIR滤波 */

arm_fir_f32(&S, FirDataInput, FirDataOutput, BLOCK_SIZE);



·

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

{

g_DSO1->usWaveBuf[i] =FirDataOutput[i+50];

}

}

上面的代码中有三个重要的地方:

(1)滤波器系数的生成,使用Matlab的fdatool工具箱即可,详情可以学习我们DSP教程的第37章节,有详细讲解:​​http://forum.armfly.com/forum.php?mod=viewthread&tid=3886​​ 。如果初学的话,可以按照教程讲解实际动手生成一次,看看跟代码中的系数是否一致,一致的话,说明已经成功生成。

(2)FIR滤波器有一个重要的概念就是群延迟,当波形经过FIR滤波器后,输出的波形会有一定的延迟。对于线性相位的FIR,这个群延迟就是一个常数。但是实际应用中这个群延迟是多少呢,关于群延迟的数值,Matlab的fdatool 工具箱会根据用户的配置计算好。比如我们这里设计的80阶FIR低通滤波器的群延迟就是40,反应在实际的采样值上就是滤波后输出数据的第41个才是实际滤波后的波形数据起始点。

程序中为了方便起见,每次都是处理650个数据,直接使用滤波结果的后600个数据。更多关于延迟的知识,看我们DSP教程第37章的37.8小节即可。

(3)FIR滤波器涉及到的函数arm_fir_init_f32和arm_fir_f32也是在DSP教程第37章进行了讲解。

 

关于二代示波器的FIR滤波器设计就为大家说这么多,更多这方面的知识需要学习我们的DSP教程。

 

10.3  总结

如果大家不熟悉FFT和FIR的话,务必要优先学习我们DSP教程的相关章节,磨刀不费砍柴工。有了一定的认识后,再来二代示波器的基础上做实战演练即可。

 

微信公众号:armfly_com


标签:FIR,10,DSO1,FFT,2048,示波器,f32,安富,arm
From: https://blog.51cto.com/u_15785540/5752538

相关文章

  • 【安富莱二代示波器教程】第8章 示波器设计—测量功能
    第8章       示波器设计—测量功能二代示波器测量功能实现比较简单,使用2D函数绘制即可。不过也专门开辟一个章节,为大家做一个简单的说明,方便理解。8.1  水平测......
  • P1004 [NOIP2000 提高组] 方格取数
    P1004[NOIP2000提高组]方格取数题目描述设有\(N\timesN\)的方格图\((N\le9)\),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字\(0\)。如下图所示(......
  • part2-HOT100+剑指Offer
    leetcode:​​https://leetcode-cn.com/problemset/algorithms/​​​类别:热题HOT100easy篇共26道No.21--------------可将滑动窗口作为一个章节来看啦。。。标签:哈希......
  • 关于一个人类智慧的DP - Vijos 1037 搭建双塔 题解
    关于一个人类智慧的DP-Vijos1037搭建双塔目录关于一个人类智慧的DP-Vijos1037搭建双塔更好的阅读体验戳此进入题面输入格式ExamplesSolutionCodeCode-C++98(JDO......
  • 负数补码(16进制转10进制的负数)
    假如我想通过modbustcp接收设备上传的报文,该设备显示为负数,但报文上无法解析出来(温度报文异常,负数无法显示与转换)。这时候,我就需要对这个报文进行负数补码形式,16进制转10......
  • 代码随想录训练营|Day 23|669,108,538,总结
    669.TrimaBinarySearchTreeGiventhe root ofabinarysearchtreeandthelowestandhighestboundariesas low and high,trimthetreesothatallits......
  • 2022.10.13实现callable接口
    实现callable接口(了解即可)实现callable接口,需要返回值类型重写call方法,需要抛出异常创建目标对象创建执行服务:ExecutorServiceser=Executor.newFixedThread......
  • W10 启动 RabbitMQ 教程
       启动服务   1.进入rabbitmq的安装sbin目录下cmd进入命令窗口          2.cmd输入命令rabbitmq-server.bat,如图启动成功    ......
  • TypeScript 诞生 10 周年
    TypeScript诞生10周年来源:OSCHINA编辑: 局2022-10-1008:05:15 7TypeScript已经诞生10年了。10年前——2012年10月1日,TypeScript 首次公......
  • 【Vegas共享】.VB.net 与C# 的代码转换 [08-03-10 Update]
    ​​http://www.harding.edu/USER/fmccown/WWW/vbnet_csharp_comparison.html​​​C#代码与VB.net代码的转换的工具:​​http://authors.aspalliance.com/aldotnet/exam......