博客首页 | 排行榜 |

ming899的博客

个人档案
博文分类
【32位MCU】音频均衡器  2010-03-18 16:04

音频均衡器,在影音方面,是指对声频信号各个频段的补偿作用。对于不同的频率,有着不同的增益,这便形成了不同的音乐效果。

1.均衡器的调整方法:
超低音:20Hz-40Hz,适当时声音强而有力。能控制雷声、低音鼓、管风琴和贝司的声音。过度提升会使音乐变得混浊不清。
低音:40Hz-150Hz,是声音的基础部份,其能量占整个音频能量的70%,是表现音乐风格的重要成份。
适当时,低音张弛得宜,声音丰满柔和,不足时声音单薄,150Hz,过度提升时会使声音发闷,明亮度下降,鼻音增强。
中低音:150Hz-500Hz,是声音的结构部分,人声位于这个位置,不足时,演唱声会被音乐淹没,声音软而无力,适当提升时会感到浑厚有力,提高声音的力度和响度。提升过度时会使低音变得生硬,300Hz处过度提升3-6dB,如再加上混响,则会严重影响声音的清晰度。
中音:500Hz-2KHz,包含大多数乐器的低次谐波和泛音,是小军鼓和打击乐器的特征音。适当时声音透彻明亮,不足时声音朦胧。过度提升时会产生类似电话的声音。
中高音:2KHz-5KHz,是弦乐的特征音(拉弦乐的弓与弦的摩搡声,弹拔乐的手指触弦的声音某)。不足时声音的穿透力下降,过强时会掩蔽语言音节的识别。
高音:7KHz-8KHz,是影响声音层次感的频率。过度提升会使短笛、长笛声音突出,语言的齿音加重和音色发毛。
极高音:8KHz-10KHz
合适时,三角铁和立叉的金属感通透率高,沙钟的节奏清晰可辨。过度提升会使声音不自然,易烧毁高频单元。

2.平衡悦耳的声音应是:
150Hz以下(低音)应是丰满、柔和而富有弹性;
150Hz-500Hz(中低音)应是浑厚有力百不混浊;
500Hz-5KHz(中高音)应是明亮透彻而不生硬;
5KHz以上(高音)应是纤细,园顺而不尖锐刺耳。
整个频响特性平直时:声音自然丰满而有弹性,层次清晰园顺悦耳。频响多峰谷时:声音粗糙混浊,高音刺耳发毛,无层次感扩声易发生反馈啸叫。

3.频率的音感特征:
30~60Hz 沉闷 如没有相当大的响度,人耳很难感觉。
60~100Hz 沉重 80Hz附近能产生极强的“重感”效果,响度很高也不会给人舒服的感觉,可给人以强烈的刺激作用。
100~200Hz 丰满
200~500Hz 力度 易引起嗡嗡声的烦闷心理。
500~1KHz 明朗 800Hz附近如提升10dB,会明显产生一种嘈杂感,狭窄感。
1K~2KHz 透亮 2800Kz附近明亮感关系最大。
2K~4Kz 尖锐 6800Hz形成尖啸,锐利的感觉。
4K~8Kz 清脆 3400Hz易引起听觉疲劳。
8K~16Kz 纤细 >7.5KHz音感清彻纤细。

4.设计方案:
(1)前置放大电路:
 a. 小信号电压放大倍数不小于400倍(输入正弦信号电压有效值小于10mV)。
 b. -1dB通频带为20Hz~20kHz。
 c. 输出电阻为600。
(2)应用数字信号处理技术,对语音信号(20Hz~20kHz)进行幅频均衡。要求:
 a. 输入电阻为600。
 b. 经过数字幅频均衡处理后,以10kHz时输出信号电压幅度为基准,通频带20Hz~20kHz内的电压幅度波动在1.5dB以内。

(前置电路采用AD603设计,MCU采样STM32,图略)
(在此感谢 何彪胜同学 提供技术支持)

5.主体部分程序:
/************************************
*函数名:void Init_Gain(void)
*功  能:初始化
*输  入:void
*返  回:void
*注  备:
*************************************/
void Init_FIR(void)
{
 DAC_OUT_Init();  //DAC初始化,输出0电平,AD603衰减0dB
 Init_ADC_DC();   //初始化AD为直流模式
// TIM1_Configuration(); //初始化
}
/************************************
*函数名:void DAC_out(void)
*功  能:DAC 直流输出
*输  入:u16 volt_mv
*返  回:void
*注  备:输入单位为mv
   为了校准在需要输出的电压上减去3mv
*************************************/
void DAC_out(u32 volt_mv)
{
// u16  DA_Code;      //为了校准在需要输出的电压上减去3mv
// DA_Code = (u16)((volt_mv)*4096/2500); //计算相应码值   
// DAC_SetChannel1Data(DAC_Align_12b_R, DA_Code); //送恒流源参考电压
 DAC_SetChannel1Data(DAC_Align_12b_R, (u16)volt_mv); //送恒流源参考电压
 DAC_SoftwareTriggerCmd(DAC_Channel_1, ENABLE);
}
/************************************
*函数名:void DAC_OUT_Init(void)
*功  能:DAC 直流输出初始化
*输  入:void
*返  回:void
*注  备:
*************************************/
void DAC_OUT_Init(void)
{
 DAC_InitTypeDef   DAC_InitStructure;
    /* DAC Periph clock enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
  /* DAC channel1 Configuration */
   DAC_InitStructure.DAC_Trigger = DAC_Trigger_Software; //DAC软件触发
   DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; //禁用噪声或三角波发生
   DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_4095;
   DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
   DAC_Init(DAC_Channel_1, &DAC_InitStructure);
   /* DAC channel2 Configuration */
   DAC_Init(DAC_Channel_2, &DAC_InitStructure);
   /* Enable DAC Channel1: 当使能DAC通道1后, PA.04 自动连接到DAC转换器 */
   DAC_Cmd(DAC_Channel_1, ENABLE);
   /* Enable DAC Channel2: 当使能DAC通道2后, PA.05 自动连接到DAC转换器 */
   DAC_Cmd(DAC_Channel_2, ENABLE);
   /* Set DAC dual channel DHR12RD register */ //数据12位右对齐,DAC通道2,通道1
   DAC_SetDualChannelData(DAC_Align_12b_R, 0, 0);  //通道1~0.15V f6
 DAC_SoftwareTriggerCmd(DAC_Channel_1, ENABLE);
 DAC_SoftwareTriggerCmd(DAC_Channel_2, ENABLE);
}
/************************************
*函数名:u16 Get_AD_value(void)
*功  能:软件触发AD使能 
*输  入:void
*返  回:u16 AD_value
*注  备:
*************************************/
u16 Get_AD_value(void)
{
 u16  AD_value=0;
 //舍去第一次采样值
/* ADC_SoftwareStartConvCmd(ADC1, ENABLE);
 while(ADC_GetCalibrationStatus(ADC1));  //等待转换完成
 AD_value = ADC_GetConversionValue(ADC1);
 */
 ADC_SoftwareStartConvCmd(ADC1, ENABLE);
 while(ADC_GetCalibrationStatus(ADC1));  //等待转换完成
 AD_value = ADC_GetConversionValue(ADC1);
  return  AD_value;
}
/************************************
*函数名:void Init_ADC_DC(void)
*功  能:初始化ADC1为直流,软件触发方式
*输  入:void
*返  回:void
*注  备:
*************************************/
void Init_ADC_DC(void)
{
 ADC_InitTypeDef   ADC_InitStructure;
 /* ADC1 configuration ------------------------------------------------------*/   
 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  //ADC 工作模式 ADC1 ADC2 单独工作    
 ADC_InitStructure.ADC_ScanConvMode = DISABLE;       //多通道扫描模式
 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //是否启用连续转换模式ENABLE
 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  //软件触发方式
 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;   //数据右对齐
 ADC_InitStructure.ADC_NbrOfChannel = 1;  //ADC规则转换通道数量
 ADC_Init(ADC1, &ADC_InitStructure);  
 /* ADC1 regular channel8 configuration */ //配置转换规则  PB0
 ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_1Cycles5);  
 /* Enable ADC1 */
 ADC_Cmd(ADC1, ENABLE);   //使能ADC1 
 /* Enable ADC1 DMA */
 ADC_DMACmd(ADC1, ENABLE);  
 /* Enable Vrefint channel17 */
 //  ADC_TempSensorVrefintCmd(ENABLE); 
 /* Enable ADC1 reset calibaration register */  
 ADC_ResetCalibration(ADC1);
 /* Check the end of ADC1 reset calibration register */
 while(ADC_GetResetCalibrationStatus(ADC1)); 
 /* Start ADC1 calibaration */
 ADC_StartCalibration(ADC1);
 /* Check the end of ADC1 calibration */
 while(ADC_GetCalibrationStatus(ADC1)); 
 ADC_SoftwareStartConvCmd(ADC1, ENABLE);  //开启ADC   
}                        
//Step3.TIM1模块设置
void TIM1_Configuration(void)
{
 TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
// TIM_OCInitTypeDef TIM_OCInitStructure;  
 //TIM1 使用内部时钟
 //TIM_InternalClockConfig(TIM1);  
 //TIM1基本设置
 //设置预分频器分频系数71,即APB2=72M, TIM1_CLK=72/72=1MHz
 //TIM_Period(TIM1_ARR)=1000,计数器向上计数到1000后产生更新事件,计数值归零
 //向上计数模式
 //TIM_RepetitionCounter(TIM1_RCR)=0,每次向上溢出都产生更新事件
 TIM_BaseInitStructure.TIM_Period = 1800;
 TIM_BaseInitStructure.TIM_Prescaler = 0;
 TIM_BaseInitStructure.TIM_ClockDivision = 0;
 TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
 TIM_BaseInitStructure.TIM_RepetitionCounter = 0;
 TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);  
 //清中断,以免一启用中断后立即产生中断
 TIM_ClearFlag(TIM1, TIM_FLAG_Update);
 //使能TIM1中断源
 TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);  
 //TIM1总开关:开启
 TIM_Cmd(TIM1, ENABLE);
}
//64HZ低通
u16 IIR_LPF_64Hz(void)  

 static long long buf_64Hzn=0,buf_64Hzn_1=0,buf_64Hzn_2=0;
 s16 xn,yn;
 xn = Get_AD_value(); 
 buf_64Hzn = (xn-2048)*16 + (19844*buf_64Hzn_1 - 9845*buf_64Hzn_2)/10000;  
 yn = 3*(buf_64Hzn + 2*buf_64Hzn_1 + buf_64Hzn_2)/100000 + 32768;   
 buf_64Hzn_2 = buf_64Hzn_1;
 buf_64Hzn_1 = buf_64Hzn;
 return yn;   
}
//125Hz带通   
u16 IIR_BPF_125Hz(void) 
{
 static long long  buf1_125_n=0,buf1_125_n_1=0,buf1_125_n_2=0;
 static long long  buf2_125_n=0,buf2_125_n_1=0,buf2_125_n_2=0;
 s16 xn,y1n,y2n; 
 xn = Get_AD_value();  //获取AD采样值
  //第一级
 buf1_125_n = xn + 1.9932*buf1_125_n_1 - 0.9936*buf1_125_n_2;  
// y1n = 0.00391612*(buf1_125_n - buf1_125_n_2);    //****   加上会失真  + 32768 
 y1n = 78*(buf1_125_n - buf1_125_n_2)/1000000 +2048;
 buf1_125_n_2 = buf1_125_n_1;
 buf1_125_n_1 = buf1_125_n;   
 //第二级
 buf2_125_n = y1n + (2045*buf2_125_n_1 - 1022*buf2_125_n_2)>>10;  
 y2n = 0.00391612*(buf2_125_n - buf2_125_n_2) + 2048;  // 
// y2n = 257*(buf2_125_n - buf2_125_n_2)>>16 + 2048;  // 
 buf2_125_n_2 = buf2_125_n_1;
 buf2_125_n_1 = buf2_125_n;
 return y2n; 
}
//1k带通   
u16 IIR_BPF_1k(void) 
{
 static long long  buf1_1k_n=0,buf1_1k_n_1=0,buf1_1k_n_2=0;
 static long long  buf2_1k_n=0,buf2_1k_n_1=0,buf2_1k_n_2=0;
 s16 xn,y1n,y2n; 
 xn = Get_AD_value();  //获取AD采样值 
 //第一级
 buf1_1k_n = xn + (1958*buf1_1k_n_1 - 979*buf1_1k_n_2)/1000;  
 y1n = 3*(buf1_1k_n - buf1_1k_n_2)/1000;    //****   加上会失真  + 32768
 buf1_1k_n_2 = buf1_1k_n_1;
 buf1_1k_n_1 = buf1_1k_n;   
 //第二级
 buf2_1k_n = y1n + (1949*buf2_1k_n_1 - 977*buf2_1k_n_2)/1000;  
 y2n = 816*(buf2_1k_n - buf2_1k_n_2)/10000 + 2048;  //  
 buf2_1k_n_2 = buf2_1k_n_1;
 buf2_1k_n_1 = buf2_1k_n;
 return y2n; 
}  
//2k带通  偏移   
u16 IIR_BPF_2k(void) 
{
 static long long  buf1_2k_n=0,buf1_2k_n_1=0,buf1_2k_n_2=0;
 static long long  buf2_2k_n=0,buf2_2k_n_1=0,buf2_2k_n_2=0;
 s16 xn,y1n,y2n; 
 xn = Get_AD_value();  //获取AD采样值 
 //第一级
 buf1_2k_n = xn + (1889*buf1_2k_n_1 - 979*buf1_2k_n_2)/1000 ;  
 y1n = 155*(buf1_2k_n - buf1_2k_n_2)/10000;    //   加上会失真  + 32768
 buf1_2k_n_2 = buf1_2k_n_1;
 buf1_2k_n_1 = buf1_2k_n;
 //第二级
 buf2_2k_n = y1n + (1874*buf2_2k_n_1 - 977*buf2_2k_n_2)/1000 ;  
 y2n = 155*(buf2_2k_n - buf2_2k_n_2)/10000 + 2048;  //  
 buf2_2k_n_2 = buf2_2k_n_1;
 buf2_2k_n_1 = buf2_2k_n;
  return y2n; 

//8K FIR 高通 定点
u32 FIR_HPF_8k(void) 

 static s32 xn_1=0,xn_2=0,xn_3=0,xn_4=0;
 s32 xn;
 s32 yn;
 xn = Get_AD_value()-2048;    //获取AD采样值
         //*1024倍
// yn = -135.8181910486016*(xn + xn_4) - 187.696123738624*(xn_1 + xn_3) + 803.9252064246784*xn_2;
 yn = -136*(xn + xn_4) - 187*(xn_1 + xn_3) + 804*xn_2 ;  //*1024倍 
 xn_4 = xn_3;
 xn_3 = xn_2; 
 xn_2 = xn_1;
 xn_1 = xn;             //加上偏置2048*1024
 yn = (yn + 2097152)>>10; //DA_value = yn[22:10]   即:yn>>10
 return yn;      
}
 

类别:【32位MCU】 |
上一篇:【32位MCU】+ 多功能数字示波表(4) | 下一篇:【32位MCU】+ 多功能数字示波表(3)
以下网友评论只代表其个人观点,不代表本网站的观点或立场