转载请注明出处: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. powx-n 分治实现乘方

    题目描述 Implement pow(x, n). AC: class Solution { public: double pow(double x, int n) { && n == ...

  2. Plus One 加一运算

    Given a non-negative number represented as an array of digits, plus one to the number. The digits ar ...

  3. kettle Spoon.bat运行闪退

      1.情景展示 启动kettle的Spoon.bat闪退,并没有进入kettle的启动界面. 2.原因分析 使用条件: jdk版本需>=1.6: java需配置环境变量. 如果满足了上述前提条 ...

  4. 【Linux】eclipse juno 边框过大的调整方法

    切换至eclipse目录: vi plugins/org.eclipse.platform_4.2.*/css/e4_default_gtk.css 找到.MPartStack,替换成如下代码: .M ...

  5. Tomcat服务器版本号泄露-低危漏洞修复

    一.问题描述Tomcat报错页面泄漏Apache Tomcat/7.0.52相关版本号信息,是攻击者攻击的途径之一.因此实际当中建议去掉版本号信息.二.解决办法 1.进入到tomcat/lib目录下, ...

  6. Android Studio 错误: 非法字符: &#39;\ufeff&#39; 解决方式|错误: 须要class, interface或enum

    在导入eclipse项目到Android Studio出现这种错误, 非法字符: '\ufeff' 解决方式|错误: 须要class, interface或enum.查阅后了解到Eclipse能够智能 ...

  7. 数据库行列转换sql

    经常折腾数据库,常常遇到数据库行列转换的问题,下面就用一个小例子来演示下如何进行行列转换. 1.创建一张表 CREATE TABLE [android_source]( [CREATETIME] [d ...

  8. sort.js

    JavaScript to achieve the ten common sorting algorithm library 1 ; (function (global, factory) { // ...

  9. 阿里云ecs配置辅助网卡绑定公网ip地址

    EIP直通车 前置条件:1.大家的实例是从经典迁移到VPC里面的,上古时期,经典实例大家购买实例的时候都是买了带宽的.而这种带宽一般情况下都是包年包月的,而且这种绑定在实例上的IP,我们把它叫做公网I ...

  10. spring hiberante 集成出现异常 java.lang.ClassNotFoundException: org.hibernate.engine.SessionFactoryImplementor

    出现如题的异常是由于hibernate和spring集成时的的版本不一致所导致. 如下面,所示,如果你用的hibneate 4.0及以上版本,那么将会报错,因为这里用的事务管理是hibernate 3 ...