energyaddcorrellation_improve_done1.cpp
资源名称:se06.rar [点击查看]
上传用户:kepeng103
上传日期:2022-07-27
资源大小:2653k
文件大小:13k
源码类别:
DSP编程
开发平台:
C/C++
- /**********本函数的功能是用能量和自相*******************
- ***********关向量方差相结合的算法来进*******************
- ******************行VAD检测*****************************/
- /**********胡曙辉,2008年4月完成********************/
- /*4.3 加入了一些必须的初始化语句,*/
- /*4.7 在判断语音起始点和结束点加入了窗移动函数,即用连续多帧来进行判断*
- *******解决了训练过程的一个bug*******/
- /*4.8 把整个代码用函数实现**********/
- /*4.14 对语音的结束点判断采用了另一种方法*/
- /*4.16 静噪时候的压缩倍数必须增大,否则当输入信号的能量较大时,可以听到较小的压缩后输出。到1000倍左右,目前是150倍***
- ********为了减少误报率,必须提高能量门限,8倍到10倍左右,第二级门限设定到5至7倍,**
- ********找语音结束点的时候,采用的是两级判决方法,首先在50帧内计算出能量少于某一门限的帧数,如果帧数大于某一个值,这个值需要进行一定的试验调整(选15~25帧),然后对最后一帧用avv判决,这里好像有一定的偶然性,可能会提前终止语音。是否可以将avv加到能量判决那一部分中,统计同时满足两个条件的总帧数。*****
- ********当找到语音起始点的时候,默认输出100帧(1.6s),可能在换台的时候会使系统的静噪关断时延超过3s。因为后面还有50帧的统计,总时间为2.4s,如果第一次未能准确判决,将会有4.8s才能关断。将100帧换为75帧,时延减少0.4s,换为50帧,时延减少0.8s。********/
- /*k值有变换,今天试验的时候需要选择10,以前是2.5,有点奇怪。*/
- /*4.17 语音起始点判断的时候,连续两帧满足avv才判为语音起始点(效果很好,噪声误判率极低,试听了很久)*/
- /* 4.18 根据试验结果修改了一些参数值*/
- /* 4.23 改变了语音起始点的检测,起始点和结束点的参数也不一样,并不是判为噪声才进行噪声更新,在能量低于1.5倍门限的时候也进行噪声更新,防止长时间不更新噪声影响系统的判决。
- 每次找语音起始点之前重新训练信道*/
- #include "..commonhal.h"
- #include "device.h"
- #include "buf.h"
- #include <stdio.h>
- #include <math.h>
- #define PI 3.141592
- float noise_energy[10]={0};
- float subframe_energy[32]={0};
- float input_signal[128]={0};
- float energy_threshhold=0;
- float average_noiseenergy=0;
- float signal_energy=0;
- float signal_temp[128];
- float frame_energyvariance=0;
- float frame_noisereference=0;
- float frame_energyreference;
- int16 qq[128]={0};
- int16 *p;
- void train(void);
- void read_signal(void);
- void compress_signal(void);
- void subframe_energyvar(void);
- void noise_update(void);
- void sys_init(void)
- {
- gpio_init();
- dac_reset();
- mcbsp0_init_serial();
- adc_init();
- mcasp_init();
- timer0_init();
- ADC_SE_HI();
- ISTP = 0x00000400;
- IER |= 0x00000002;
- CSR |= 0x00000001;
- }
- void spark_led(void)
- {
- REG32(MCASP1_PFUNC) |= 0x0000003e;
- REG32(MCASP1_PDIR) |= 0x0000003e;
- REG32(MCASP1_PDOUT) = 0x00000000;
- uint8 code = 1;
- for(int k=0; k<10; k++)
- {
- set_led(0xff, code);
- code <<= 1;
- code = (code == 0x20? 1:code);
- delay_ms(100);
- }
- REG32(MCASP1_PDOUT) = 0x00000000;
- }
- int16 data[128];
- void data_init(void)
- {
- for(int i=0; i<128; i++)
- {
- data[i] = 30000*sin(i*PI*2/64);
- }
- }
- /**本函数的目的是训练信道******
- ***输入:读入10帧数据 ******
- ***输出:得到average_noiseenergy值和energy_threshhold值*/
- void train(void)
- {
- int i;
- int j;
- for(i=0; i<10; i++)
- {
- noise_energy[i] = 0.0;
- }
- for(i=0; i<10; i++)
- {
- p = read_data();
- for(j=0; j<128; j++)
- {
- input_signal[j] = (float)p[j];
- noise_energy[i] += input_signal[j]*input_signal[j];
- qq[j] = input_signal[j];
- }
- noise_energy[i]/=128;
- compress_signal();//训练的时候默认是关断输出
- write_data(qq);
- }
- average_noiseenergy = 0.0;
- for(i=0; i<10; i++)
- {
- average_noiseenergy += noise_energy[i];
- }
- average_noiseenergy /= 10;
- //能量判决门限初始化为起始10帧数据的平均能量值;
- energy_threshhold = average_noiseenergy;
- }//训练结束
- /*****功能:读取一帧数据,并计算出signal_energy****
- ******输入:无 ****
- ******输出:一帧数据和此数据帧的signal_energy值***/
- void read_signal(void)
- {
- int i;
- p = read_data();
- signal_energy = 0.0;
- for(i=0; i<128; i++)
- {
- input_signal[i] = (float)p[i];
- qq[i] = (int16)input_signal[i];
- signal_energy += input_signal[i]*input_signal[i];
- }
- signal_energy /= 128;
- }
- /****功能:对qq[128]赋值零****
- *****输入:无 ****
- *****输出:qq[128] ***/
- void compress_signal(void)
- {
- int i;
- for(i=0; i<128; i++)
- {
- qq[i] = 0;
- }
- }
- /*****功能:把一帧数据分成32个子帧,计算出子帧 ****
- ******的frame_energyvariance与frame_energyreference****
- ******输入:一帧数据 ****
- ******输出:frame_energyvariance与frame_energyreference值***/
- void subframe_energyvar(void)
- {
- int i;
- int j;
- int subframe_number = 32;
- float subframe_total;
- float subframelength=128/subframe_number;
- for(i=0; i<subframe_number; i++)
- {
- subframe_energy[i]=0;
- }
- for(i=0; i<subframe_number; i++)
- {
- for(j=0; j<subframelength; j++)
- subframe_energy[i] += input_signal[i*4+j]*input_signal[i*4+j];
- subframe_energy[i] /= subframelength;
- }
- subframe_total = 0;
- for(i=0; i<subframe_number; i++)
- {
- subframe_total += subframe_energy[i];
- }
- frame_energyreference = subframe_total/subframe_number;
- frame_energyvariance = 0.0;
- for(i=0; i<subframe_number; i++)
- {
- frame_energyvariance += (subframe_energy[i]-frame_energyreference)*(subframe_energy[i]-frame_energyreference);
- }
- frame_energyvariance = sqrt(frame_energyvariance);
- }
- /*****功能:更新门限energy_threshhold****
- ******使之能自适应信道的变化 ****
- ******输入:一帧数据 ****
- ******输出:门限energy_threshhold值 ***/
- void noise_update(void)
- {
- int i;
- float old_noiseenergyvar;
- float new_noiseenergyvar;
- float ratio;
- float t;
- average_noiseenergy = 0.0;
- for(i=0; i<10; i++)
- {
- average_noiseenergy += noise_energy[i];
- }
- average_noiseenergy /= 10;
- old_noiseenergyvar = 0.0;
- for(i=0; i<10; i++)
- old_noiseenergyvar += (noise_energy[i]-average_noiseenergy)*(noise_energy[i]-average_noiseenergy);
- for(i=0; i<9; i++) //这里i最高只能取8!!!
- {
- noise_energy[i+1] = noise_energy[i];
- noise_energy[0] = signal_energy;
- }
- average_noiseenergy = 0.0;
- for(i=0; i<10; i++)
- {
- average_noiseenergy += noise_energy[i];
- }
- average_noiseenergy /= 10;
- new_noiseenergyvar = 0.0;
- for(i=0; i<10; i++)
- new_noiseenergyvar += (noise_energy[i]-average_noiseenergy)*(noise_energy[i]-average_noiseenergy);
- old_noiseenergyvar = sqrt(old_noiseenergyvar);
- new_noiseenergyvar = sqrt(new_noiseenergyvar);
- //根据当前噪声能量方差与先前能量方差的比值来对p赋值,借此自适应的跟踪信道的噪声变化;
- ratio = new_noiseenergyvar/old_noiseenergyvar;
- if(ratio>=1.25)
- t=0.25;
- else if(ratio>=1.10)
- t=0.20;
- else if(ratio>=1.00)
- t=0.15;
- else
- t=0.10;
- energy_threshhold = energy_threshhold*(1-t)+t*noise_energy[0];
- }
- int main(void)
- {
- float a;//avv判决语音起始点的倍数
- float b; //avv判决语音结束点的倍数
- float c;//第一级能量倍数
- float d; //第二级能量倍数
- float f;
- int dip1,dip2,dip3,dip4;
- int value;
- bool flag;
- CSR &= (~0x00000001);
- IER = 0;
- data_init();
- buf_init();
- timer1_init();
- spark_led();
- sys_init();
- //循环判断每帧数据
- while(1)
- {
- //用十帧数据来训练整个算法,并得到相关参数.
- train();
- flag = false;//初始化flag:语音有无标志
- //找语音的起始点
- while(!flag)
- {
- value = REG32(GPIO_GPVAL);
- dip1 = value & 0x00000001;
- dip2 = value & 0x00000080;
- dip3 = value & 0x00000040;
- dip4 = value & 0x00000020;
- if((!dip1) && (dip2) && (dip3) && (dip4))
- {
- a = 0.8;
- b = 0.5;
- c = 5;
- d = 3;
- f = 1.0;
- }
- else if((!dip1) && (dip2) && (dip3) && (!dip4))
- {
- a = 1.2;
- b = 1;
- c = 5;
- d = 4;
- f = 1.5;
- }
- else if((!dip1) && (dip2) && (!dip3) && (dip4))
- {
- a = 3;
- b = 3;
- c = 6;
- d = 4;
- f = 1.5;
- }
- else if((!dip1) && (dip2) && (!dip3) && (!dip4))
- {
- a = 5;
- b = 4;
- c = 6;
- d = 4;
- f=1.8;
- }
- else
- ;
- read_signal();
- //能量判决,如果读入帧的能量与门限值比较,如果大于门限,则输出,
- if(signal_energy > c*energy_threshhold)
- {
- subframe_energyvar();
- if(frame_energyvariance>(a-0.5)*(frame_energyreference+0.1))
- {
- flag = true;
- write_data(qq);
- }
- else
- {
- compress_signal();
- flag = false;
- write_data(qq);
- noise_update();
- }
- }
- //如果是5倍门限以上则需看avv;
- else if(signal_energy > d*energy_threshhold)
- {
- subframe_energyvar();
- //avv判决
- if(frame_energyvariance > (a-0.5)*(frame_energyreference+0.1))
- {
- flag = true;
- write_data(qq);
- }
- else
- {
- compress_signal();
- flag = false;
- write_data(qq);
- noise_update();
- }
- }
- else if(signal_energy > 1.8*energy_threshhold)
- {
- subframe_energyvar();
- //avv判决;
- if(frame_energyvariance>a*(frame_energyreference+0.1))
- {
- compress_signal();
- write_data(qq);
- read_signal();
- subframe_energyvar();
- //avv判决;
- if(frame_energyvariance>(a)*(frame_energyreference+0.1))
- {
- flag = true;
- write_data(qq);
- }
- else
- {
- compress_signal();
- write_data(qq);
- flag = false;
- noise_update();
- }
- }
- //当判为静音帧时进行噪声更新;
- else
- {
- compress_signal();
- write_data(qq);
- flag = false;
- noise_update();
- }
- }
- //小能量帧用avv判决
- else
- {
- subframe_energyvar();
- if(frame_energyvariance>(a+0.5)*(frame_energyreference+0.1))//文献中用的是frame_noisereference
- {
- compress_signal();
- write_data(qq);
- read_signal();
- subframe_energyvar();
- //进一步avv判决;
- if(frame_energyvariance>(a+0.5)*(frame_energyreference+0.1))
- {
- flag = true;
- write_data(qq);
- }
- else
- {
- compress_signal();
- write_data(qq);
- flag = false;
- noise_update();
- }
- }
- else
- {
- compress_signal();
- write_data(qq);
- flag = false;
- noise_update();
- }
- }//if(signal_energy > 8*energy_threshhold)
- }//while(!flag)结束
- //找语音的结束点
- //如果有连续
- while(flag)
- {
- value = REG32(GPIO_GPVAL);
- dip1 = value & 0x00000001;
- dip2 = value & 0x00000080;
- dip3 = value & 0x00000040;
- dip4 = value & 0x00000020;
- if((!dip1) && (dip2) && (dip3) && (dip4))
- {
- a = 0.8;
- b = 0.8;
- c = 5;
- d = 3;
- f = 1.0;
- }
- else if((!dip1) && (dip2) && (dip3) && (!dip4))
- {
- a = 1.2;
- b = 1;
- c = 5;
- d = 4;
- f = 1.5;
- }
- else if((!dip1) && (dip2) && (!dip3) && (dip4))
- {
- a = 3;
- b = 3;
- c = 6;
- d = 4;
- f = 1.5;
- }
- else if((!dip1) && (dip2) && (!dip3) && (!dip4))
- {
- a = 5;
- b = 4;
- c = 6;
- d = 4;
- f = 1.8;
- }
- else
- ;
- //这种判断方法是在50帧中如果有15帧的能量小于1.5倍门限则进一步用avv判决
- int s = 150;
- int totalenergynum = 0;
- int totalavvnum = 0;
- int totalnum = 0;
- read_signal();
- //能量判决,如果读入k帧的能量与门限值比较,如果大于门限,则输出,否则进一步用AVV判决;
- while(s!=0)
- {
- if(signal_energy < f*energy_threshhold)
- {
- totalenergynum++;
- noise_update();
- }
- else if(signal_energy < 1.8*energy_threshhold)
- {
- totalnum++;
- }
- else
- ;
- subframe_energyvar();
- //根据子帧能量方差与子帧的平均能量比较来做判决;
- if(frame_energyvariance<(b)*(frame_energyreference+0.1))
- {
- totalavvnum++;
- }
- write_data(qq);
- read_signal();
- s--;
- }
- //if(totalnum>60 && totalavvnum<60)
- //{
- // flag = true;
- // write_data(qq);
- //}
- //else
- {
- if(totalenergynum>120)
- {
- totalenergynum=0;
- //语音结束点,并更新噪声
- flag = false;
- compress_signal();
- write_data(qq);
- noise_update();//当判为静音帧时进行噪声更新
- }//if(totalenergynum>70 && totalavvnum>50)结束
- else
- {
- flag = true;
- write_data(qq);
- }
- }//while(s!=0)结束
- }//while(flag)结束
- }//while(1)结束
- }//主函数结束