转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38023431

通过前面的介绍我们知道。声音信号要通过AD转换,变成我们可以处理的数字信号,然后再交给FFT进行处理。

一.ADC转换

1.设置引脚

void GPIO_Init()					 	// GPIO口的初始化
{
P1M1 = B(00000011); //设置P1口模式
P1M0 = B(00000000); //设置P1口模式 仅仅有1.0和1.1为开漏,用于AD
P1 = B(00000011);
P1ASF = B(00000011); //将P10,P11的IO设置为模拟输入功能。
}

2.ADC初始化

void ADC_Init()							// 集成ADC的初始化(官方函数)
{
ADC_RES = 0; //Clear previous result
ADC_CONTR = ADC_POWER | ADC_SPEEDLL; //ADC_SPEEDLL,每次转换须要420个时钟周期。420*0.04=16.8us
Delay(2); //ADC power-on and delay
}

3.ADC转换

uchar GetADCResult(uchar ch)		   	// 进行AD转换(官方函数)
{
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
_nop_(); //Must wait before inquiry
_nop_();
_nop_();
_nop_();
while (!(ADC_CONTR & ADC_FLAG));//Wait complete flag
ADC_CONTR &= ~ADC_FLAG; //Close ADC
return ADC_RES; //Return ADC result
}

二.FFT

FFT(Fast Fourier Transformation),即为高速傅氏变换。是离散傅氏变换的高速算法,它是依据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。

1.实现的根本:时域到频域

从这张图我们清晰的看到,左面的就是我们输入的信号,右面就是输出到点阵上面的信号。中间的转换过程由FFT实现。

2.算法实现

float code iw[32]=
{
1.000,0.000, /* 0.9952,-0.0980,*/ 0.9808,-0.1951, /*0.9569,-0.2903,*/ 0.9239,-0.3827, /*0.8819,-0.4714,*/ 0.8315,-0.5556,
/*0.7730,-0.6344,*/ 0.7071,-0.7071, /* 0.6344,-0.7730,*/ 0.5556,-0.8315, /* 0.4714,-0.8819,*/ 0.3827,-0.9239, /*0.2903,-0.9569, */
0.1951,-0.9808, /*0.0980,-0.9952,*/ 0.0,-1.0000, /*-0.0980,-0.9952,*/ -0.1951,-0.9808, /* -0.2903,0.9569,*/ -0.3827,-0.9239,
/*-0.4714,-0.8819, */ -0.5556,-0.8315, /* -0.6344,-0.7730, */ -0.7071,-0.7071, /* -0.7730,-0.6344, */ -0.8315,-0.5556, /* -0.8819,-0.4714, */
-0.9239,-0.3827, /* -0.9569,-0.2903,*/ -0.9808,-0.1951, /*-0.9952,-0.0980 */
}; //偶数cos值 奇数sin值。       复常数码表 。 历经几个小时最终尼玛明确了。。原因 就是计算器还要调弧度和角度模式。 。 好了这这就是将1的sin和cos值依照角度平均分然后得到的sin和cos值即为上表。 目的是为了节约计算量。 第二个cos(π/32)记住计算器弧度和角度的设置 void ee(struct compx b1,uchar b2) //复数乘法
{
temp.real=b1.real*iw[2*b2]-b1.imag*iw[2*b2+1];
temp.imag=b1.real*iw[2*b2+1]+b1.imag*iw[2*b2];
} uint mypow(uchar nbottom,uchar ntop) //乘方函数
{
uint result=1;
uchar t;
for(t=0;t<ntop;t++)result*=nbottom;
return result;
} void fft(struct compx *xin,uchar data N) //高速傅立叶变换
{
uchar data fftnum,i,j,k,l,m,n,disbuff,dispos,dissec;
data struct compx t;
fftnum=N; //傅立叶变换点数
for(m=1;(fftnum=fftnum/2)!=1;m++);//求得M的值 N=64 所以M=6 也就是分解为6级
for(k=0;k<=N-1;k++) //码位倒置
{
n=k;
j=0;
for(i=m;i>0;i--) //倒置 比如001变为100
{
j=j+((n%2)<<(i-1)); //二进制除二取余的反过程。就得到了倒置十进制数
n=n/2; //倒置过程中处位和末位都不变即0和63都不变。此例中1相应32
}
if(k<j){t=xin[1+j];xin[1+j]=xin[1+k];xin[1+k]=t;}//交换数据 , 由于从0開始。所以进行加1处理。比如xin[2]和xin[33]交换。即1与32交换
} //到此FFT码位倒置结束
for(l=1;l<=m;l++) //FFT运算 l为级数
{
disbuff=mypow(2,l); //求得碟间距离 求得碟间距离 (乘方函数 pow(X,y)就是计算X的Y次方)
dispos=disbuff/2; //求得碟形两点之间的距离
for(j=1;j<=dispos;j++) //每一个蝶形群运算的次数 当N等于64时每次进行蝶形运算次数l=1时为1*32 l=2时为 2* 16 总之每次进行蝶形运算数不变都为N/2 仅仅只是相乘的两个数的间隔每级都加大
for(i=j;i<N;i=i+disbuff) //遍历M级全部的碟形
{
dissec=i+dispos; //求得第二点的位置
ee(xin[dissec],(uint)(j-1)*(uint)N/disbuff);//复数乘法
t=temp;
xin[dissec].real=xin[i].real-t.real;
xin[dissec].imag=xin[i].imag-t.imag;
xin[i].real=xin[i].real+t.real;
xin[i].imag=xin[i].imag+t.imag;
}
}
}

尽管凝视的比較完好,但我还须要进行几点说明:

a.FFT的产生

我们想通过单片机处理信号,信号必须是离散的和有限长度的数据才干被处理。所以我们仅仅能用DFT(离散傅里叶变换),DFT尽管可以处理信号,可是运算比較复杂,所以依据它的一些性质提出了FFT。

b.蝶形算法

在这里希望读者感兴趣的话找一本信号分析与处理的数来对比着分析,我写的凝视比較完好,相信你可以理解,当中的凝视部分。是我在用64点採样的时候做的,32点的原理是一样的。我在这里简单说下思路。

1.码位倒置

2.基32的FFT蝶形算法

c.採样点数的选取

这里网上大家通常看到的用单片机一般都採用64个点的。高级一点的STM32的程序用128个点的,而我选择了32个点。

这里事实上并没有明白要求大家採样用多少个点。

可是通常都是2的N次方,因为计算会方便。再来说说我做的,因为因为FFT结果的对称性,通常仅仅使用前N/2个採样点的结果。

所以我用32个点採样,刚刚好能满足。

採样频率我选择的是1KHZ,因为我一共同拥有16列所以,每一个列的频率事实上已经固定了。所以加大採样的点数仅仅是添加了计算而已。还有就是添加了我这16个点的选择机会。

我測试过採用64个点,发现会有闪屏的现象,就是偶尔你会发现点阵上没有灯亮和刚开机的时候一样,后来分析原因就是运算的时间过长。使得画面无法连续显示。

d.FFT的採样时间

理论的情况:依据香农採样定力我们知道:为了不失真地恢复模拟信号,採样频率应该不小于模拟信号频谱中最高频率的2倍。人耳理论能听到声音范围20HZ---20kHZ,我选择了500us定时,也就是2kHZ的採样频率。可是非常遗憾结果是失真的,可是失真的结果是能够接受的。

真实的情况:我曾最后拿着音频频谱和分析音频的软件相对照,发现你採样时2KHZ还是4KHZ结果差点儿是几乎相同的。我试着再次减小频率,发现还是几乎相同。

最后分析整个程序我才发现当中的问题。那就是因为单片机性能还是有限处理这样的FFT计算还是有些费力。所以造成的运算的时间比較长。这就使得不管你如何调节定时器。仅仅要超过了某个值。其结果都是一样的,这也是这个设计的一个缺陷之处。

void Timer0() interrupt 1			//我用的24M晶振,ADC採样频率即为採样周期	 2KH	 因为运行语句过长所以即使频率加大也没有仍会失真
{
TH0 = 0xd1;
TL0 = 0x20; fft_sign = 1; }

e.显示的BUG

显示的时候小伙伴可能会看到第一列的灯始终是亮着的,由于这个是结果产生的直流分量,当时调程序的时候。由于C语言能力有限,没可以弄掉,有点遗憾。

LED音乐频谱之输入数据处理的更多相关文章

  1. LED音乐频谱之输出数据处理

    转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/38023539 一.PWM调节 1.初始化 void DACInit() { C ...

  2. LED音乐频谱之概述

    点击打开链接       转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/37929733 这个LED音乐频谱是我在学51单片机的 ...

  3. LED音乐频谱之点阵

    转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/37967455 一.硬件 watermark/2/text/aHR0cDovL2 ...

  4. Three.js + HTML5 Audio API 打造3D音乐频谱,Let’s ROCK!

    继续玩味之前写的音乐频谱作品,将原来在Canvas标签上的 作图利用Three.js让它通过WebGL呈现,这样就打造出了一个全立体感的频谱效果了. 项目详情及源码 项目GitHub地址:https: ...

  5. TensorFlow多线程输入数据处理框架(四)——输入数据处理框架

    参考书 <TensorFlow:实战Google深度学习框架>(第2版) 输入数据处理的整个流程. #!/usr/bin/env python # -*- coding: UTF-8 -* ...

  6. tensorflow学习笔记——多线程输入数据处理框架

    之前我们学习使用TensorFlow对图像数据进行预处理的方法.虽然使用这些图像数据预处理的方法可以减少无关因素对图像识别模型效果的影响,但这些复杂的预处理过程也会减慢整个训练过程.为了避免图像预处理 ...

  7. STM32通过FSMC驱动3.2寸液晶屏实现的音乐频谱

    视频演示: http://player.youku.com/player.php/sid/XNDcyMDgwMTE2/v.swf 源码下载: lattice_ music _tft.rar(1.42 ...

  8. TensorFlow多线程输入数据处理框架(三)——组合训练数据

    参考书 <TensorFlow:实战Google深度学习框架>(第2版) 通过TensorFlow提供的tf.train.batch和tf.train.shuffle_batch函数来将单 ...

  9. TensorFlow多线程输入数据处理框架(二)——输入文件队列

    参考书 <TensorFlow:实战Google深度学习框架>(第2版) 一个简单的程序来生成样例数据. #!/usr/bin/env python # -*- coding: UTF-8 ...

随机推荐

  1. Java项目持续集成检查项

    1)   检查项:使用Super POM. 2)   检查项:GroupID应该以特定名称开头.3)   检查项:版本号符合规范.版本号必须是三段数字,之后加或不加-SNAPSHOT.4)   检查项 ...

  2. gnu screen的用法

    在使用ssh或者telnet登录远程主机后执行一些耗时的命令, 如果此时ssh或者telnet中断, 那么远程主机上正在执行的程序或者说命令也会被迫终止. screen能够很好地解决这个问题, scr ...

  3. 这是一篇满载真诚的微信小程序开发干货

    1月9日零点刚过,张小龙与团队正式发布微信小程序.它究竟能在微信8.5亿用户中牵动多少人,现在还很难说.但对于创业者来讲,小程序无疑带来了新契机,以及服务“上帝”们的新方式. 从今天起,只要开发者登录 ...

  4. Light OJ 1406 Assassin`s Creed 状态压缩DP+强连通缩点+最小路径覆盖

    题目来源:Light OJ 1406 Assassin`s Creed 题意:有向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方 思路:最少的的人能够走全然图 明显是最小路径覆盖问题 ...

  5. Ubuntu登录Windows Server 2008r2 密码总是错误与NLA验证

    日期:2013-05-22   经过一天的折腾,终于能够用Ubuntu登录Windows server 2008 R2 了. 寝室里面用小本子,装的ubuntu,实验室的服务器是win server0 ...

  6. NFS客户端、服务器协商读写粒度(rsize、wsize)流程 【转】

    rsize和wsize决定了网络文件系统(NFS)一次网络交互所能够读写的数据块的大小,rsize和wsize的大小对网络文件系统(NFS)的性能有重要影响.rsize和wsize的大小是在用户配置的 ...

  7. 原创工具binlog2sql:从MySQL binlog得到你要的SQL

    从MySQL binlog得到你要的SQL.根据不同设置,你可以得到原始SQL.回滚SQL.去除主键的INSERT SQL等. 用途 数据回滚 主从切换后数据不一致的修复 从binlog生成标准SQL ...

  8. windows下如何生成gitlab ssh公钥

    1.查看是否已经有了ssh密钥:cd ~/.ssh如果没有密钥则不会有此文件夹,有则备份删除2.生存密钥: $ ssh-keygen -t rsa -C “你的邮箱”按3个回车,密码为空. Your ...

  9. 算法中的 log 到底是什么?

    之前一直不解为何算法中经常会看到 log 今天看<数据结构与算法分析 Java 语言描述>(第 3 版)2.4.3 节 求最大子序列和的分治算法实现时才注意到原因 翻看第 29 页的最后一 ...

  10. Spring Cloud启动应用时指定IP或忽略某张网卡配置

    说明:分布式应用部署到服务上,由于服务器可能存在多张网卡,造成IP地址不准的问题. 解决方法: 1.直接添加忽略某张网卡的配置: spring.cloud.inetutils.ignored-inte ...