我使用知识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毫秒,然后就会停止工作。
我的问题是为什么有较低频率的大组件,尽管它可以重建类似的声音。我确信硬件配置没有问题。
我做了一个实验,看看哪些原始数据存储在缓冲区中。我做了以下测试:
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
我用它作为小端。
答案 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 ;
}