gpt4 book ai didi

audio - 麦克风的低频分量过大

转载 作者:行者123 更新时间:2023-12-02 23:05:44 25 4
gpt4 key购买 nike

我使用knowles sph0645lm4h-b 麦克风获取数据,它是24 位PCM 格式,具有18 个数据精度。然后将 24 位 PCM 数据截断为 18 位数据,因为根据规范,最后 6 位始终为 0。之后,18 位数据存储为 32 位无符号整数。当 MSB 位为 0 时,表示为正整数,当 MSB 为 0 时,表示为负整数。

在那之后,我发现所有的数据都是正面的,不管我曾经测试过哪种声音。我用双频对其进行了测试,并进行了 FFT,然后我发现结果几乎是正确的,除了大约 0-100Hz 的较低频率更大。但我用数据重建了声音,用于 FFT 算法。重建的声音几乎是正确的,但有噪音。

我使用缓冲区来存储使用 DMA 传输的麦克风数据。缓冲区是

uint16_t fft_buffer[FFT_LENGTH*4]

DMA 配置如下:
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)fft_buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_BufferSize = FFT_LENGTH*4;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

从缓冲区中提取数据,截断为 18 位并将其扩展为 32 位并存储在 fft_integer:
int32_t fft_integer[FFT_LENGTH];

fft_buffer 存储来自一个 channel 的原始数据和来自另一个 channel 的冗余数据。原始数据存储在数组的两个元素中,如 fft_buffer[4] 和 fft_buffer[5],它们都是 16 位。 fft_integer 只存储来自一个 channel 的数据,每个数据占用 32 位。这就是 fft_buffer 数组的大小为 [FFT_LENGTH*4] 的原因。 2 个元素用于来自一个 channel 的数据,2 个元素用于另一个 channel 。但是对于 fft_integer,fft_integer 数组的大小是 FFT_LENGTH。因为存储了一个 channel 的数据,并且可以将 18 位存储在一个 int32_t 类型的元素中。
for (t=0;t<FFT_LENGTH*4;t=t+4){
uint8_t first_8_bits, second_8_bits, last_2_bits;
uint32_t store_int;
/* get the first 8 bits, middle 8 bits and last 2 bits, combine it to a new value */
first_8_bits = fft_buffer[t]>>8;
second_8_bits = fft_buffer[t]&0xFF;
last_2_bits = (fft_buffer[t+1]>>8)>>6;

store_int = ((first_8_bits <<10)+(second_8_bits <<2)+last_2_bits);

/* convert it to signed integer number according to the MSB of value
* if MSB is 1, then set all the bits before MSB to 1
*/
const uint8_t negative = ((store_int & (1 << 17)) != 0);
int32_t nativeInt;
if (negative)
nativeInt = store_int | ~((1 << 18) - 1);
else
nativeInt = store_int;

fft_integer[cnt] = nativeInt;
cnt++;
}

麦克风采用I2S接口(interface),是单声道麦克风,也就是说只有一半的数据在一半的传输时间内有效。它工作大约 128 毫秒,然后将停止工作。

这张图片显示了我将其转换为整数的数据。 enter image description here

我的问题是为什么会有大量低频分量,尽管它可以重建相似的声音。我确定硬件配置没有问题。

我做了一个实验,看看哪些原始数据存储在缓冲区中。我做了以下测试:
uint8_t a, b, c, d
for (t=0;t<FFT_LENGTH*4;t=t+4){
a = (fft_buffer[t]&0xFF00)>>8;
b = fft_buffer[t]&0x00FF;
c = (fft_buffer[t+1]&0xFF00)>>8;
/* set the tri-state to 0 */
d = fft_buffer[t+1]&0x0000;
printf("%.2x",a);
printf("%.2x",b);
printf("%.2x",c);
printf("%.2x\n",d);

}

PCM 数据如下所示:
0ec40000
0ec48000
0ec50000
0ec60000
0ec60000
0ec5c000
...
0cf28000
0cf20000
0cf10000
0cf04000
0cef8000
0cef0000
0cedc000
0ced4000
0cee4000
0ced8000
0cec4000
0cebc000
0ceb4000
....
0b554000
0b548000
0b538000
0b53c000
0b524000
0b50c000
0b50c000
...

内存中的原始数据:
c4 0e ff 00
c5 0e ff 40
...
52 0b ff c0
50 0b ff c0

我用它作为小端。

最佳答案

原始数据中从DC开始的大低频分量是由于错误地将24位二进制补码样本转换为int32_t造成的大DC偏移。 .直流偏移是听不见的,除非它导致发生削波或算术溢出。实际上没有任何高达 100Hz 的低频,这仅仅是 FFT 对强 DC (0Hz) 元素的响应的人工产物。这就是为什么你听不到任何低频的原因。

下面我已经尽可能清楚地陈述了一些假设,以便可以调整答案以匹配实际情况。

鉴于:

Raw data in Memory:

c4 0e ff 00
c5 0e ff 40
...
52 0b ff c0
50 0b ff c0

I use it as little endian.





2 elements are used for data from one channel and 2 element is used for the other channel



并给出随后的评论:

fft_buffer[0] stores the higher 16 bits, fft_buffer[1] stores the lower 16 bits



那么数据实际上是跨端的,例如,对于:
c4 0e ff 00

然后
fft_buffer[n]   = 0x0ec4 ;
fft_buffer[n+1] = 0x00ff ;

重建的样本应该是:
0x00ff0ec4

那么翻译就是重新解释 fft_buffer作为 32 位数组,交换 16 位字序,然后移位以将符号位移动到 int32_t符号位位置和(可选)重新缩放,例如:
c4 0e ff 00 => 0x00ff0ec4
0x00ff0ec4<< 8 = 0xff0ec400
0xff0ec400/ 16384 = 0xffff0ec4(-61756)

因此:
// Reinterpret DMA buffer as 32bit samples
int32_t* fft_buffer32 = (int32_t*)fft_buffer ;

// For each even numbered DMA buffer sample...
for( t = 0; t < FFT_LENGTH * 2; t += 2 )
{
// ... swap 16 bit word order
int32_t sample = fft_buffer32 [t] << 16 |
fft_buffer32 [t] >> 16 ;

// ... from 24 to 32 bit 2's complement and rescale to
// maintain original magnitude. Copy to single channel
// fft_integer array.
fft_integer[t / 2] = (sample << 8) / 16384 ;
}

关于audio - 麦克风的低频分量过大,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44684556/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com