i2S驱动MEMS数字硅麦采集噪声,使用PDM2PCM库

mems数字麦克风大致都一样,VDD和GND,时钟脚CLK,左右声道选择L/R,数据线DATA,当然这是输出PDM数据的麦克风,也有I2S接口的数字麦克风,他会多一个引脚,就是WS。我使用的是PDM数字麦克风。

d636298f8ecc4528b445c983f82d635c.png

该器件根据LR电平,分别在CLK的低电平和高电平时间输出左右声道信号,我这里就L/R接地,只有一个硅麦。实现单声道采集。(连线我就不多讲了,肯定都会)

fa94312d283e40b29c01ab659a9111e2.png

直接使用CubeMX进行配置

48KHz的采样率,16位数据,CLK的频率就是1.536MHz,

13278fa87b5e43118e068bff52b155e4.png

开启DMA采集

f918c8ec2dd148db8ab7f88659b69653.png

配置PDM2PCM

PDM_Filter_Handler_t PDM1_filter_handler;
	PDM_Filter_Config_t PDM1_filter_config;
	/* Initialize PDM Filter structure */
	PDM1_filter_handler.bit_order = PDM_FILTER_BIT_ORDER_LSB;
	PDM1_filter_handler.endianness = PDM_FILTER_ENDIANNESS_BE;
	PDM1_filter_handler.high_pass_tap = 2136746228; //2104533974; //2136746228; //0.9xx*(2^31-1)
	PDM1_filter_handler.out_ptr_channels = 1;
	PDM1_filter_handler.in_ptr_channels = 1;
	PDM_Filter_Init ( ( PDM_Filter_Handler_t * ) ( &PDM1_filter_handler ) );

	PDM1_filter_config.output_samples_number = 32;
	PDM1_filter_config.mic_gain = 0;

	PDM1_filter_config.decimation_factor = PDM_FILTER_DEC_FACTOR_48; //PCM数据的频率:i2s的clock/抽取因子/2
	PDM_Filter_setConfig ( ( PDM_Filter_Handler_t * ) &PDM1_filter_handler, &PDM1_filter_config );

开启I2S的DMA采集

HAL_I2S_Receive_DMA ( &hi2s3, &pdmRxBuf[0], PDM_NUM );

数据存放在pdmRxBuf里,调用转换函数

PDM_Filter ( &pdmRxBuf[0], &MidBuffer[0], &PDM1_filter_handler );

这里MidBuffer里存放的就是PCM数据。当你说话时,可以明显的看到PCM数据变化。

后面就是PCM转dB了,两个方法

1.使用求振幅平均值

/**
 * @brief 获取PCM数据分贝值
 *
 * @param pcm : pcm数据指针
 * @param len : pcm数据长度
 * @return int : 分贝值  = 20*log10(pcm数据平均值)
 * @note   Lp = 20*log10(Prms/Pref)dB  | Lp:计算结果音频分贝值, Prms:当前声音振幅值,Pref:声音振幅最大值(16bit=65535), 16Bit最大分贝值=20*log10(65535)=96.32(dB)。
 *
 */
int komijbox_sound_dB ( const int16_t *pcm, int len )
{
	int sum = 0;
	int dB = 0;
	short tmp = 0;
	short *pcmaddr = ( short * ) pcm;

	for ( int i = 0; i < len; i++ )
	{
		memcpy ( &tmp, pcmaddr + i, 2 ); // 获取2字节PCM数据
		sum += abs ( tmp ); // 绝对值求和累加
	}

	sum = sum / ( len ); // 求PCM数据的平均值,2个字节表示一个16Bit PCM采样数据

	printf ( "%d\r\n", sum );

	if ( sum )
	{
		dB = ( int ) ( 20 * log10 ( sum ) );
	}

	return dB;
}

2.均方根

float   Process ( const int16_t *data, int  length )
{
	int sum_square_ = 0;
	int  sample_count_ = 0;

	for ( int i = 0; i < length; i++ )
	{
		sum_square_ += data[i] * data[i];

	}

	sample_count_ += length;

	float rms =  sum_square_ / ( sample_count_ ) ;
	//rms=sqrt(rms);//开平方
	//printf ( "%f\r\n", rms );
	rms = 10 * log10 ( rms );
	return rms ;
}

这两种出来的数都是分呗,可以看到明显的声音变化。

bab617a9f25f442eaf121aeb89428fae.png

有一个问题暂时未解决,转换出来的值失真,底噪的值变化大,在普通环境中的分呗和在消音室里的分呗数一样,我不知道是硬件问题还是PDM转PCM时数据有问题。有想研究的铁子一起探讨!!!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值