Forums

MCU signal processing PDM to PCM

Started by Makodan 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){
    //Read data from microphone
    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!

[ - ]
Reply by StenzOctober 2, 2018

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.

[ - ]
Reply by MakodanOctober 3, 2018

Sounds good, I read about FIR filters, but I haven't made any. Are there any documentations about implementation (for dummies)? 

I read these:
https://www.dsprelated.com/freebooks/sasp/Filterin...

http://shulgadim.blogspot.com/2012/01/fir-filter-i...


[ - ]
Reply by dszaboOctober 3, 2018

I’d love to read more about this.  I can sort of picture it in my head, but don’t quite get it.  Thanks

[ - ]
Reply by dudelsoundOctober 4, 2018
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.
[ - ]
Reply by dszaboOctober 2, 2018

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

[ - ]
Reply by MakodanOctober 2, 2018

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?

[ - ]
Reply by dgshaw6October 2, 2018

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.

[ - ]
Reply by MakodanOctober 3, 2018

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.

[ - ]
Reply by dgshaw6October 3, 2018

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.

[ - ]
Reply by dszaboOctober 3, 2018

Another point probably worth making is that ST provides libraries for interfacing with mems mics, here is an AN: https://www.st.com/content/ccc/resource/technical/document/application_note/ca/18/be/bb/f8/53/47/a5/DM00040808.pdf/files/DM00040808.pdf/jcr:content/translations/en.DM00040808.pdf

It may be worth trying their implementation as a starting point to verify that your hardware is working properly. I think they also provide example code with the library. Note that they are using a HP filter to remove the offset

[ - ]
Reply by dszaboOctober 2, 2018

Subtracting our the offset would probably work. However, you may find that you need to high pass for some other reason, in which case there’s no need to do the subtraction. For now though, either way is fine