Roman Black - 16th Jun 2011, updated 26th June 2011.

This is a very simple circuit where the PIC and an internal 1kHz sinewave table do all the hard work of making an accurate sinewave. Then it needs only a few external parts for filtering.

The sinewave has a very high frequency accuracy as it is generated from a xtal. And with appropriate filter parts the sinewave is quite low in distortion. This makes the device useful for calibration testing and any use where you need a

The PIC runs from a 20MHz xtal. The PIC generates one PWM cycle for exactly 100 instructions, ie every 20uS.

The sinewave is generated by a 50 entry sinewave table for the complete sine period of 50 * 20uS (1000uS).

The sine table was created in Excel spreadsheet and makes a sine ranging from PWM 14 to PWM 86, a total PWM amplitude of 73% which is accurately distributed around the mid voltage point of 50% PWM. The sinewave was deliberately made at this amplitude to get the best performance out of the PWM system.

The sinewave has some tiny error in each sample, but every sample has been rounded up or down to the closest PWM value to a perfect sine. The max error for any sample is less than 0.68% of the sine amplitude. Hopefully this will not matter in the final operation as the important thing is the overall shape of the sinewave, because all the tiny PWM errors will be easily integrated out by the hardware filter.

A PIC 16F628 was set up with nothing more than a 5v regulator and 20MHz xtal (and a few PSU caps etc). A trimmer cap was used to trim the 20MHz xtal to better than 1 PPM against my GPS tuned frequency meter. This means the 1kHz output will be 1000.000Hz (+/-0.001Hz).

The PWM output from PIC pin RB3 was filtered through a 1k trimpot and 0.22uF cap. The trimpot was adjusted to about 800 ohms, and the output of the filter is shown below on the scope;

The sine wave is about 3v amplitude peak to peak. You can see the 50kHz PWM frequency as the fine sawtooth "hash". But importantly, the overall shape of the sine looks quite good and the tiny differences in each of the sine table enries look to have already been smoothed out.

Checking some online "low-pass filter calculators" showed that inductor values would be quite large and these inductors might not be very accessible for a simple hobby style build. So I fiddled with some RC values in an attempt to get a good 2v p/p sinewave.

I tried to keep the first stage impedance low, but 330 ohms to 0.33uF was about as low as I could go without causing some distortion from drawing too much current from the PIC output pin. Then the other 2 stages tried to keep total impedance low by keeping the resistor values low, and used just enough capacitance to get rid of the 50kHz PWM hash while hopefully having very little effect on the sine shape or amplitude.

Above shows the waveforms at points A (2.4v p/p) and B (2.2v p/p).

And here are the waveforms comparing point B with

Unfortunately I don't have a distortion meter to measure just how good the output sine wave is made by such a simple filter. But when I adjusted the amplitudes on the 'scope to be the same, the 3 sine waveforms appear to be exactly the same shape as each other, which is a good sign (good sine? haha).

I don't have many inductors in the mH size range apart from some cheap miniatures that are a bit nasty. However I did find some decent sized 1.15mH toroids in my old stock. I added 2 in series (to make a 2.3mH inductor) in the first filter stage.

This reduced the 50kHz hash at point A by about 60% compared to the same filter without the inductor. Which was quite nice and better still had practically no visible effect on the sine wave shape. I did notice all the amplitudes went up a couple of percent I assume this is because the currents out of the PIC pin are reduced due to the inductor so the PIC output pin FETs are able to produce a few percent more average voltage. As I saw previously reducing the current loading on the PIC output improved the sine shape so this is a good thing.

Above are the waveforms at points A and B. The 50kHz hash is greatly reduced. I have normalised the amplitudes on the 'scope to compare the waves. There is almost no hash visible at point B.

Above shows point B again and the final output at point C. Amplitudes have been normalised again. The final output must be REALLY free of hash now.

Above shows point A compared to the final output point C. Since all 3 of these waves have exactly the same shape I am guessing the sine distortion is pretty low. :)

Being happy with the performance of the sine generator (it has better freq accuracy and sine distortion than my commercial sine generators) I decided to add a little complexity like a calibrate switch and dual-colour LED to show if it is in SINE or CAL modes;

The two black square devices on the left are 1.15mH SMPS toroids left over stocks from years ago. Together in series they make 2.3mH. The filter is 3 stages, values as shown in the diagram above but I added a trimpot in the last stage to trim the 2v p/p output voltage.

A dual-colour RED/GREEN LED was used to add a nice touch, and is driven automatically by two PIC pins. A DPDT push on/off switch was glued in place with 2 support blocks and hot melt glue in "Borg Hive" style. The switch selects SINE or CAL mode and in CAL mode it disconnects the filter and connects a 1MHz output from the PIC to the device output.

The finished device. I added an engraved front plate. You can get these made for a few dollars at any "trophy engraving" shop. :)

Here is the full schematic. The DPDT switch pulls RB0 low in CAL mode, this tells the PIC to output a 1MHz squarewave instead of the sine. At the same time the DPDT switch disconnects the sine filter.

If you just want to throw together a 1kHz sine generator and don't need the extra 1MHz calibration switch and LEDs etc, this is the simplest setup that will just make the sinewave;

With nothing connected to PIC pin RB0 the software always defaults to sine mode, so this simple version

The filter has been reduced to 2 stages for simplicity and common parts, the values shown will remove all the 50kHz hash and give a very nice quality sinewave output at about 1.5v p/p.

If you just use a 20MHz xtal and two 22pF caps, xtal frequency will be within about 50 PPM accuracy, so the sine freq will be 1000.00Hz +/-0.05Hz. If you use a trimmer cap you can trim the xtal to a higher accuracy using a frequency meter. Remember if you gound PIC pin RB0 the PIC will output 1MHz from pin RB3 to allow calibration (you have to measure at RB3 as the 1MHz will not get through the filter!).

Thanks to the expert help from some of the regulars at the

My first sine table was generated with some effort to make all 50 entries properly rounded and to ensure the top and bottom half of the sine were symmetrical.

However the PWM created by the PIC is "left-aligned, trailing edge" which is a very standard PWM but this causes a 2nd harmonic distortion. The distortion is caused because the PWM always has the HI period before the LO period, and the left edge is fixed. So the average voltage of each PWM pulse is fractionally shifted in time compared to the original sine.

The result is that even though the original sine table had matching top and bottom halves, after the PWM output and filtering the top and bottom analog halves no longer match perfectly.

Suggestions were provided by TheElectrician and MrAl of using a centre-aligned PWM or somehow inverting the second half of the PWM table and using PWM that is right-edge aligned. Unfortunately the PIC PWM module cannot do these things and it would require manually generated PWM in code.

Above is a simulation (provided by

I read some research papers on PWM being used to reproduce high-fidelity audio waveforms and learned that the sine table could be generated by "natural sampling" instead of the "regular sampling" that I used.

Above you can see that for the same 2 areas of the sinewave a different PWM width is generated due to natural sampling of the original waveform (blue sine) against a linear (purple) ramp.

My original sine table in Excel was very easy, it just used the sine table value as the PWM value.

This "natural sampled" compensated table was more difficult as each PWM value had to be interpolated at some point between every two sine samples and the interpolation point is determined by the interpolation point.

I quickly realised that because of the low table resolution (1% amplitude steps) I could use a math short cut and still get a result much more accurate than the integer rounding so it would be "good enough".

The interpolation between any 2 samples was determined by the average % height of those 2 samples. This gave the "average" ramp value to an accuracy good enough to determine the ramp intersect.

A = A + (((A+B)/2)/100) * (B-A))

A = 71 + (0.73) * (4)

A = 71 + 2.92

A = 73.92

A = 74 (after integer rounding up)

Above you can see the new 50 entry "compensated" sine table I generated in Excel.

There are actually TWO sines there, the BLUE one made by the circuit is underneath a perfect RED reference sine. As you can see it is a very good match!

My RLC filter values were chosen for one real design goal, to get 2v peak to peak output amplitude and still remove the 50kHz PWM hash. And it was tight, there is not a lot of filtering squeezed in there considering there are 3 filter stages!

Almost any change to this filter that is an

I will leave my original filter values as "standard" for this project because they meet the design goal of simplicity and are easily available to hobbyists. And because they were modelled in the calculations and simulatons shown above.

Regarding using the 3 stage filter without the inductor (just with RC);

I used the 1kHz sine to test some caps. Because the sine has excellent frequency and low distortion it can be used to measure capacitance by putting one cap and one resistor in series and solving by Xc (capacitive reactance).

Two matching Fluke multimeters were used to measure AC millivolts, and the 2 meters matched each other in back to back testing exactly to the millivolt.

I adjusted the variable resistor until the cap and the resistor had matching AC volts. The 2 meters were left in place so their capacitance and resistance was matched. Swapping the two meters gave identical results.

Above you can see the 0.22uF cap under test, both meters reading 393mV.

Then the sine generator was unclipped and the meter measured the value of the variable resistor. I checked both meters measuring the one resistor and both measured the same! Good old Fluke meters. :)

C(uF) = 1000000 / (2pi * f * Xc)

C = 1000000 / (2pi * 1000 * Xc)

C = 1000000 / (6283.18 * 721)

C = 1000000 / 4530172.7

C = 0.2207 uF

I also tested a 0.056uF cap and a 1000pF cap, resistances were 3.002k and 163.2k. Now I have 3 caps measured to a decent accuracy I can calibrate my capacitance meter, and maybe build a new one. :)

Well I know my sine freq is excellent as it was calibrated against my GPS tuned freq meter. I assume my two Fluke meters measure ohms correctly as they match each other to the last digit. I know they match AC millivolts as they were tested by swapping. The main thing affecting accuracy is digit rounding.

Millivolt matching was within 1 digit, so within about 0.3% or so. Ohms likewise the last digit is about 0.2 or 0.3%. So capacitance accuracy is possibly around 0.6% or better. I feel pretty confident that these 3 capacitors can be called "1% capacitors" now.

- end -

[Back to Home Page]