麦克风的频率较低的组件

时间:2017-06-21 19:18:29

标签: audio embedded signal-processing stm32 microphone

我使用知识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存储来自一个通道的原始数据和来自其他通道的冗余数据。原始数据存储在数组的两个元素中,如fft_buffer [4]和fft_buffer [5],它们都是16位。并且fft_integer只存储来自一个通道的数据,每个数据占用32位。这就是为什么fft_buffer数组的大小为[FFT_LENGTH * 4]。 2个元素用于来自一个通道的数据,2个元素用于另一个通道。但是对于fft_integer,fft_integer数组的大小是FFT_LENGTH。因为存储了来自一个通道的数据,并且可以将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接口,它是一个单声道麦克风,这意味着只有一半的数据在传输时间的一半时有效。它的工作时间约为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

我用它作为小端。

1 个答案:

答案 0 :(得分:1)

原始数据中从DC开始的大型低频分量是由于将24位二进制补码样本错误地转换为int32_t而导致的大DC偏移。除非导致削波或算术溢出,否则DC偏移是听不见的。实际上没有任何低至100Hz的低频,这仅仅是FFT对强DC(0Hz)元件的响应的假象。这就是为什么你听不到任何低频。

下面我已尽可能清楚地说明了一些假设,以便答案可能会适应实际情况。

假设:

  

内存中的原始数据:

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

我用它作为小端。

  

2个元素用于来自一个通道的数据,2个元素用于另一个通道

并给出随后的评论:

  

fft_buffer [0]存储高16位,fft_buffer [1]存储低16位

然后数据实际上是 cross-endian ,例如,对于:

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 ;
}