OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 23699|回复: 13

【正点原子探索者STM32F407开发板例程连载+教学】第52章 DSP测试实验

[复制链接]

230

主题

1950

帖子

10

精华

论坛元老

Rank: 8Rank: 8

积分
4562
金钱
4562
注册时间
2010-12-14
在线时间
32 小时
发表于 2014-12-9 12:59:10 | 显示全部楼层 |阅读模式

第五十二章 DSP测试实验

 

1.硬件平台:正点原子探索者STM32F407开发板 
2.软件平台:MDK5.1 
3.固件库版本:V1.4.0

上一章,我们在ALIENTEK探索者STM32F4开发板上测试了STM32F4的硬件FPUSTM32F4除了集成硬件FPU外,还支持多种DSP指令集。同时ST还提供了一整套DSP库方便我们工程中开发应用。

本章,我们将指导大家入门STM32F4DSP,手把手教大家搭建DSP库测试环境,同时通过对DSP库中的几个基本数学功能函数和FFT快速傅里叶变换函数的测试,让大家对STM32F4DSP库有个基本的了解。本章分为如下几个部分:

52.1 DSP简介与环境搭建

52.2 硬件设计

52.3 软件设计

52.4 下载验证

 

52.1 DSP简介与环境搭建  

本节将分两个部分:1STM32F4 DSP简介;2DSP库运行环境搭建

52.1.1 STM32F4 DSP简介 

STM32F4采用Cortex-M4内核,相比Cortex-M3系列除了内置硬件FPU单元,在数字信号处理方面还增加了DSP指令集,支持诸如单周期乘加指令(MAC),优化的单指令多数据指令(SIMD),饱和算数等多种数字信号处理指令集。相比Cortex-M3Cortex-M4在数字信号处理能力方面得到了大大的提升。Cortex-M4执行所有的DSP指令集都可以在单周期内完成,而Cortex-M3需要多个指令和多个周期才能完成同样的功能。

接下来我们来看看Cortex-M4的两个DSP指令:MAC指令(32位乘法累加)和SIMD指令。

32位乘法累加(MAC)单元包括新的指令集,能够在单周期内完成一个 32×32+ 64à 64 的操作或两个16×16 的操作,其计算能力,如表52.1.1.1所示:

52.1.1.1 32位乘法累加(MAC)单元的计算能力

Cortex-M4支持SIMD指令集,这在Cortex-M3/M0系列是不可用的。上述表中的指令,有的属于SIMD指令。与硬件乘法器一起工作(MAC),使所有这些指令都能在单个周期内执行。受益于SIMD指令的支持,Cortex-M4处理器能在单周期内完成高达32×32+64à64的运算,为其他任务释放处理器的带宽,而不是被乘法和加法消耗运算资源。

比如一个比较复杂的运算:两个16×16乘法加上一个32位加法,如图52.1.1.2所示:

52.1.1.2 SUM运算过程

以上图片所示的运算,即:SUM = SUM +A* C+B *D),在STM32F4上面,可以被编译成由一条单周期指令完成。

上面我们简单的介绍了Cortex-M4DSP指令,接下来我们来介绍一下STM32F4DSP库。

STM32F4DSP库源码和测试实例在ST提供的标准库:stm32f4_dsp_stdperiph_lib.zip里面就有(该文件可以在:http://www.st.com/web/en/catalog/tools/FM147/CL1794/SC961/SS1743/P

F257901下载,文件名:STSW-STM32065),该文件在:光盘à 8STM32参考资料àSTM32F4xx固件库 文件夹里面,解压该文件,即可找到ST提供的DSP库,详细路径为:光盘à8STM32参考资料àSTM32F4xx固件库àSTM32F4xx_DSP_StdPeriph_Lib_V1.4.0àLibrariesàCMSISà

DSP_Lib,该文件夹下目录结构如图52.1.1.3所示:

52.1.1.3 DSP_Lib目录结构

DSP_Lib源码包的Source文件夹是所有DSP库的源码,Examples文件夹是相对应的一些测试实例。这些测试实例都是带main函数的,也就是拿到工程中可以直接使用。接下来我们一一讲解一下Source源码文件夹下面的子文件夹包含的DSP库的功能。

BasicMathFunctions

基本数学函数:提供浮点数的各种基本运算函数,如向量加减乘除等运算。

CommonTables

arm_common_tables.c文件提供位翻转或相关参数表。

ComplexMathFunctions

复杂数学功能,如向量处理,求模运算的。

ControllerFunctions

控制功能函数。包括正弦余弦,PID电机控制,矢量Clarke变换,矢量Clarke逆变换等。

FastMathFunctions

快速数学功能函数。提供了一种快速的近似正弦,余弦和平方根等相比CMSIS计算库要快的数学函数。

FilteringFunctions

滤波函数功能,主要为FIRLMS(最小均方根)等滤波函数。
MatrixFunctions

矩阵处理函数。包括矩阵加法、矩阵初始化、矩阵反、矩阵乘法、矩阵规模、矩阵减法、矩阵转置等函数。

StatisticsFunctions

统计功能函数。如求平均值、最大值、最小值、计算均方根RMS、计算方差/标准差等。
SupportFunctions

支持功能函数,如数据拷贝,Q格式和浮点格式相互转换,Q任意格式相互转换。
TransformFunctions

变换功能。包括复数FFTCFFT/复数FFT逆运算(CIFFT)、实数FFTRFFT/实数FFT逆运算(RIFFT)、和DCT(离散余弦变换)和配套的初始化函数。

       所有这些DSP库代码合在一起是比较多的,因此,ST为我们提了.lib格式的文件,方便使用。这些.lib文件就是由Source文件夹下的源码编译生成的,如果想看某个函数的源码,大家可以在Source文件夹下面查找。.lib格式文件路径:光盘à8STM32参考资料àSTM32F4xx固件库àSTM32F4xx_DSP_StdPeriph_Lib_V1.4.0àLibrariesàCMSISàLibàARM ,总共有8.lib文件,如下:

①  arm_cortexM0b_math.lib  (Cortex-M0大端模式)

②  arm_cortexM0l_math.lib   (Cortex-M0小端模式)

③  arm_cortexM3b_math.lib  (Cortex-M3大端模式)

④  arm_cortexM3l_math.lib   (Cortex-M3小端模式)

⑤  arm_cortexM4b_math.lib  (Cortex-M4大端模式)

⑥  arm_cortexM4bf_math.lib  (Cortex-M4小端模式)

⑦  arm_cortexM4l_math.lib   (浮点Cortex-M4大端模式)

⑧  arm_cortexM4lf_math.lib  (浮点Cortex-M4小端模式)

我们得根据所用MCU内核类型以及端模式来选择符合要求的.lib文件,本章我们所用的STM32F4属于CortexM4F内核,小端模式,应选择:arm_cortexM4lf_math.lib(浮点Cortex-M4小端模式)

       对于DSP_Lib的子文件夹Examples下面存放的文件,是ST官方提供的一些DSP测试代码,提供简短的测试程序,方便上手,有兴趣的朋友可以根据需要自行测试。

52.1.2 DSP库运行环境搭建     

本节我们将讲解怎么搭建DSP库运行环境,只要运行环境搭建好了,使用DSP库里面的函数来做相关处理就非常简单了。本节,我们将以上一章例程(实验46_1)为基础,搭建DSP运行环境。

MDK里面搭建STM32F4DSP运行环境(使用.lib方式)是很简单的,分为3个步骤:

1, 添加文件。

首先,我们在例程工程目录下新建:DSP_LIB文件夹,存放我们将要添加的文件:arm_cortexM4lf_math.lib和相关头文件,如图52.1.2.1所示:

52.1.2.1 DSP_LIB文件夹添加文件

其中arm_cortexM4lf_math.lib的由来,在52.1.1节已经介绍过了。Include文件夹,则是直接拷贝:STM32F4xx_DSP_StdPeriph_Lib_V1.4.0àLibrariesàCMSISàInclude 这个Include文件夹,里面包含了我们可能要用到的相关头文件。

然后,打开工程,新建DSP_LIB分组,并将arm_cortexM4lf_math.lib添加到工程里面,如图52.1.2.2所示:

52.1.2.2 添加.lib文件

       这样,添加文件就结束了(就添加了一个.lib文件)。

2, 添加头文件包含路径

添加好.lib文件后,我们要添加头文件包含路径,将第一步拷贝的Include文件夹和DSP_LIB文件夹,加入头文件包含路径,如图52.1.2.3所示:

52.1.2.3 添加相关头文件包含路径

3, 添加全局宏定义

最后,为了使用DSP库的所有功能,我们还需要添加几个全局宏定义:

1__FPU_USED

2__FPU_PRESENT

3ARM_MATH_CM4

4__CC_ARM

5ARM_MATH_MATRIX_CHECK

6ARM_MATH_ROUNDING

添加方法:点击àC/C++选项卡,然后在Define里面进行设置,如图52.1.2.4所示:

52.1.2.4 DSP库支持全局宏定义设置

这里,两个宏之间用“,”隔开。并且,上面的全局宏里面,我们没有添加__FPU_USED,因为这个宏定义在Target选项卡设置Code Generation的时候(上一章有介绍),选择了:Use FPU(如果没有设置Use FPU,则必须设置!!),故MDK会自动添加这个全局宏,因此不需要我们手动添加了。同时__FPU_PRESENT全局宏我们FPU实验已经讲解,这个宏定义在stm32f4xx.h头文件里面已经定义。这样,在Define处要输入的所有宏为:STM32F40_41xxx,USE_STDPERIPH_DRIVER,ARM_MATH_CM4,__CC_ARM,ARM_MATH_MATRIX_CHECK,ARM_MATH_ROUNDING 6个。

       至此,STM32F4DSP库运行环境就搭建完成了。

       特别注意,为了方便调试,本章例程我们将MDK的优化设置为-O0优化,以得到最好的调试效果。

52.2 硬件设计

本例程包含2个源码:实验47_1 DSP BasicMath测试实验47_2 DSP FFT测试,他们除了main.c里面内容不一样外,其他源码完全一模一样(包括MDK配置)。

实验47_1 DSP BasicMath测试 实验功能简介:测试STM32F4的DSP库基础数学函数:arm_cos_f32和arm_sin_f32和标准库基础数学函数:cosf和sinf的速度差别,并在LCD屏幕上面显示两者计算所用时间,DS0用于提示程序正在运行。

实验47_2 DSP FFT测试 实验功能简介:测试STM32F4的DSP 库的FFT函数,程序运行后,自动生成1024点测试序列,然后,每当KEY0按下后,调用DSP库的FFT算法(基4法)执行FFT运算,在LCD屏幕上面显示运算时间,同时将FFT结果输出到串口,DS0用于提示程序正在运行。

本实验用到的资源如下:

1,指示灯DS0

2KEY0按键

3,串口

4TFTLCD模块   

这些前面都已介绍过。

52.3 软件设计

本章代码,分成两个工程:1,实验47_1 DSP BasicMath测试;2,实验47_2 DSP FFT测试,接下来我们分别介绍。

52.3.1 DSP BasicMath测试

       这是我们使用STM32F4DSP库进行基础数学函数测试的一个例程。使用大家耳熟能详的公式进行计算:

sin(x)2+cos(x)2=1

       这里我们用到的就是sincos函数,不过实现方式不同。MDK的标准库(math.h)提供我们:sincossinfcosf4个函数,带f的表示单精度浮点型运算,即float型,而不带f的表示双精度浮点型,即double

       STM32F4DSP库,则提供我们另外两个函数:arm_sin_f32arm_cos_f32注意:需要添加:arm_math.h头文件才可使用!!!),这两个函数也是单精度浮点型的,用法同sinfcosf一模一样。

       本例程就是测试:arm_sin_f32& arm_cos_f32 sinf&cosf的速度差别。

       因为52.1.2节已经搭建好DSP库运行环境了,所以我们这里直接只需要修改main.c里面的代码即可,main.c代码如下:

#include "math.h"

#include "arm_math.h"   

#define    DELTA   0.000001f              //误差值

//sin cos测试   angle:起始角度  times:运算次数

//mode:0,不使用DSP;1,使用DSP

//返回值:0,成功;0XFF,出错

u8 sin_cos_test(float angle,u32 times,u8 mode)

{

       float sinx,cosx;

       float result;

       u32 i=0;

       if(mode==0)

       {

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

              {

                     cosx=cosf(angle);                 //不使用DSP优化的sincos函数

                     sinx=sinf(angle);

                     result=sinx*sinx+cosx*cosx; //计算结果应该等于

                     result=fabsf(result-1.0f);       //对比与1的差值

                     if(result>DELTA)return 0XFF;//判断失败

                     angle+=0.001f;                    //角度自增

              }

       }else

       {

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

              {

                     cosx=arm_cos_f32(angle);     //使用DSP优化的sincos函数

                     sinx=arm_sin_f32(angle);

                     result=sinx*sinx+cosx*cosx; //计算结果应该等于

                     result=fabsf(result-1.0f);       //对比与1的差值

                     if(result>DELTA)return 0XFF;//判断失败

                     angle+=0.001f;                    //角度自增

              }

       }

       return 0;//任务完成

}

u8 timeout;//定时器溢出次数

int main(void)

{    

       float time;

       u8 buf[50]; u8 res;

       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2

       delay_init(168);  //初始化延时函数

       uart_init(115200);         //初始化串口波特率为115200

       LED_Init();                         //初始化LED

       KEY_Init();                         //初始化按键

      LCD_Init();                         //初始化LCD

      TIM3_Int_Init(65535,8400-1);//10Khz计数频率,最大计时6.5秒超出

       POINT_COLOR=RED;

       LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");      

       LCD_ShowString(30,70,200,16,16,"DSP BasicMath TEST");   

       LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");

       LCD_ShowString(30,110,200,16,16,"2014/7/2");      

       LCD_ShowString(30,150,200,16,16," No DSP runtime:"); //显示提示信息

       LCD_ShowString(30,190,200,16,16,"Use DSP runtime:"); //显示提示信息    

      POINT_COLOR=BLUE;       //设置字体为蓝色  

       while(1)

       {

              LCD_Fill(30+16*8,150,lcddev.width-1,60,WHITE);          //清除原来现实

              //不使用DSP优化

              TIM_SetCounter(TIM3,0);//重设TIM3定时器的计数器值

              timeout=0;

              res=sin_cos_test(PI/6,200000,0);

              time=TIM_GetCounter(TIM3) +(u32)timeout*65536;

              sprintf((char*)buf,"%0.1fms\r\n",time/10);

              if(res==0)LCD_ShowString(30+16*8,150,100,16,16,buf); //显示运行时间           

              else LCD_ShowString(30+16*8,150,100,16,16,"error"); //显示当前运行情况    

              //使用DSP优化          

              TIM_SetCounter(TIM3,0);//重设TIM3定时器的计数器值

              timeout=0;

              res=sin_cos_test(PI/6,200000,1);

              time= TIM_GetCounter(TIM3)+(u32)timeout*65536;

              sprintf((char*)buf,"%0.1fms\r\n",time/10);

              if(res==0)LCD_ShowString(30+16*8,190,100,16,16,buf); //显示运行时间    

              else LCD_ShowString(30+16*8,190,100,16,16,"error"); //显示错误    

              LED0=!LED0;

       }

}

这里包括2个函数:sin_cos_testmain函数,sin_cos_test函数用于根据给定参数,执行

sin(x)2+cos(x)2=1

的计算。计算完后,计算结果同给定的误差值(DELTA)对比,如果不大于误差值,则认为计算成功,否则计算失败。该函数可以根据给定的模式参数(mode)来决定使用哪个基础数学函数执行运算,从而得出对比。

       main函数则比较简单,这里我们通过定时器3来统计sin_cos_test运行时间,从而得出对比数据。主循环里面,每次循环都会两次调用sin_cos_test函数,首先采用不使用DSP库方式计算,然后采用使用DSP库方式计算,并得出两次计算的时间,显示在LCD上面。

       DSP基础数学函数测试的程序设计就讲解到这里。

52.3.1 DSP FFT测试

       这是我们使用STM32F4DSP库进行FFT函数测试的一个例程。

首先,我们简单介绍下FFTFFT即快速傅里叶变换,可以将一个时域信号变换到频域。因为有些信号在时域上是很难看出什么特征的,但是如果变换到频域之后,就很容易看出特征了,这就是很多信号分析采用FFT变换的原因。另外,FFT可以将一个信号的频谱提取出来,这在频谱分析方面也是经常用的。简而言之,FFT就是将一个信号从时域变换到频域方便我们分析处理。

       在实际应用中,一般的处理过程是先对一个信号在时域进行采集,比如我们通过ADC,按照一定大小采样频率F去采集信号,采集N个点,那么通过对这N个点进行FFT运算,就可以得到这个信号的频谱特性。

这里还涉及到一个采样定理的概念:在进行模拟/数字信号的转换过程中,当采样频率F大于信号中最高频率fmax2倍时(F>2*fmax),采样之后的数字信号完整地保留了原始信号中的信息,采样定理又称奈奎斯特定理。举个简单的例子:比如我们正常人发声,频率范围一般在8KHz以内,那么我们要通过采样之后的数据来恢复声音,我们的采样频率必须为8KHz2倍以上,也就是必须大于16KHz才行。

模拟信号经过ADC采样之后,就变成了数字信号,采样得到的数字信号,就可以做FFT变换了。N个采样点数据,在经过FFT之后,就可以得到N个点的FFT结果。为了方便进行FFT运算,通常N2的整数次方。

假设采样频率为F,对一个信号采样,采样点数为N,那么FFT之后结果就是一个N点的复数,每一个点就对应着一个频率点(以基波频率为单位递增),这个点的模值(sqrt(实部2+虚部2))就是该频点频率值下的幅度特性。具体跟原始信号的幅度有什么关系呢?假设原始信号的峰值为A,那么FFT的结果的每个点(除了第一个点直流分量之外)的模值就是AN/2倍,而第一个点就是直流分量,它的模值就是直流分量的N倍。

这里还有个基波频率,也叫频率分辨率的概念,就是如果我们按照F的采样频率去采集一个信号,一共采集N个点,那么基波频率(频率分辨率)就是fk=F/N。这样,第n个点对应信号频率为:F*(n-1)/N;其中n1,当n=1时为直流分量。

       关于FFT我们就介绍到这。

       如果我们要自己实现FFT算法,对于不懂数字信号处理的朋友来说,是比较难的,不过,ST提供的STM32F4 DSP库里面就有FFT函数给我们调用,因此我们只需要知道如何使用这些函数,就可以迅速的完成FFT计算,而不需要自己学习数字信号处理,去编写代码了,大大方便了我们的开发。

       STM32F4DSP库里面,提供了定点和浮点 FFT实现方式,并且有基4的也有基2的,大家可以根据需要自由选择实现方式。注意:对于基4FFT输入点数必须是4n,而基2FFT输入点数则必须是2n,并且基4FFT算法要比基2的快。

本章我们将采用DSP库里面的基4浮点FFT算法来实现FFT变换,并计算每个点的模值,所用到的函数有:

arm_status arm_cfft_radix4_init_f32(

  arm_cfft_radix4_instance_f32 * S,

  uint16_t fftLen,uint8_t ifftFlag,uint8_t bitReverseFlag)

void arm_cfft_radix4_f32(const arm_cfft_radix4_instance_f32 * S,float32_t * pSrc)

void arm_cmplx_mag_f32(float32_t * pSrc,float32_t * pDst,uint32_t numSamples)

       第一个函数arm_cfft_radix4_init_f32,用于初始化FFT运算相关参数,其中:fftLen用于指定FFT长度(16/64/256/1024/4096),本章设置为1024ifftFlag用于指定是傅里叶变换(0)还是反傅里叶变换(1),本章设置为0bitReverseFlag用于设置是否按位取反,本章设置为1;最后,所有这些参数存储在一个arm_cfft_radix4_instance_f32结构体指针S里面。

       第二个函数arm_cfft_radix4_f32就是执行基4浮点FFT运算的,pSrc传入采集到的输入信号数据(实部+虚部形式),同时FFT变换后的数据,也按顺序存放在pSrc里面,pSrc必须大于等于2fftLen长度。另外,S结构体指针参数是先由arm_cfft_radix4_init_f32函数设置好,然后传入该函数的。

       第三个函数arm_cmplx_mag_f32用于计算复数模值,可以对FFT变换后的结果数据,执行取模操作。pSrc为复数输入数组(大小为2*numSamples)指针,指向FFT变换后的结果;pDst为输出数组(大小为numSamples)指针,存储取模后的值;numSamples就是总共有多少个数据需要取模。

       通过这三个函数,我们便可以完成FFT计算,并取模值。本节例程(实验47_2 DSP FFT测试)同样是在52.1.2节已经搭建好DSP库运行环境上面修改代码,只需要修改main.c里面的代码即可,本例程main.c代码如下:

#include "math.h"

#include "arm_math.h"    

#define FFT_LENGTH         1024      //FFT长度,默认是1024FFT

float fft_inputbuf[FFT_LENGTH*2];   //FFT输入数组

float fft_outputbuf[FFT_LENGTH];     //FFT输出数组

u8 timeout;//定时器溢出次数

int main(void)

{    

    arm_cfft_radix4_instance_f32 scfft;

      u8 key,t=0;   float time;

       u8 buf[50];   u16 i;

       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2

       delay_init(168);  //初始化延时函数

       uart_init(115200);         //初始化串口波特率为115200

       LED_Init();                         //初始化LED

       KEY_Init();                         //初始化按键

      LCD_Init();                         //初始化LCD

       TIM3_Int_Init(65535,84-1);  //1Mhz计数频率,最大计时65ms左右超出

      POINT_COLOR=RED;

       LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");      

       LCD_ShowString(30,70,200,16,16,"DSP FFT TEST");     

       LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");

       LCD_ShowString(30,110,200,16,16,"2014/7/2");      

       LCD_ShowString(30,130,200,16,16,"KEY0:Run FFT");    //显示提示信息

       LCD_ShowString(30,160,200,16,16,"FFT runtime:");              //显示FFT执行时间

      POINT_COLOR=BLUE;       //设置字体为蓝色  

       arm_cfft_radix4_init_f32(&scfft,FFT_LENGTH,0,1);//初始化scfft结构体,设定FFT参数

      while(1)

       {

              key=KEY_Scan(0);

              if(key==KEY0_PRES)

              {

                     for(i=0;i<FFT_LENGTH;i++)//生成信号序列

                     {                                

                             fft_inputbuf[2*i]=100+

                                               10*arm_sin_f32(2*PI*i/FFT_LENGTH)+

                                                        30*arm_sin_f32(2*PI*i*4/FFT_LENGTH)+

                                            50*arm_cos_f32(2*PI*i*8/FFT_LENGTH); //实部

                 fft_inputbuf[2*i+1]=0;//虚部全部为0

                     }

                     TIM_SetCounter(TIM3,0);//重设TIM3定时器的计数器值

                     timeout=0;

                     arm_cfft_radix4_f32(&scfft,fft_inputbuf);          //FFT计算(基4

                     time= TIM_GetCounter(TIM3)+(u32)timeout*65536;              //计算所用时间

                     sprintf((char*)buf,"%0.3fms\r\n",time/1000);    

                     LCD_ShowString(30+12*8,160,100,16,16,buf);  //显示运行时间           

                     arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT_LENGTH);//取模得幅值

                     printf("\r\n%d point FFT runtime:%0.3fms\r\n",FFT_LENGTH,time/1000);

                     printf("FFT Result:\r\n");

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

                     {

                            printf("fft_outputbuf[%d]:%f\r\n",i,fft_outputbuf);

                     }

              }else delay_ms(10);

              t++;

              if((t%10)==0)LED0=!LED0;               

       }

}

       以上代码只有一个main函数,里面通过我们前面介绍的三个函数:arm_cfft_radix4_init_f32

arm_cfft_radix4_f32arm_cmplx_mag_f32来执行FFT变换并取模值。每当按下KEY0就会重新生成一个输入信号序列,并执行一次FFT计算,将arm_cfft_radix4_f32所用时间统计出来,显示在LCD屏幕上面,同时将取模后的模值通过串口打印出来。

       这里,我们在程序上生成了一个输入信号序列用于测试,输入信号序列表达式:

fft_inputbuf[2*i]=100+

                    10*arm_sin_f32(2*PI*i/FFT_LENGTH)+

                            30*arm_sin_f32(2*PI*i*4/FFT_LENGTH)+

                50*arm_cos_f32(2*PI*i*8/FFT_LENGTH); //实部

       通过该表达式我们可知,信号的直流分量为100,外加2个正弦信号和一个余弦信号,其幅值分别为103050

       关于输出结果分析,请看52.4节,软件设计我们就介绍到这里。

 

52.4 下载验证

代码编译成功之后,便可以下载到我们的探索者STM32F4开发板上验证了。

对于实验47_1 DSP BasicMath测试,下载后,可以在屏幕看到两种实现方式的速度差别,如图52.4.1所示:

说明: 说明: C:\Users\Administrator\Desktop\F407教程文档资料\例程图片\DSP_basicmath测试.jpg

52.4.1使用DSP库和不使用DSP库的基础数学函数速度对比

从图中可以看出,使用DSP库的基础数学函数计算所用时间比不使用DSP库的短,使用STM32F4DSP库,速度上面比传统的实现方式提升了约17%

对于实验47_2 DSP FFT测试,下载后,屏幕显示提示信息,然后我们按下KEY0就可以看到FFT运算所耗时间,如图52.4.2所示:

说明: 说明: C:\Users\Administrator\Desktop\F407教程文档资料\例程图片\DSP_FFT测试.jpg

52.4.2 FFT测试界面

可以看到,STM32F4采用基4法计算1024个浮点数的FFT,只用了0.584ms,速度是相当快的了。同时,可以在串口看到FFT变换取模后的各频点模值,如图52.4.3所示:

52.4.3 FFT变换后个频点模值

查看所有数据,会发现:第01481016102010237个点的值比较大,其他点的值都很小,接下来我们就简单分析一下这些数据。

由于FFT变换后的结果具有对称性,所以,实际上有用的数据,只有前半部分,后半部分和前半部分是对称关系,比如1102341020,81016等,就是对称关系,因此我们只需要分析前半部分数据即可。这样,就只有第0148这四个点,比较大,重点分析。

假设我们采样频率为1024Hz,那么总共采集1024个点,频率分辨率就是1Hz,对应到频谱上面,两个点之间的间隔就是1Hz。因此,上面我们生成的三个叠加信号:10*sin(2*PI*i/1024)+ 30*sin(2*PI*i*4/1024)+50*cos(2*PI*i*8/1024),频率分别是:1Hz4Hz8Hz

对于上述4个值比较大的点,结合52.3.1节的知识,很容易分析得出:第0点,即直流分量,其FFT变换后的模值应该是原始信号幅值的N倍,N=1024,所以值是100*1024=102400,与理论完全一样,然后其他点,模值应该是原始信号幅值的N/2倍,即10*51230*51250*512,而我们计算结果是:5119.99902315360256000,除了第1个点,稍微有点点误差(说明精度上有损失),其他同理论值完全一致。

       DSP测试实验,我们就讲解到这里,DSP库的其他测试实例,大家可以自行研究下,我们这里就不再介绍了。

 

实验详细手册和源码下载地址:http://www.openedv.com/posts/list/41586.htm 

正点原子探索者STM32F407开发板购买地址http://item.taobao.com/item.htm?id=41855882779

  


实验47 DSP测试实验.zip

8.35 MB, 下载次数: 3363

第五十二章 DSP测试实验-STM32F4开发指南-正点原子探索者STM32开发板.pdf

885.18 KB, 下载次数: 1472

我是开源电子网?网站管理员,对网站有任何问题,请与我联系!QQ:389063473Email:389063473@qq.com
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

13

主题

57

帖子

0

精华

初级会员

Rank: 2

积分
193
金钱
193
注册时间
2014-9-11
在线时间
15 小时
发表于 2015-4-30 16:46:10 | 显示全部楼层
回复 支持 反对

使用道具 举报

0

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
83
金钱
83
注册时间
2013-10-22
在线时间
15 小时
发表于 2015-5-10 22:21:36 | 显示全部楼层
mark一下
回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
23
金钱
23
注册时间
2015-4-15
在线时间
0 小时
发表于 2015-6-5 22:17:57 | 显示全部楼层
支持原子哥,很不错,狠细致的讲解!大爱!
回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
23
金钱
23
注册时间
2015-4-15
在线时间
0 小时
发表于 2015-6-5 22:50:38 | 显示全部楼层
原子哥,“ bitReverseFlag用于设置是否按位取反,本章设置为1”,设为1到底是不是按位取反了呢,按位取反在这里是怎么个意义呢?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-6-5 23:55:38 | 显示全部楼层
回复【5楼】Huangogo:
---------------------------------
你分别测试下,看看结果,对比下数据。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

1

主题

3

帖子

0

精华

新手上路

积分
35
金钱
35
注册时间
2015-7-2
在线时间
2 小时
发表于 2015-7-2 08:19:19 | 显示全部楼层
原子哥,请问一下M4内核给的一些SIMD指令,比如SMLALBB,我在实际程序编写时直接调用__SMLALBB();但是提示没有定义,这些指令定义在哪里呢?我在库里面找到core_cm4_simd.h,但是文章中“图52.1.1.1 32位乘法累加(MAC)单元的计算能力”里面的某些指令并没有,比如SMULBB,SMLALBB等。如果我想用这些指令应该怎么做?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-7-2 21:17:44 | 显示全部楼层
回复【7楼】xysyc0571:
---------------------------------
写汇编。。。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

1

主题

3

帖子

0

精华

新手上路

积分
35
金钱
35
注册时间
2015-7-2
在线时间
2 小时
发表于 2015-7-3 10:02:30 | 显示全部楼层
回复【8楼】正点原子:
---------------------------------
汇编不会写,伤不起
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
23
金钱
23
注册时间
2015-12-10
在线时间
0 小时
发表于 2015-12-10 22:55:54 | 显示全部楼层
请教原子哥,如果离散信号直接接入,管脚应该怎么连,输入信号应该怎么编写?新人菜鸟望指点
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-12-10 23:45:23 | 显示全部楼层
回复【10楼】caicaii:
---------------------------------
从哪里采集,就接哪个脚
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
2
金钱
2
注册时间
2016-1-18
在线时间
0 小时
发表于 2016-1-18 06:47:09 | 显示全部楼层
本帖最后由 atde 于 2016-1-18 06:52 编辑

请教原子哥,打开这个程序就出现这个问题
原子哥.png
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
23
金钱
23
注册时间
2015-12-10
在线时间
0 小时
发表于 2016-1-26 05:56:13 | 显示全部楼层
正点原子 发表于 2015-12-10 23:45
回复【10楼】caicaii:
---------------------------------
从哪里采集,就接哪个脚

原子哥,还有一问题请教,可否在FFT之后先加窗滤波然后再取最大值呢?多谢多谢
回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
31
金钱
31
注册时间
2020-9-7
在线时间
9 小时
发表于 2021-7-17 11:12:48 | 显示全部楼层
不错的样子
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 12:05

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表