[sdiy] Pulse Density Modulation, PDM instead of PWM (was Re: How to measure 1-bit DAC performance?)
Tom Wiltshire
tom at electricdruid.net
Mon May 1 19:01:02 CEST 2017
It's not an original idea, but I haven't seen anything that describes using the PIC NCO like this. I saw that the DSPSynths JVS-01 chip claims to use "1 MHz 16-bit sigma-delta PDM, 66.9KHz PCM"
http://www.dspsynth.eu
http://dspsynth.eu/files/JVS-01%20manual%20v1.0.pdf
So then I started wondering what exactly that was, and how it had been implemented, and whether it was actually any better than basic PWM (which some of the other chips use). They've done it on AVR, so the other question was if I could do it on a PIC, or if there was some special gizmo on those chips that helps.
I found out what I could about Pulse Density Modulation, and found a couple of different algorithms for doing it. This is the complicated "keeping track of the errors" way:
http://wsprnet.org/drupal/node/3216//
Then I found an alternative algorithm here:
https://hackaday.io/project/6356-delta-sigma-versus-pwm
The executive summary version of this is you have an integrator to which you add the signal every clock. If the integrator overflows, the output goes high for a single clock.
Reading about this it occurred to me that the NCO hardware is essentially exactly what they've done in software. Turns out it is. You can put the NCO in "Pulse Frequency Mode" (e.g. changing the increment changes the frequency of the pulses - pulse density modulation by another name) and then you simply stick your sample in as the increment value, left-aligned if you're not using the whole 20-bits.
There are a couple of technical points. The earlier incarnations of the PIC NCO peripheral only allow you a 16-bit increment for a 20-bit accumulator. This is no good. The newer chips have an extra byte which gives you a full 20-bit increment. You need a maximum value sample (say 65535) to make the integrator overflow practically every single time -
The second point is that you can set the length of the output pulses from a single clock upwards. I found that a single 16MHz clock was too short to do much due to rise time, and the net result was some distortion of the output waveform (a classic tube-like "squashing" actually - in other contacts, I'd probably be delighted..). Increasing the pulse length to 4 or 8 clocks and then shifting the increment down either 2 or 3 places fixed this problem at the cost of output frequency. But since 16MHz/8 is still 2MHz, that's miles above any frequency of interest and allows me to output waveforms and filter with a passive filter and still get a decent result.
There are various advantages. One is simple speed. Whilst you might well run a PWM module with a clock of 16MHz, with 10-bit resolution, that gives you an output frequency of 15.625KHz. The worst-case for PWM is the midpoint value, since the filter spends longest charging and then discharging whilst trying to produce a smooth middle value. For PDM, the midpoint value is the *best* case, since the output is one pulse on, one pulse off at the clock frequency - so say 16MHz for our example. That's enormously easier to smooth than 15KHz! As the output value approaches the extremes, you'll get long strings of on or off filled by a brief blip of the opposite, but the brief blips will always be distributed rather than all together as they are for PWM. This is a massive advantage.
It's a clever trick, and the NCO is dead handy for it. I shall probably be using it rather than PWM on future chip designs and projects.
There's still some things I don't understand about it, like what happens if you output high resolution samples faster than the integrator can keep up. For example, if you use 16-bit samples, a value of 1 will take 65536 clocks to overflow and produce a pulse. At 16MHz clock, that's 244Hz. If I send out another sample before that time has elapsed, what happens? Do I lose some resolution? Does it scramble the output? In practice it seems to work ok, so I'm betting you just lose resolution - it becomes impossible to differentiate two close sample values, because you don't allow the integrator time enough to settle accurately enough to see a single bit.
Tom
On 1 May 2017, at 15:58, Richie Burnett <rburnett at richieburnett.co.uk> wrote:
> Tom, I'm intrigued by your mention of using the NCO module for pulse density modulation. Is this described in an app note somewhere or something you came up with yourself?
>
> -Richie,
>
> Sent from my Xperia SP on O2
>
> ---- Tom Wiltshire wrote ----
>
>> Thank very much to everyone that helped me with this.
>>
>> With your pointers, I was able to establish using the FFT function on my scope that 10-bit PWM at 31.25KHz gives me background hash at a level -41dB wrt my sine signal, and that 10-bit PDM pushes that down to -64dB. That's not bad for something that is just one IO pin on a PIC with a passive RC filter hanging off it.
>>
>> I'm now going to experiment to see if I can squeeze more resolution out of it too, and if that helps further.
>>
>> Tom
>>
>>
>>
>> On 25 Apr 2017, at 14:09, Tom Wiltshire <tom at electricdruid.net> wrote:
>>
>>> Hi All,
>>>
>>> I've been using the PWM output module on the PIC chips as a cheap DAC for years. It does this job reasonably well, all things considered. Whilst the quality and 10-bit resolution aren't great, it's cheap and convenient, and those are big pluses.
>>>
>>> However, I've been looking at using the NCO peripheral as a Pulse Density Modulated output instead. This would in theory produce a higher frequency output and allow a greater resolution.
>>>
>>> In order to determine if the results I can get out of it are genuinely an improvement, I need to be able to accurately measure the performance of both styles of "DAC".
>>>
>>> How would I do this?
>>>
>>> My current method is to send an incrementing count to the DAC and then have a look at the post-reconstruction filter output on a 'scope. How wiggly the line is is my measure of quality! Not very exact!
>>>
>>> I've got a digital oscilloscope, a multimeter, and a laptop. No other test equipment is available, unless I make it.
>>>
>>> Thanks,
>>> Tom
>>>
>>>
>>> _______________________________________________
>>> Synth-diy mailing list
>>> Synth-diy at synth-diy.org
>>> http://synth-diy.org/mailman/listinfo/synth-diy
>>
>>
>> _______________________________________________
>> Synth-diy mailing list
>> Synth-diy at synth-diy.org
>> http://synth-diy.org/mailman/listinfo/synth-diy
More information about the Synth-diy
mailing list