[数字麦克风] 声源定位代码

littleshrimp   2017-10-19 12:28 楼主
完成SensorTile声源定位代码 所有计算代码全部有STM32L476完成 计算出角度后通过USB CDC将数据发送到电脑 上位机根据角度控制图片转动 ezgif-4-0a4ae49ab8.gif 具体过程可以参考下边贴子 为SensorTile添加一颗外部麦克风实现双通道输入 https://bbs.eeworld.com.cn/thread-569074-1-1.html 利用SensorTile和EXCEL对双声道麦克风的数据进行简单分析 https://bbs.eeworld.com.cn/thread-569171-1-1.html 双麦克风声源定位分析 https://bbs.eeworld.com.cn/thread-570113-1-1.html 主要代码
  1. int main( void )
  2. {
  3. uint16_t i;
  4. float a,b,c;
  5. /* STM32F4xx HAL library initialization:
  6. - Configure the Flash prefetch, instruction and Data caches
  7. - Configure the Systick to generate an interrupt each 1 msec
  8. - Set NVIC Group Priority to 4
  9. - Global MSP (MCU Support Package) initialization
  10. */
  11. HAL_Init();
  12. /* Configure the system clock */
  13. SystemClock_Config();
  14. /* Configure Audio Output peripheral (SAI) and external DAC */
  15. BSP_AUDIO_OUT_Init(PCM1774_0, &PCM1774_X_0_handle, 0, 20, AUDIO_SAMPLING_FREQUENCY);
  16. BSP_AUDIO_OUT_SetVolume(PCM1774_X_0_handle, 10);
  17. /* Configure Audio Input peripheral - DFSDM */
  18. BSP_AUDIO_IN_Init(AUDIO_SAMPLING_FREQUENCY, 16, AUDIO_CHANNELS);
  19. /* enable USB power on Pwrctrl CR2 register */
  20. HAL_PWREx_EnableVddUSB();
  21. /*** USB CDC Configuration ***/
  22. /* Init Device Library */
  23. USBD_Init(&USBD_Device, &VCP_Desc, 0);
  24. /* Add Supported Class */
  25. USBD_RegisterClass(&USBD_Device, USBD_CDC_CLASS);
  26. /* Add Interface callbacks for AUDIO and CDC Class */
  27. USBD_CDC_RegisterInterface(&USBD_Device, &USBD_CDC_fops);
  28. /* Start Device Process */
  29. USBD_Start(&USBD_Device);
  30. /* Start Microphone acquisition */
  31. BSP_AUDIO_IN_Record(PCM_Buffer,0);
  32. while (1)
  33. {
  34. //数据达到FFT_SIZE时做FFT
  35. if(fft_flag)
  36. {
  37. //填充左声道数据到fft_data
  38. for(i=0;i<FFT_SIZE;i++)
  39. {
  40. fft_data[i*2] = audio_out1[i];[/i]
  41. [i] fft_data[i*2 + 1] = 0;[/i]
  42. [i] }[/i]
  43. [i] //FFT转换[/i]
  44. [i] fft();[/i]
  45. [i] //计算最大幅度[/i]
  46. [i] amplitude[0] = get_max_index_amplitude();[/i]
  47. [i] //判断幅度是否大于预设幅度[/i]
  48. [i] if(amplitude[0] > AMPLITUDE_LEVEL)[/i]
  49. [i] {[/i]
  50. [i] //判断最大幅度对应的频率是否超过测试允许的最大频率[/i]
  51. [i] while(get_max_index_freq() > MAX_FREQ)[/i]
  52. [i] {[/i]
  53. [i] //如果频率过高,去掉最大值,读取第二大幅度数据[/i]
  54. [i] fft_mod[max_index] = 0;[/i]
  55. [i] arm_max_f32(fft_mod, FFT_SIZE, &maxValue, &max_index);[/i]
  56. [i] }[/i]
  57. [i] } [/i]
  58. [i] //获得当前频率[/i]
  59. [i] freq[0] = get_max_index_freq();[/i]
  60. [i] //获得当前频率的相位[/i]
  61. [i] phase[0] = get_max_index_phase();[/i]
  62. [i] //填充右声道数据到fft_data[/i]
  63. [i] for(i=0;i<FFT_SIZE;i++)[/i]
  64. [i] {[/i]
  65. [i] fft_data[i*2] = audio_out2;[/i]
  66. [i] fft_data[i*2 + 1] = 0;[/i]
  67. [i] }[/i]
  68. [i] //FFT转换[/i]
  69. [i] fft();[/i]
  70. [i] //计算最大幅度[/i]
  71. [i] amplitude[1] = get_max_index_amplitude();[/i]
  72. [i] //判断幅度是否大于预设幅度[/i]
  73. [i] if(amplitude[1] > AMPLITUDE_LEVEL)[/i]
  74. [i] {[/i]
  75. [i] //判断最大幅度对应的频率是否超过测试允许的最大频率[/i]
  76. [i] while(get_max_index_freq() > MAX_FREQ)[/i]
  77. [i] {[/i]
  78. [i] //如果频率过高,去掉最大值,读取第二大幅度数据[/i]
  79. [i] fft_mod[max_index] = 0;[/i]
  80. [i] arm_max_f32(fft_mod, FFT_SIZE, &maxValue, &max_index);[/i]
  81. [i] }[/i]
  82. [i] } [/i]
  83. [i] //获得当前频率[/i]
  84. [i] freq[1] = get_max_index_freq();[/i]
  85. [i] //获得当前频率的相位[/i]
  86. [i] phase[1] = get_max_index_phase();[/i]
  87. [i] //如果左右声道符合频率要求的最大幅度对应的频率相等,且幅度大于预设值[/i]
  88. [i] if( (amplitude[0] > AMPLITUDE_LEVEL || amplitude[1] > AMPLITUDE_LEVEL) && freq[0] == freq[1])[/i]
  89. [i] {[/i]
  90. [i] //计算相位差[/i]
  91. [i] phase_diff = phase[0] - phase[1];[/i]
  92. [i] //相位差大于180度时取反[/i]
  93. [i] if(phase_diff < -180) phase_diff = 360 + phase_diff;[/i]
  94. [i] else if(phase_diff > 180) phase_diff = phase_diff - 360;[/i]
  95. [i] //计算声源到2个麦克风的距离差[/i]
  96. [i] length_diff = 346.00/freq[0]/360.00*phase_diff;[/i]
  97. [i] //如果因为误差导致距离差不符合2边之合大于第3边时,限定length_diff的最大长度[/i]
  98. [i] if(length_diff > 0.159999999)length_diff = 0.15999999;[/i]
  99. [i] else if(length_diff < -0.15999999)length_diff = -0.15999999;[/i]
  100. [i] //读取预设麦克风间距和声源到麦克风的距离[/i]
  101. [i] c = DISTANCE_LEFT_MIC_RIGHT_MIC;[/i]
  102. [i] a = DISTANCE_SOUND_SOURCE_LEFT_MIC;[/i]
  103. [i] b = DISTANCE_SOUND_SOURCE_LEFT_MIC + length_diff;[/i]
  104. [i] //计算弧度[/i]
  105. [i] angle = acos((pow(a,2)+pow(c,2)-pow(b,2))/(2*a*c));[/i]
  106. [i] //计算角度[/i]
  107. [i] angle = angle / PI * 180;[/i]
  108. [i] //通过虚拟串口发送到电脑[/i]
  109. [i] sprintf( dataOut, "freq:%.2f\tphaseL:%.2f\tphaseR:%.2f\tphaseDiff:%.2f\tlength:%.2f\tangle:%.2f\r\n", freq[0], phase[0], phase[1], phase_diff,length_diff, angle);[/i]
  110. [i] CDC_Fill_Buffer(( uint8_t * )dataOut, strlen( dataOut ));[/i]
  111. [i] __NOP();[/i]
  112. [i] }[/i]
  113. [i] __NOP();[/i]
  114. [i] fft_flag = 0;[/i]
  115. [i] }[/i]
  116. [i] }[/i]
  117. [i]}[/i]
  118. [i]//快速符里叶变换[/i]
  119. [i]void fft(void)[/i]
  120. [i]{ [/i]
  121. [i] /* Process the data through the CFFT/CIFFT module */[/i]
  122. [i] arm_cfft_f32(&arm_cfft_sR_f32_len4096, fft_data, ifftFlag, doBitReverse);[/i]
  123. [i] arm_cmplx_mag_f32(fft_data, fft_mod, FFT_SIZE);[/i]
  124. [i] arm_max_f32(fft_mod, FFT_SIZE, &maxValue, &max_index); [/i]
  125. [i]}[/i]
  126. [i]//获得最大幅值[/i]
  127. [i]float get_max_index_amplitude(void)[/i]
  128. [i]{[/i]
  129. [i] if(max_index > 0)[/i]
  130. [i] {[/i]
  131. [i] return fft_mod[max_index] / (FFT_SIZE/2);[/i]
  132. [i] }[/i]
  133. [i] return 0;[/i]
  134. [i]}[/i]
  135. [i]//获得相位[/i]
  136. [i]float get_max_index_phase(void)[/i]
  137. [i]{ [/i]
  138. [i] float phase;[/i]
  139. [i] phase = atan2(fft_data[max_index * 2 + 1],fft_data[max_index * 2]) / PI * 180;[/i]
  140. [i] if(phase < 0)phase += 360;[/i]
  141. [i] return phase;[/i]
  142. [i]}[/i]
  143. [i]//获得频率[/i]
  144. [i]float get_max_index_freq(void)[/i]
  145. [i]{[/i]
  146. [i] return (max_index - 1.00f) * (float)AUDIO_SAMPLING_FREQUENCY / (float)FFT_SIZE;[/i]
  147. [i]}[/i]
  148. [i]/**[/i]
  149. [i]* [/i][i][url=home.php?mod=space&uid=159083]@brief[/url][/i][i] User function that is called when 1 ms of PDM data is available.[/i]
  150. [i]* In this application only PDM to PCM conversion and USB streaming[/i]
  151. [i]* is performed.[/i]
  152. [i]* User can add his own code here to perform some DSP or audio analysis.[/i]
  153. [i]* @param none[/i]
  154. [i]* @retval None[/i]
  155. [i]*/[/i]
  156. [i]void AudioProcess(void)[/i]
  157. [i]{[/i]
  158. [i] /*for L4 PDM to PCM conversion is performed in hardware by DFSDM peripheral*/[/i]
  159. [i] static uint32_t IndexOut = 0;[/i]
  160. [i] static uint32_t AudioOutActive = 0;[/i]
  161. [i] uint32_t indexIn;[/i]
  162. [i]// Send_Audio_to_USB((int16_t *)PCM_Buffer, AUDIO_SAMPLING_FREQUENCY/1000*AUDIO_CHANNELS); [/i]
  163. [i] for(indexIn=0;indexIn<AUDIO_IN_BUF_LEN;indexIn+=2)[/i]
  164. [i] {[/i]
  165. [i] audio_out_buffer[IndexOut++] = PCM_Buffer[indexIn];[/i]
  166. [i] audio_out_buffer[IndexOut++] = PCM_Buffer[indexIn+1];[/i]
  167. [i] if(fft_flag == 0)[/i]
  168. [i] {[/i]
  169. [i] audio_out1[audio_out_index] = PCM_Buffer[indexIn];[/i]
  170. [i] audio_out2[audio_out_index] = -PCM_Buffer[indexIn+1];[/i]
  171. [i] audio_out_index++;[/i]
  172. [i] if( audio_out_index >= FFT_SIZE)[/i]
  173. [i] {[/i]
  174. [i] audio_out_index = 0;[/i]
  175. [i] fft_flag = 1;[/i]
  176. [i] }[/i]
  177. [i] }[/i]
  178. [i] }[/i]
  179. [i] if(!AudioOutActive && IndexOut==AUDIO_OUT_BUF_LEN/2)[/i]
  180. [i] {[/i]
  181. [i] BSP_AUDIO_OUT_Play(PCM1774_X_0_handle,(uint16_t*)audio_out_buffer, AUDIO_OUT_BUF_LEN);[/i]
  182. [i] AudioOutActive=1;[/i]
  183. [i] }[/i]
  184. [i] if(IndexOut==AUDIO_OUT_BUF_LEN)[/i]
  185. [i] {[/i]
  186. [i] IndexOut=0;[/i]
  187. [i] }[/i]
  188. [i]}[/i]
  189. [i]/**[/i]
  190. [i]* @brief Transfer Complete user callback, called by BSP functions.[/i]
  191. [i]* @param None[/i]
  192. [i]* @retval None[/i]
  193. [i]*/[/i]
  194. [i]void BSP_AUDIO_IN_TransferComplete_CallBack(void)[/i]
  195. [i]{[/i]
  196. [i] AudioProcess();[/i]
  197. [i]}[/i]
  198. [i]/**[/i]
  199. [i]* @brief Half Transfer Complete user callback, called by BSP functions.[/i]
  200. [i]* @param None[/i]
  201. [i]* @retval None[/i]
  202. [i]*/[/i]
  203. [i]void BSP_AUDIO_IN_HalfTransfer_CallBack(void)[/i]
  204. [i]{[/i]
  205. [i] AudioProcess();[/i]
  206. [i]}
视频 https://training.eeworld.com.cn/course/4063/learn?preview=1#lesson/11047 例程基于STSW-STLKT01_V1.3.1修改
游客,如果您要查看本帖隐藏内容请回复
本帖最后由 littleshrimp 于 2017-10-19 12:28 编辑
虾扯蛋,蛋扯虾,虾扯蛋扯虾

回复评论 (40)

收藏,谢谢了。
点赞  2017-10-19 13:12
很厉害啊,学习了新知识
点赞  2017-10-19 14:05
牛掰
距离定位准确吗?
So TM what......?
点赞  2017-10-19 14:11
什么东东
点赞  2017-10-19 14:28
谢谢!
天下难事,必做于易;天下大事,必做于细。 与其博览群书,不如精读一本。
点赞  2017-10-19 15:27
学习学习
点赞  2017-10-19 16:17
引用: ljj3166 发表于 2017-10-19 14:11
牛掰
距离定位准确吗?

精度和采样率和声源频率有关
2颗麦克风只能用来估算声源的方向
虾扯蛋,蛋扯虾,虾扯蛋扯虾
点赞  2017-10-19 21:01
厉害学习学习
点赞  2017-10-20 11:24
最近很多城市的鸣笛抓拍就是这个原理吧。楼主再继续搞一搞呗。
点赞  2017-10-20 18:44
good job
点赞  2017-10-21 09:00
看着很棒
点赞  2017-10-21 17:21
it very good topic!!!!!!!!!
点赞  2017-10-21 19:35
厉害了
BlueCoin套件上有4个硅麦,可以玩一下
http://www.st.com/content/st_com ... eval-bcnkt01v1.html
点赞  2017-10-25 16:48
引用: 朵拉A萌 发表于 2017-10-25 16:48
厉害了
BlueCoin套件上有4个硅麦,可以玩一下
http://www.st.com/content/st_com/zh/products/e ...

看到过这个套件,不知道哪卖,估计也不会便宜
里边有很多算法不错,相信厂家也不会提供源码
虾扯蛋,蛋扯虾,虾扯蛋扯虾
点赞  2017-10-25 17:24
学习学习
点赞  2017-10-25 23:15
点赞  2017-11-23 13:33
太棒了,刚刚好需要呢
点赞  2017-11-24 10:11
刚刚好需要
点赞  2018-1-5 16:27
真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒真棒
点赞  2018-2-12 16:54
123下一页
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复