## MCU signal processing PDM to PCM

Started by 3 years ago11 replieslatest reply 3 years ago1087 views

I would like to measure background noise - speech loudness in a room with a wireless sensor (with STM32F1 + wifi module). I bought a MEMS microphone (MP34DT01). This microphone has PDM output. I generate 1.3 MHz clock for the microphone, so the sampling rate is 1.3 MSample/s. I read a lot about PDM, the conclusion that I just have to use a low pass filter.

Now I read 1000 sample into a buffer array (huge overhead, because I store a bit as uint8) then I use a second order IIR Butterworth with 20kHz cutting frequency. Then I send data over TCP to my PC and draw a real-time graph. Example code of the processing:

#define NZEROS 2
#define NPOLES 2
#define GAIN   5.282971791e+02

float filtered[1000] = {0};
uint8_t buffer[1000] = {0};
static float xv[NZEROS+1], yv[NPOLES+1];

while(1){
MP34DT01_Listen(buffer);

for(int i = 0, i<1000; i++){
{ xv[0] = xv[1]; xv[1] = xv[2];
xv[2] = buffer[i] / GAIN;
yv[0] = yv[1]; yv[1] = yv[2];
yv[2] =   (xv[0] + xv[2]) + 2 * xv[1]
+ ( -0.8807871294 * yv[0]) + (  1.8732156333 * yv[1]);
filtered[i] = yv[2];
}
}

//Send data over TCP to python client
WifiSend(filtered);
}


The output data doesn't correlate to the noise, I talked to the microphone, I knocked on it, but seems I process noise, neither of them appear on the graph. I tried to use moving average filter with 16 window, I tried another low pass filter, I tried 64 decimation than filter and filter than decimation.

What is the proper way to convert PDM to PCM?

Thank you!

[ - ]

A more efficient way to deal with PDM data is to group the 1-bit samples by eight into unsigned chars and do FIR filtering by using these as indices in lookup tables. The choice of FIR has the advantage that it can be used as a down sampler which operates at the target rate.

As an example, consider an 80-tap FIR and downsampling by a factor of 32. This requires 10 precalculated tables and the whole process boils down to the addition of 10 lookup values at the output rate.

[ - ]

[ - ]

[ - ]
some micro-controllers offer hard-wired instructions to count the number of bits in a variable. Sometimes these instructions can be accessed within c by using compiler intrinsics. This would greatly reduce your effort.

Using the number of ones in a byte as audio signal represents a decimation by eight with a moving average low pass FIR filter of length 8. And all of it in one cycle without memory usage.
[ - ]

Do the bytes filled by the listen function contain either 0 or 1?  If that’s the case you’ll end up with a DC offset of about 0.5.  If you were calculating an RMS value on your client side, that would cause some issues.  You could fix that with a high pass filter

[ - ]

Thank you! Yes, the listen function stores the samples as 0 or 1. Must I use the filter in any case? What if I just subtract 0.5?

[ - ]

Replace the data with signed values of -1 and +1 instead of 0 and 1, by converting your uint8_t to int8_t, multiply by 2 and subtract 1.

No need for high pass.

[ - ]

I modified the listen function, so it stores 0 and 1 as -1 and 1. After the filtering most of the filtered values is in the 0.02-0.09 range. It does not seems good.

[ - ]

I assume that you are decimating after the filtering operation.  In order to bring the signal back up to a reasonable level, you probably need to scale up by your decimation factor.

Also, I suggested +-1, but you can use any scale factor.  So you could store the data as +- 127 fro example.

[ - ]