energyaddcorrellation_improve_done1.cpp
上传用户:kepeng103
上传日期:2022-07-27
资源大小:2653k
文件大小:13k
源码类别:

DSP编程

开发平台:

C/C++

  1. /**********本函数的功能是用能量和自相*******************
  2. ***********关向量方差相结合的算法来进*******************
  3. ******************行VAD检测*****************************/
  4. /**********胡曙辉,2008年4月完成********************/
  5. /*4.3  加入了一些必须的初始化语句,*/
  6. /*4.7  在判断语音起始点和结束点加入了窗移动函数,即用连续多帧来进行判断*
  7. *******解决了训练过程的一个bug*******/
  8. /*4.8  把整个代码用函数实现**********/
  9. /*4.14 对语音的结束点判断采用了另一种方法*/
  10. /*4.16 静噪时候的压缩倍数必须增大,否则当输入信号的能量较大时,可以听到较小的压缩后输出。到1000倍左右,目前是150倍***
  11. ********为了减少误报率,必须提高能量门限,8倍到10倍左右,第二级门限设定到5至7倍,**
  12. ********找语音结束点的时候,采用的是两级判决方法,首先在50帧内计算出能量少于某一门限的帧数,如果帧数大于某一个值,这个值需要进行一定的试验调整(选15~25帧),然后对最后一帧用avv判决,这里好像有一定的偶然性,可能会提前终止语音。是否可以将avv加到能量判决那一部分中,统计同时满足两个条件的总帧数。*****
  13. ********当找到语音起始点的时候,默认输出100帧(1.6s),可能在换台的时候会使系统的静噪关断时延超过3s。因为后面还有50帧的统计,总时间为2.4s,如果第一次未能准确判决,将会有4.8s才能关断。将100帧换为75帧,时延减少0.4s,换为50帧,时延减少0.8s。********/
  14. /*k值有变换,今天试验的时候需要选择10,以前是2.5,有点奇怪。*/
  15. /*4.17 语音起始点判断的时候,连续两帧满足avv才判为语音起始点(效果很好,噪声误判率极低,试听了很久)*/
  16. /* 4.18 根据试验结果修改了一些参数值*/
  17. /* 4.23 改变了语音起始点的检测,起始点和结束点的参数也不一样,并不是判为噪声才进行噪声更新,在能量低于1.5倍门限的时候也进行噪声更新,防止长时间不更新噪声影响系统的判决。
  18.    每次找语音起始点之前重新训练信道*/
  19. #include "..commonhal.h"
  20. #include "device.h"
  21. #include "buf.h"
  22. #include <stdio.h>
  23. #include <math.h>
  24. #define PI 3.141592
  25. float noise_energy[10]={0};
  26. float subframe_energy[32]={0}; 
  27. float input_signal[128]={0};
  28. float energy_threshhold=0;
  29. float average_noiseenergy=0;
  30. float signal_energy=0;
  31. float signal_temp[128];
  32. float frame_energyvariance=0;
  33. float frame_noisereference=0;
  34. float frame_energyreference;
  35. int16 qq[128]={0};
  36. int16 *p;
  37. void train(void);
  38. void read_signal(void);
  39. void compress_signal(void);
  40. void subframe_energyvar(void);
  41. void noise_update(void);
  42. void sys_init(void)
  43. {
  44. gpio_init();
  45. dac_reset();
  46. mcbsp0_init_serial();
  47. adc_init();
  48. mcasp_init();
  49. timer0_init();
  50. ADC_SE_HI();
  51. ISTP = 0x00000400;
  52. IER |= 0x00000002;
  53. CSR |= 0x00000001;
  54. }
  55. void spark_led(void)
  56. {
  57. REG32(MCASP1_PFUNC) |= 0x0000003e;
  58. REG32(MCASP1_PDIR) |= 0x0000003e;
  59. REG32(MCASP1_PDOUT) = 0x00000000;
  60. uint8 code = 1;  
  61. for(int k=0; k<10; k++) 
  62. {
  63. set_led(0xff, code);
  64. code <<= 1;
  65. code = (code == 0x20? 1:code);
  66. delay_ms(100);
  67. }
  68. REG32(MCASP1_PDOUT) = 0x00000000;
  69. }
  70. int16 data[128];
  71. void data_init(void)
  72. {
  73. for(int i=0; i<128; i++) 
  74. {
  75. data[i] = 30000*sin(i*PI*2/64);
  76. }
  77. }
  78. /**本函数的目的是训练信道******
  79. ***输入:读入10帧数据     ******
  80. ***输出:得到average_noiseenergy值和energy_threshhold值*/
  81. void train(void)
  82. {
  83. int i;
  84. int j;
  85. for(i=0; i<10; i++)
  86. {
  87. noise_energy[i] = 0.0;
  88. }
  89. for(i=0; i<10; i++)
  90. {
  91. p = read_data();
  92. for(j=0; j<128; j++)
  93. {
  94. input_signal[j] = (float)p[j];
  95. noise_energy[i] += input_signal[j]*input_signal[j]; 
  96. qq[j] = input_signal[j];
  97. }
  98. noise_energy[i]/=128;
  99. compress_signal();//训练的时候默认是关断输出
  100. write_data(qq);
  101. }
  102. average_noiseenergy = 0.0;
  103. for(i=0; i<10; i++)
  104. {
  105. average_noiseenergy += noise_energy[i];
  106. }
  107. average_noiseenergy /= 10;
  108. //能量判决门限初始化为起始10帧数据的平均能量值;        
  109. energy_threshhold = average_noiseenergy;
  110. }//训练结束
  111. /*****功能:读取一帧数据,并计算出signal_energy****
  112. ******输入:无                                 ****
  113. ******输出:一帧数据和此数据帧的signal_energy值***/
  114. void read_signal(void)
  115. {
  116. int i;
  117. p = read_data();
  118. signal_energy = 0.0;
  119. for(i=0; i<128; i++)
  120. {
  121. input_signal[i] = (float)p[i];
  122. qq[i] = (int16)input_signal[i];
  123. signal_energy += input_signal[i]*input_signal[i];
  124.     
  125. }     
  126. signal_energy /= 128;
  127. }
  128. /****功能:对qq[128]赋值零****
  129. *****输入:无             ****
  130. *****输出:qq[128]        ***/
  131. void compress_signal(void)
  132. {
  133. int i;
  134. for(i=0; i<128; i++)
  135.     {
  136. qq[i] = 0;
  137. }
  138. }
  139. /*****功能:把一帧数据分成32个子帧,计算出子帧      ****
  140. ******的frame_energyvariance与frame_energyreference****
  141. ******输入:一帧数据                                ****
  142. ******输出:frame_energyvariance与frame_energyreference值***/
  143. void subframe_energyvar(void)
  144. {
  145. int i;
  146. int j;
  147. int subframe_number = 32;
  148. float subframe_total;
  149. float subframelength=128/subframe_number;
  150.         
  151. for(i=0; i<subframe_number; i++)
  152. {
  153. subframe_energy[i]=0;
  154. }
  155. for(i=0; i<subframe_number; i++)
  156. {
  157. for(j=0; j<subframelength; j++)
  158. subframe_energy[i] += input_signal[i*4+j]*input_signal[i*4+j];
  159. subframe_energy[i] /= subframelength;
  160. }
  161. subframe_total = 0;
  162. for(i=0; i<subframe_number; i++)
  163. {
  164. subframe_total += subframe_energy[i];
  165. }
  166. frame_energyreference = subframe_total/subframe_number;
  167. frame_energyvariance = 0.0;
  168. for(i=0; i<subframe_number; i++)
  169. {
  170. frame_energyvariance += (subframe_energy[i]-frame_energyreference)*(subframe_energy[i]-frame_energyreference);
  171. }
  172. frame_energyvariance = sqrt(frame_energyvariance);
  173. }
  174. /*****功能:更新门限energy_threshhold****
  175. ******使之能自适应信道的变化        ****
  176. ******输入:一帧数据                 ****
  177. ******输出:门限energy_threshhold值  ***/
  178. void noise_update(void)
  179. {
  180. int i;
  181. float old_noiseenergyvar;
  182. float new_noiseenergyvar;
  183. float ratio;
  184. float t;
  185.         
  186. average_noiseenergy = 0.0;
  187. for(i=0; i<10; i++)
  188. {
  189. average_noiseenergy += noise_energy[i];
  190. }
  191. average_noiseenergy /= 10;
  192.         
  193. old_noiseenergyvar = 0.0;
  194. for(i=0; i<10; i++)
  195. old_noiseenergyvar += (noise_energy[i]-average_noiseenergy)*(noise_energy[i]-average_noiseenergy);
  196.         
  197. for(i=0; i<9; i++) //这里i最高只能取8!!!        
  198. {
  199. noise_energy[i+1] = noise_energy[i];
  200. noise_energy[0] =  signal_energy;
  201. }
  202. average_noiseenergy = 0.0;
  203. for(i=0; i<10; i++)
  204. {
  205. average_noiseenergy += noise_energy[i];
  206. }
  207. average_noiseenergy /= 10;
  208. new_noiseenergyvar = 0.0;
  209. for(i=0; i<10; i++)
  210. new_noiseenergyvar += (noise_energy[i]-average_noiseenergy)*(noise_energy[i]-average_noiseenergy);
  211. old_noiseenergyvar = sqrt(old_noiseenergyvar);
  212. new_noiseenergyvar = sqrt(new_noiseenergyvar);
  213. //根据当前噪声能量方差与先前能量方差的比值来对p赋值,借此自适应的跟踪信道的噪声变化;                    
  214.         
  215. ratio = new_noiseenergyvar/old_noiseenergyvar;
  216. if(ratio>=1.25)
  217. t=0.25;
  218. else if(ratio>=1.10)
  219. t=0.20;
  220. else if(ratio>=1.00)
  221. t=0.15;        
  222. else
  223. t=0.10;
  224. energy_threshhold = energy_threshhold*(1-t)+t*noise_energy[0];
  225.        
  226. }
  227. int main(void)
  228. {
  229. float a;//avv判决语音起始点的倍数
  230. float b; //avv判决语音结束点的倍数
  231. float c;//第一级能量倍数
  232. float d;  //第二级能量倍数
  233. float f;
  234. int dip1,dip2,dip3,dip4;
  235. int value;  
  236. bool flag;
  237. CSR &= (~0x00000001);
  238. IER = 0;
  239. data_init();
  240. buf_init();
  241. timer1_init();
  242. spark_led();
  243. sys_init();
  244. //循环判断每帧数据    
  245. while(1)
  246. {         
  247. //用十帧数据来训练整个算法,并得到相关参数.
  248. train();
  249. flag = false;//初始化flag:语音有无标志
  250. //找语音的起始点
  251.         
  252. while(!flag)
  253. {            
  254. value = REG32(GPIO_GPVAL);
  255. dip1 = value & 0x00000001;
  256. dip2 = value & 0x00000080;
  257. dip3 = value & 0x00000040;
  258. dip4 = value & 0x00000020;
  259. if((!dip1) && (dip2) && (dip3) && (dip4))
  260. {
  261. a = 0.8;
  262. b = 0.5;
  263. c = 5;
  264. d = 3;
  265. f = 1.0;
  266. }
  267. else if((!dip1) && (dip2) && (dip3) && (!dip4))
  268. {
  269. a = 1.2;
  270. b = 1;
  271. c = 5;
  272. d = 4;
  273. f = 1.5;
  274. }
  275. else if((!dip1) && (dip2) && (!dip3) && (dip4))
  276. {
  277. a = 3;
  278. b = 3;
  279. c = 6;
  280. d = 4;
  281. f = 1.5;
  282. }
  283. else if((!dip1) && (dip2) && (!dip3) && (!dip4))
  284. {
  285. a = 5;
  286. b = 4;
  287. c = 6;
  288. d = 4;
  289. f=1.8;
  290. }
  291. else 
  292. ;
  293. read_signal();
  294. //能量判决,如果读入帧的能量与门限值比较,如果大于门限,则输出,                            
  295. if(signal_energy > c*energy_threshhold)
  296. {                  
  297. subframe_energyvar();
  298.           
  299. if(frame_energyvariance>(a-0.5)*(frame_energyreference+0.1))
  300. {            
  301. flag = true;                       
  302. write_data(qq);   
  303. }
  304. else
  305. {
  306. compress_signal();
  307. flag = false;
  308. write_data(qq);
  309. noise_update();
  310. }
  311. }
  312.     //如果是5倍门限以上则需看avv;         
  313. else if(signal_energy > d*energy_threshhold)
  314. {
  315. subframe_energyvar();
  316. //avv判决           
  317. if(frame_energyvariance > (a-0.5)*(frame_energyreference+0.1))
  318. {            
  319. flag = true;
  320. write_data(qq);
  321. }           
  322. else
  323. {                            
  324. compress_signal();
  325. flag = false;
  326. write_data(qq);
  327. noise_update();
  328. }
  329. }
  330.     
  331.         
  332. else if(signal_energy > 1.8*energy_threshhold)
  333. {                  
  334. subframe_energyvar();
  335. //avv判决;
  336. if(frame_energyvariance>a*(frame_energyreference+0.1))
  337. {                        
  338. compress_signal();
  339. write_data(qq);
  340. read_signal();
  341. subframe_energyvar();
  342. //avv判决;
  343. if(frame_energyvariance>(a)*(frame_energyreference+0.1))
  344. {
  345. flag = true;
  346. write_data(qq);
  347. }
  348. else
  349. {
  350. compress_signal();
  351. write_data(qq);
  352. flag = false;
  353. noise_update();
  354. }
  355. }                
  356. //当判为静音帧时进行噪声更新;                  
  357. else                  
  358. {                        
  359. compress_signal();                        
  360. write_data(qq);
  361. flag = false;                        
  362. noise_update();                  
  363. }             
  364. }
  365. //小能量帧用avv判决 
  366. else
  367. {
  368. subframe_energyvar();
  369. if(frame_energyvariance>(a+0.5)*(frame_energyreference+0.1))//文献中用的是frame_noisereference
  370. {
  371. compress_signal();
  372. write_data(qq);
  373. read_signal();
  374. subframe_energyvar();
  375. //进一步avv判决;
  376. if(frame_energyvariance>(a+0.5)*(frame_energyreference+0.1))
  377. {
  378. flag = true;
  379. write_data(qq);
  380. }
  381. else
  382. {
  383. compress_signal();
  384. write_data(qq);
  385. flag = false;
  386. noise_update();
  387. }
  388. }
  389. else
  390. {
  391. compress_signal();
  392. write_data(qq);
  393. flag = false;
  394. noise_update();
  395. }
  396. }//if(signal_energy > 8*energy_threshhold)
  397. }//while(!flag)结束
  398.        //找语音的结束点
  399. //如果有连续        
  400. while(flag)
  401. {    
  402.     value = REG32(GPIO_GPVAL);
  403. dip1 = value & 0x00000001;
  404. dip2 = value & 0x00000080;
  405. dip3 = value & 0x00000040;
  406. dip4 = value & 0x00000020;
  407. if((!dip1) && (dip2) && (dip3) && (dip4))
  408. {
  409. a = 0.8;
  410. b = 0.8;
  411. c = 5;
  412. d = 3;
  413. f = 1.0;
  414. }
  415. else if((!dip1) && (dip2) && (dip3) && (!dip4))
  416. {
  417. a = 1.2;
  418. b = 1;
  419. c = 5;
  420. d = 4;
  421. f = 1.5;
  422. }
  423. else if((!dip1) && (dip2) && (!dip3) && (dip4))
  424. {
  425. a = 3;
  426. b = 3;
  427. c = 6;
  428. d = 4;
  429. f = 1.5;
  430. }
  431. else if((!dip1) && (dip2) && (!dip3) && (!dip4))
  432. {
  433. a = 5;
  434. b = 4;
  435. c = 6;
  436. d = 4;
  437. f = 1.8;
  438. }
  439. else 
  440. ;
  441. //这种判断方法是在50帧中如果有15帧的能量小于1.5倍门限则进一步用avv判决  
  442. int s = 150;
  443. int totalenergynum = 0;
  444. int totalavvnum = 0;
  445. int totalnum = 0;
  446. read_signal();
  447. //能量判决,如果读入k帧的能量与门限值比较,如果大于门限,则输出,否则进一步用AVV判决;               
  448. while(s!=0)
  449. {
  450. if(signal_energy < f*energy_threshhold)
  451. {
  452. totalenergynum++;
  453. noise_update();
  454. }
  455. else if(signal_energy < 1.8*energy_threshhold)
  456. {
  457. totalnum++;
  458. }
  459. else
  460. ;
  461. subframe_energyvar();
  462. //根据子帧能量方差与子帧的平均能量比较来做判决;
  463. if(frame_energyvariance<(b)*(frame_energyreference+0.1))
  464. {
  465. totalavvnum++;
  466. }
  467.                    
  468. write_data(qq);
  469. read_signal();
  470. s--;
  471. }
  472. //if(totalnum>60 && totalavvnum<60)
  473. //{
  474. // flag = true;  
  475. // write_data(qq);
  476. //}
  477. //else
  478. {
  479. if(totalenergynum>120)
  480. {
  481. totalenergynum=0;
  482. //语音结束点,并更新噪声
  483. flag = false;
  484. compress_signal();
  485. write_data(qq);
  486. noise_update();//当判为静音帧时进行噪声更新          
  487. }//if(totalenergynum>70 && totalavvnum>50)结束
  488. else
  489. {
  490. flag = true;
  491. write_data(qq);
  492. }
  493. }//while(s!=0)结束
  494. }//while(flag)结束
  495.     }//while(1)结束
  496. }//主函数结束