PWM + Filter

Go To Last Post
31 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,
I want to use mega8 to generate a sine wave using it's PWM output. The frequency range would be from 20Hz to 20KHz (audio frequency). What is the good PWM frequency should I use? How do I calculate the output filter? Consider I'm just using simple RC filter.
Thanks.

KISS - Keep It Simple Stupid!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With a 16mhz xtal, you can get 62.5khz 8 bit pwm from one timer. If you can get a 40khz interrupt from another timer for sampling rate you are golden. Calc f=1/(2piRC) at 20khz. Just pick a c like .1 or .01 and use what comes out for R. Try 2 stages. Not mathematically correct, but might be good enough.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well done Bob. That's a good idea. The simulation seems great for me.

KISS - Keep It Simple Stupid!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Aaaagh, Bob! That's *not* gonna work well - it'll be full of aliases and harmonic distortion.

For the best audio your pwm rate *must* match your sampling rate; your sampling rate must meet the nyquist minima; you must use as many bits as possible; and your reconstruction filter must be brick-wall (or as good as you can get) at the maximum frequency of the input.

So ideally, set the pwm rate to 44.1KHz and sample the audio at that rate; one sample to one pwm output. Filter at 20k at best, better at 16k, with *at least* 12dB an octave, preferably more. If you're going to use an RC filter I'd advise using multiple stages and an op-amd; you might like to consider a switched-capacitor filter. Also, you should filter the input audio so it has nothing above 20kHz, too...

Neil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Maybe he'll try it and get back to us. I have nice clean tones coming out using 8khz sample rate and the 62khz pwm. You tried to explain this to me a while back and I'm too stupid to understand it. If I change the pwm duty every 125usec, but the pwm freq is 16usec, you'll see 7 or 8 little 62khz stair steps in between 8khz samples. The higher the pwm freq, the easier it is to skim it off with an rc filter. Isnt that how the 18 bit dacs work with the 16 bit pwm in CDs?

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I feed 44.1 kHz sampled sound via 44.1 kHz PWM
directly to a speaker (with or without MOSFETs as AMP).
Sounds not that bad.

Maybe my ears are too bad and I am too old.... :lol:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Barn,
I understand why Bob uses that 40KHz sampling frequency, looks like he doesn't run to a high quality audio reproduction, maybe just a telephone like.
My need is I want to reproduce sound waves as good as it could (highest sample rate, greatest resolution).
Right now i use somewhat odd but cool sampling rate due my crystal's frequency. I use 8 MHz crystal, therefore i got 125KHz sampling rate (by /64 clock divisor). I won't modify the timer's TOP value to meet that 44.1KHz requirement because I still want to take the advantage of 16 bit PWM resolution (using Timer 1).

KISS - Keep It Simple Stupid!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bob - as you say 'seven or *eight*' stair steps between samples - think of it as 12.5% jitter on the sample. With the higher sample rate it's easier to filter the PWM frequency away, but because your sample rate and pwm rate are not the same you have an aliased frequency as a component of the output.

If the OP wishes to get the best quality possible - and let's face it, with eight bits he needs all the help he can get :) - then he should use an audio sampling rate which is an integer multiple - ideally '1' - of the PWM rate.

Class D amplifiers will use PWM rates in the megahertz range, to simplify the filtering requirements.

m, if you have a pwm rate of 125 kHz, you only have 64 counts available between samples - effectively you're working with six bits irrespective of the number of bits in the counter. 36dB s/n ratio...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So if I rewrite my program to keep changing OCR at 8khz (sample rate), and change pwm freq from 62500 to 10000, and play a 1000hz sine wave from the table, I will hear a 2000hz alias between the sample rate and the pwm rate? Even with my 4khz two stage RC lo pass filter on the pwm output? (My understanding is that the alias is between the sampling freq and the sampled signal). I would expect it to sound like dogbreath with no filter, and sound maybe soso with a wimpy filter, and sound pretty good with an 8th order LC Cauer filter, but I'm trying to devise an experiment here that makes the alias audibly prominent.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

:?: :?: :?: :cry: :cry: :cry:
hit me barn, really, hit me. I've banging my head on the wall but still don't understand your statement.
like you said before

Quote:
if you have a pwm rate of 125 kHz, you only have 64 counts available between samples

I don't understand how can you say that I just only have 64 counts available between samples? how do you know that?
I'm so sorry.

KISS - Keep It Simple Stupid!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I may have misunderstood you; I now suspect that you're using a prescale of 64 as the clock source to the counter - so the PWM timer counts at a rate of 8M/64 = 125kHz.

The PWM is effectively a counter, right? It counts up, and when it reaches your trigger value it changes state, so you get an average across a single PWM waveform which is the instantaneous DC you're trying to output (yeah, I know it's an AC signal, but think of it as stepped DC).

You start with your 8MHz clock, and divide by 64 to get 125k PWM ticks per second. So every 64 clocks, the PWM increments by one. The counter starts, and sets the output high. When it gets to the OCR value which you will have loaded with your desired output value, it sets the output low. When it reaches the TOP value which you will have set as the repeat rate for your PWM, it resets the counter to zero, sets the output high again, and repeats.

So, to quote from app note AVR131 (which deals with the Tiny26 and its phase locked high speed counter, but the principles are the same):

Quote:

The Top value affects the resolution and the
base frequency of the PWM – the higher the Top value is the higher resolution and the
lower base frequency.

So, looking at that nice MR Nyquist fellow, we find that to achieve adequate reconstruction of the sampled signal, we must sample at least twice (and preferably a bit more) the frequency of the highest signal frequency we have in the signal, and we must be careful that our signal *does not* contain signals at more than half the sampling rate.

At 44100Hz sampling, there are therefore only 125000/44100 = 2.8 timer ticks between successive output samples - which means that practically you can only count to two on the PWM TOP value, and that restricts you to only one bit on the PWM... not good.

If you remove the prescale, you now clock the timer 64 times faster and you have 8M/44100 = 181 ticks between samples; now you can practically increase your sample depth to seven bits (0-127) (You could use the entire 181 ticks for an improvement of a dB or so signal to noise by scaling your signal). Double your clock speed to 16MHz and you can do 8-bit output without problems.

This is why Atmel now have a phase-locked oscillator in some chips which allows counts at 64MHz - with that you can go to ten-bit output at 44.1ks/s.

BUT... there's still the issue of synchronisation of the PWM clock and the audio samples. You really need - for best quality - a one to one match between the two. And you can't do that with a simple divisor change to 44.1kHz - if you sampled your audio at 32kHz, though, you could use a PWM top of 250 (actually, it probably would be 249) and that way your samples match the PWM rate at as near to 8-bit quality as makes no difference (scaling the audio to suit).

Why is this important? (Bob, this goes to answering your query too, though I'm writing some code to generate audio with your proposed 8k sample/10k pwm repeat rate which will demonstrate the issue audibly).

Using Bob's example, he has the PWM reseting the count every 100us, and new data arriving asynchonously every 125us. Assuming they're synced at the first sample, he loads sample 1 at the same time as pwm cycle 1 starts. 100uS later, the pwm times out and starts again, but the OC value is not rewritten until 25us later - so the old value is still in the OCR. I don't know exactly what the PWM counter does in this situation but there are several cases:

- the old value was less than 25% and it's already timed out
- the old value was more than 25% but the new value is less
- the old value was more than 25% and the new value is more

And so on. Whatever happens it's basically not going to count to the value you expect. And it gets worse at the next sample; we don't have it ready until half-way through the pwm period. If you think of the PWM as a DAC that takes 100us to produce an output, you'll see that effectively, every fourth sample is repeated - though because of the counting system, it may not actually *be* the fourth sample...

Am I boring people yet?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hokay, here's a little program to demonstrate what happens if your input samples and output samples are not at the same rate. It's in C, for linux, but should compile ok in MS - uses char 8bit, short 16 bit, int 32 bit; you might need to change those but probably not.

It's a *horrible* bit of code, completely lacking in the social graces and any form of error checking. If you don't keep an eye on it it will probably wander off and pee in the fireplace or something equally obnoxious... but it does demonstrate what's going on. I did the analysis using the Audacity player (select the entire track and hit analysis, hanning window, 16k window size.

It generates two files - 911-clean.wav and 911-dirty.wav

Each is ten seconds long; the first generates (using a sine lookup table) a 911Hz tone sampled at 8kHz and replayed at 8kHz. As you'll hear, it's pretty clean for an eight-bit signal, and the analysis will show lots of harmonics but all around -50dB... they're there because I deliberately chose a frequency without a common factor with the sample rate.

The second shifts the sample frequency to 10kHz and attempts to show a 911Hz tone again, but this time every fourth sample is duplicated... zoom in to the waveform and you'll see the step. This is what you get if your PWM rate is 10k and your audio sample rate is 8k, per Bob's question upthread. Now listen to it; you can hear all sorts of nasties going on. And when you do the analysis, you see the primary tone at 911Hz, an alias almost as loud at 2911Hz - note that 2k offset - an alias at 4911Hz but reflected by the sampling to 3100 or thereabouts, and another reflection at 1100 or so... nasty nasty nasty.

*That's* what happens on a single tone; now imagine it happening with speech, or worse, music. Even on telephone quality audio, I put it to m'learned colleagues that this is rather an unpleasant effect.

// pwm demo to show nastiness involved in pwm
//
// step one - create an eight-bit sinewave as raw audio

// generate steptone...

#include 
#include 
#include 

#define PI 3.14159265
	
#define FTONE 911

struct _waveheader {
	char 	riff[4];
	int 	block_size;
	char 	wave[4];
	char 	fmt[4];
	int 	chunk_size;
	short   tag;
	short		channels;
	long	samples_per_sec;
	long	bytes_per_sec;
	short		block_align;
	short		bits_per_sample;
	char	data[4];
	int	data_size;
	};

_waveheader wh;              			// header for wave files
FILE * fo;						// file handles

int main (int argc, char * argv[])
{
long count;						// number of bytes in block
long q;
int r;
char s;
int t;
unsigned char sines[256];		// the sine wave table
int sin_step;							// a high-precision offset
int sin_off;							// the pointer

	// build a sine wave table - 256 samples
	// the samples are eight bits unsigned offset with the zero at 0x80
	
	for (q=0; q<256; q++)
	{
		sines[q] = (unsigned char)(127*sin(((float)q/(float)256)*(2*PI)))+128;
	}
	
	printf("Opening 8_bit_tone.wav for generation\n");
	printf("Pass 1 - 911Hz sampled at 8ks/s, played at 8ks/s\n");

	// fill the header
	// total length will be 10 seconds
	// we're doing this at 8kHz sample rate, 
	// eight bits per sample
	// mono FTONEHz tone

	memcpy (wh.riff,"RIFF",4);
	wh.block_size = 80036;
	memcpy (wh.wave,"WAVE",4);
	memcpy (wh.fmt,"fmt ",4);
	wh.chunk_size = 16;
	wh.tag = 1;
	wh.channels = 1;
	wh.samples_per_sec = 8000;
	wh.bytes_per_sec = 8000;
	wh.block_align = 1;
	wh.bits_per_sample= 8;
	memcpy(wh.data,"data",4);
	wh.data_size = 80000;

	fo = fopen("911hz-clean.wav","wb");			// write binary as output
	fwrite (&wh,sizeof(wh),1,fo);			// write the header
	

	// to use the sine table, we move along it in regular steps. The size of
	// the step is the ratio of the generated tone and the sample rate. Ideally
	// this is done at high resolution so that the accumulated errors are reduced
	// to a practical minimum. I use 16-bit resolution for the step-size.
	
	sin_step = (int)(65536*((float)FTONE/(float)8000));
	sin_off = 0;
	//
	for (count = 0; count < 80000; count++)
	{
		//s = (char)(127*sin((((float)(FTONE)/(float)8000)*count)*(2*PI)))+128;
		sin_off += sin_step;
		if (sin_off > 65535)
		{
			sin_off -= 65536;
		}
		s = sines[sin_off>>8];
		fwrite (&s,sizeof(s),1,fo);
	}
	
	fcloseall();
	
	printf("Pass 2 - 911Hz sampled at 8ks/s, played at 10ks/s\n");

	// fill the header
	// total length will be 10 seconds
	// we're doing this at 10kHz sample rate, 
	// eight bits per sample, every fourth sample repeated
	// mono FTONEHz tone

	// now we are simulating the situation where a sample every 125us is fed to 
	// a DAC which expects a sample every 100us - so, every fourth sample is
	// sent twice.
	//
	// we also need to change the sample rate which is now 10kHz
	
	memcpy (wh.riff,"RIFF",4);
	wh.block_size = 80036;
	memcpy (wh.wave,"WAVE",4);
	memcpy (wh.fmt,"fmt ",4);
	wh.chunk_size = 16;
	wh.tag = 1;
	wh.channels = 1;
	wh.samples_per_sec = 10000;
	wh.bytes_per_sec = 10000;
	wh.block_align = 1;
	wh.bits_per_sample= 8;
	memcpy(wh.data,"data",4);
	wh.data_size = 100000;

	fo = fopen("911hz-dirty.wav","wb");			// write binary as output
	fwrite (&wh,sizeof(wh),1,fo);			// write the header
	
	
	sin_step = (int)(65536*((float)FTONE/(float)8000));
	sin_off = 0;
	//
	for (count = 0; count < 80000; count++)
	{
		sin_off += sin_step;
		if (sin_off > 65535)
		{
			sin_off -= 65536;
		}
		s = sines[sin_off>>8];
		fwrite (&s,sizeof(s),1,fo);
		
		if (count % 4 == 0)
		{
			// repeat the sample
			fwrite (&s, sizeof(s),1,fo);
		}
	}
	printf("All done!\n");

	fclose(fo);
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But I must respectfully point out that line one of my message says "keep the sample rate at 8khz".

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Indeed, but you then follow it with 'pwm freq to 10kHz' which I have understood to mean the repeat rate (base frequency) of the PWM.

My code produces - in the dirty file - output at 10kHz and input at 8kHz with no interpolation, as you'd get in that circumstance.

Have I misunderstood totally here?

Neil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lets apply the 2 stage 4khz rc filter to the dirty waveform and see if it cleans up. (My original assertion is that 62500hz would be easier to filter off, but we changed it down to 10khz to make the bad stuff more obvious)

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't think it will; all the noise is already in the system below 4kHz. At 62500 you'd filter at 31250; filtering at 4k would definitely improve things then because you'd be dropping 12dB/octave so 36dB down or so.

But there's still that trade-off: if you want high resolution (i.e. lots of bits) you can't have a high base frequency; if you want high frequency, you can't have many bits.

And you should *always* try and match the input and output sample rates; sample rate conversion is computationally *hard* except in integer ratios, and even then it's still intensive.

Neil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmm..

Didn't the OP just want to output a sine wave?

I noticed a comment about Class D amps operating in the MHz range...
While there are some that do, it seems the general concensus is that the ideal frequency is around 400 to 600 kHz ...
Any thing higher and switching losses and EMI become significant...

I will pickup a some of the PWM AVR's with the PLL soon ...
My goal is just sine wave output into a class D stage...
No sampling input... .

Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was quoting from a class-D amplifier chip - the repeat rate was switchable IIRC at 250k, 500k, and 1M.

That repeat rate is you input sampling rate, or a multiple thereof. If it's a multiple, then effectively you are outputing the same sample multiple times. The problems with aliasing occurs when these rates are *not* integer multiples, or when the repeat rate is too slow for the desired bandwidth or resolution.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Neil,

Simple question, as I haven't played with PWM and audio signals...

Would adding an R-2R ladder, (low cost), and generatng the sin wave using DDS improve the output spectrum over the audio frequency range mentioned above?

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think the goal is 'generate a clean sine wave' which I guess means less than .01% distortion or something like that. That means all the little stair steps need to get filtered off so they are a 1/10000th of the full scale sine wave. 1 part in 10,000 needs a good 14bit dac or a less good 16bit dac. Cant get there with 8 resistors in a ladder I dont think. Can get there theoretically with pwm with timer res in the 14bit range. That's what we're arguing about... whether the 'artifacts' will be audible. I'm also writing a test prog like Barnacle did... I'm trying to graph the lo pass output after the pwm.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bob,
Got it.

Thanks,

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As Bob says; get enough bits at high enough frequency and, well, he's your uncle :)

Treat the repeat rate of the PWM - not the clock rate - as the sample rate and build your filters against that specification. Generally, you need to filter at half the repeat rate, or a shade lower, with the best slope you can get. You need to have a response proportional to your input resolution - for 8 bits input, you need to be 48dB down at the sample; for 16 bits, 96dB.

But remember that you can only count as many clocks as there are between PWM repeats, and that restricts your dynamic range severely at the clock speeds that the AVR can use.

Neil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

barnacle wrote:
I don't think it will; all the noise is already in the system below 4kHz. At 62500 you'd filter at 31250; filtering at 4k would definitely improve things then because you'd be dropping 12dB/octave so 36dB down or so.

Ah ha! That's why my PWM filter simulation works good if i made low pass filter with cut off frequency around 2KHz.
Thanks Barn,
I got your point after reading your so-long essay. But no, it's not boring :lol: though.

KISS - Keep It Simple Stupid!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DocJC wrote:
Neil,

Simple question, as I haven't played with PWM and audio signals...

Would adding an R-2R ladder, (low cost), and generatng the sin wave using DDS improve the output spectrum over the audio frequency range mentioned above?

JC

Pin count is the problem. I need 2 channel with each 16 bit accuracy. That would need 32 bit. So I chose PWM.
....
Later on, after struggling with PWM. and the need to increase the capability to support MP3... I've decided to add VS1053 (from VLSI). The good news is, VS1053 also supports Ogg Vorbis/MP3/AAC/WMA/MIDI/WAV(PCM IMA ADPCM). This sounds to wow, but hey, 16 euro (about 24$) for a complete system.

KISS - Keep It Simple Stupid!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

found this
http://www.dspdesignline.com/sho...

PWM Output
Another popular type of modulation is pulse-width modulation (PWM). In PWM, it is the duty cycle, not voltage level, that codes a signal's amplitude. An advantage of PWM is that PWM signals can drive an output circuit directly without any need for a DAC. This is especially useful when a low-cost solution is required. PWM signals can be generated with general-purpose I/O pins, or they can be driven directly by specialized PWM timers, available on many processors.
To achieve decent quality, the PWM carrier frequency should be at least 12 times the bandwidth of the signal, and the resolution of the timer (i.e. granularity of the duty cycle) should be at least 16 bits. Because of the high carrier frequency requirement, traditional PWM audio circuits were used only for low-bandwidth audio such as audio sent to a subwoofer. However, with today's high-speed processors, it's possible to carry higher bandwidth audio.

Before the PWM stream is output, it must be low-pass-filtered to remove the high-frequency carrier. This is usually done in the amplifier circuit that drives the speaker. A class of amplifiers, called Class D, has been used successfully in such a configuration. When amplification is not required a low-pass filter is sufficient as the output stage. In some low-cost applications, where sound quality is not as important, the PWM streams can connect directly to a speaker. In such a system, the mechanical inertia of the speaker's cone acts as a low-pass filter to remove the carrier frequency.
=============================================
They talk about a PWM freq 12 times the audio freq.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bob, 12 times audio frequency means 12 x 20KHz right? That is 240KHz - 4.166 us per PWM cycle. If i use 16 bit timer then it must be very high frequency clock for the timer itself. :)

KISS - Keep It Simple Stupid!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The PWM series of AVR's have a PLL to up the PWM base frequency... AT90PWMx

I think they can do 64MHz max...

Using 8 bit res. (half what u want) then the resulting base freq. would be...

64 MHz / 256 = 250 kHz ...

So it's possible at 8 bit but not so easy at 16bit...

If you just want high resolution sine generation ..
Then you could try the AD9833 DDS, I posted an SPI driver for it in the projects section...

What's the reason you want 16 bit and what wave shape you want?

Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also, there are some at-tiny models that also have the "High Speed" PWM...

Maybe ATtiny 26, not sure tho...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Like any digital to analogue conversion, you can trade sampling rate for better filters. The reason for 12 times the sample rate is to simplify the analogue filters on the output.

Worst case: sample rate = repeat rate, because you need good filters to kill the aliasing.

To calculate the bit-budget, which is of course your master clock frequency, you need only two things: the repeat rate(RR), and the signal resolution in bits(B).

Fclock = RR * 2^B

So for 16 bit 44.1k sample rate, you need 44100 * 2^16 = 2,890,137,600Hz which is probably a bit beyond even the most enthusiastic of the AVRs to deliver...

At 8 bit 44.1k, we get 44100 * 2^8 which is 11,289,600Hz, a much more manageable number if a little tricky to generate - though I suspect that may be crystals around at that frequency. Restrict yourself to 32k sampling and you come up with 8,192,000Hz as the master clock.

The point to remember though is the difference between filtering artifacts caused by the sampling rate and those present on the signal itself... if your sample rate is not a sub-multiple (including 1) of the repeat rate, you *will* have aliasing artifacts in the audio band which *cannot* be filtered; otherwise you just have the normal sampling aliases which can be filtered if your filter is good enough.

Even with the 'high speed' AVRs with the phase locked loops, you still want your master clock crystal to be a multiple of your sample rate.

Neil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

krazatchu wrote:
What's the reason you want 16 bit and what wave shape you want?

I just want to deliver the best. The basic idea is just to play a music from sampled audio before. 8 bit versus 16 bit? I heard 8 bit sound is a little bit crappy though some person didn't notice it. So I've tested with few sound samples and right, there were a lot aural difference that I could notice and I hate it. So I insist to had 16 bit PWM resolution. Any way, I've changed my strategy quickly, Plan B as usual, I've added VS1053 in my design so I don't have to worry about signal reproducing again :D

KISS - Keep It Simple Stupid!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Plan B is often the best option...