Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Audio 麦克风的低频分量过大_Audio_Embedded_Signal Processing_Stm32_Microphone - Fatal编程技术网

Audio 麦克风的低频分量过大

Audio 麦克风的低频分量过大,audio,embedded,signal-processing,stm32,microphone,Audio,Embedded,Signal Processing,Stm32,Microphone,我使用knowles sph0645lm4h-b话筒采集数据,这是一种24位PCM格式,具有18个数据预测。然后,24位PCM数据被截断为18位数据,因为根据规范,最后6位始终为0。之后,18位数据存储为32位无符号整数。当MSB位为0时,表示它是正整数;当MSB位为0时,表示它是负整数 在那之后,我发现所有的数据都是肯定的,无论我用哪种声音来测试。我用一个双频测试了它,并做了FFT,然后我发现结果几乎是正确的,除了0-100Hz的较低频率更大。但是我用数据重建了声音,这是我用于FFT算法的。重

我使用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;
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
...
从缓冲区提取数据,截断为18位,扩展为32位,并存储在fft_整数处:

int32_t fft_integer[FFT_LENGTH];
fft_缓冲区存储来自一个通道的原始数据和来自另一个通道的冗余数据。原始数据存储在数组的两个元素,如fft_缓冲区[4]和fft_缓冲区[5],它们都是16位。fft_整数只存储来自一个通道的数据,每个数据取32位。这就是为什么fft_缓冲阵列的大小为[fft_长度*4]。2个元素用于来自一个通道的数据,2个元素用于另一个通道。但对于fft_整数,fft_整数数组的大小是fft_长度。因为来自一个通道的数据被存储,并且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++;
}
内存中的原始数据:

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

我将其用作小端元。

原始数据中从DC开始的大低频分量是由于错误地将24位2的补码样本转换为
int32\t
而导致的大DC偏移。直流偏移是听不见的,除非它导致剪辑或算术溢出发生。100Hz以下的低频率实际上并不存在,这只是FFT对强直流(0Hz)元件响应的人工制品。这就是为什么你听不到任何低频

下面我已经尽可能清楚地陈述了一些假设,这样答案也许可以根据实际情况进行调整

鉴于:

内存中的原始数据:

c4 0e ff 00
c5 0e ff 40
...
52 0b ff c0
50 0b ff c0
c4 0e ff 00
c5 0e ff 40
...
52 0b ff c0
50 0b ff c0
我把它当作小endian

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

鉴于随后的评论:

fft_缓冲区[0]存储较高的16位,fft_缓冲区[1]存储较低的16位

那么,数据实际上是跨端的,例如:

c4 0e ff 00
然后

重建样本应为:

0x00ff0ec4
然后,转换是将
fft\u buffer
重新解释为32位数组,交换16位字顺序,然后移动符号位到
int32\u t
符号位位置,并(可选)重新缩放,例如:

c4 0e ff 00 => 0x00ff0ec4
0x00ff0ec4<< 8    = 0xff0ec400
0xff0ec400/ 16384 = 0xffff0ec4(-61756)
c4 0e ff 00=>0x00ff0ec4
0x00ff0ec4 16;
// ... 从24位到32位2的补码和重缩放到
//保持原始震级。复制到单通道
//fft\u整数数组。

fft_integer[t/2]=(示例,您希望我们对此做些什么?您不显示代码,不能保证硬件正确(此处不涉及主题),不提供任何相关信息。“带噪声”甚至都不是主观的。量化?多少分贝?你看过相关设备的数据表了吗?电源噪声是什么?信噪比?…你的问题是什么?这是我第一次在堆栈溢出中。很抱歉,描述模糊。我再次编辑了这个问题。现在可能更好了。数据是如何包装在
fft\u integer
,y中的ou从一个32位字中提取16位,从另一个32位字中提取2位。这看起来不太可能。fft_整数中压缩的数据是8位8位2位(这里的所有精度)。我的DMA是这样配置的,每次传输16位数据时,正如我在可变fft_缓冲区中所示,这意味着为了接收24位PCM,DMA需要两次。fft_缓冲区包含原始数据。为了减少fft_缓冲区中不必要的数据,如来自一个通道的数据是有效数据,另一个通道是冗余的。i将其存储在fft_整数中。可能我没有清楚地描述它。由于fft_缓冲区是uint16_t类型,fft_缓冲区[0]存储较高的16位,fft_缓冲区[1]存储较低的16位。示例50 0b ff c0应解释为0b 50 c0 ff作为PCM格式的数据。因为50 0b属于较高的16位,而c0 ff属于较低的16位。您的算法非常好。令人惊讶。如果较低的16位位于较高的地址中,则这不是小的尾端。每个16位都是小的尾端,但元素顺序是big-endian。它实际上是cross-endian。Fill修复答案。它是cross-endian吗?你给了我一个很好的方向。DMA将每个16位数据传输到内存中。这些数据在内存中是如何组织的。也许我误解了DMA的工作原理。@WilliWu:是的;SPI按照机器顺序处理单个16位传输,但是麦克风按相反的顺序对每个样本进行两次传输。16位传输的位顺序由SPI接口定义,但连续传输的顺序由麦克风定义。因此,每个16位的字节顺序正确,但每个32位的16位字顺序错误。(我想-我可能错了)。
// 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 ;
}