[Back to Home Page]
1kHz precision sine generator using PIC
Using a 16F628 to generate an accurate 1kHz sine in software for calibration and test use
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 mathematically correct sinewave of a very precise
fixed 1kHz frequency.
How it works
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
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.
First hardware testing
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.
Simple RC filter test
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 the final
output at point C (2.0v p/p). Afterward I zoomed the 'scope right
in but can't detect any 50kHz freq in the final output.
Output impedance was tested by using a variable resistor to load the
output to half amplitude, the output impedance is 951 ohms.
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).
Improved filter by adding one inductor
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
Finishing it off
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.
Download the C source code and HEX file; Sine1kHz.zip 9kb
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 uses the same PIC software (see above).
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!).
Accuracy... And accuracy improvements!
Thanks to the expert help from some of the regulars at the Electro-tech online forum
(MrAl, TheElectrician, EricGibbs)
an early problem with the sine distortion was found and eliminated, see below.
New! 16th July 2011. I've been asked to take part in a pilot program on the
Electro-tech forum where some of my projects are linked to a thread
where you can;
2nd harmonic distortion!
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
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.
TheElectrician did a fourier analysis of the
original PWM pattern and diagnosed an error of 3% THD, of 2nd harmonic
distortion. My 3stage filter would reduce this to an estimated 1.5% THD.
He tested this with a hardware function generator and hardware THD
meter and got a real world result of 1.6% THD (almost all 2nd harmonic).
MrAl did a comprehensive math analysis of my original PWM values into
my exact RLC filter values and came up with a final THD after filter of
1.2% (almost all 2nd harmonic).
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 TheElectrician) showing what 2% error of
2nd harmonic distortion looks like. As my original sine generator would have
had 1.2% THD this small error was just not visible to me on the 'scope!
Fixing the 2nd harmonic error
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.
Natural sampling is a common method that occurs in some hardware PWM
encoders and sets the PWM width by the point where it matches a linear rising ramp;
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.
How to do the "natural sampling" in Excel
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
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.
Example in sine table of 2 consecutive entries; A71% B75%
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)
No more 2nd harmonic distortion!
Above you can see the new 50 entry "compensated" sine table I generated in Excel.
MrAl did a math analysis of the above table
entries and (after my 3 stage filter) the result came out as total
THD of 0.08% with practically zero 2nd harmonic distortion. This was a
huge improvement on my original table that gave 1.2% THD!
NOTE!! The PIC source code and hexfile (above) now uses the compensated
sine table for greatest accuracy.
Proof of natural sampled PWM from the simulator
EricGibbs used a circuit simulator software
to model the 50 step PWM using the "natural sampled" method, (although he used
a reference sine to generate the PWM and not my sine table). He did still output
through my chosen RLC filter values (click image below);
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
Improving the filter!
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 increase of filtering
results in a better sine and reduced THD. However it also results in
reduced amplitude and/or reduced output power. For my use, the whole device
already has superb frequency and phase accuracy and good overall sine accuracy
(at 0.08% THD) so there was no need to go better.
MrAL suggested using a much larger inductor, a
23mH instead of my suggested 2.3mH (this may be hard to obtain or
more expensive). TheElectrician suggested an inductor as large as 82mH,
and that the filtering would be improved by using increased impedance in
the later filter stages (which would result in reduced output drive).
Other people suggested increased filtering with larger caps and/or resistors,
or the possible use of active filters or output amps.
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
But if you are after a really low distortion sine then you should consider
using a more aggressive passive filter and/or an opamp to boost the sinewave output, or
using an active (opamp) filter. A Google search will return many
"1kHz low pass filter" schematics and filter design calculators so I will
not spend much time discussing them here.
Update 27th June 2011;
Regarding using the 3 stage filter without the inductor (just with RC);
TheElectrician said; "The attenuation at 50 kHz for the
filter with the 82 mH inductor is 78 times greater than the 3 stage filter
without any inductor." MrAl said; "I thought that you might also like to know
that your original filter with the inductor means a filtered THD of 0.085 percent,
but with the inductor shorted out the THD only rises to 0.096 percent, so that's
just a little less than one tenth of one percent without the inductor.
You may want to mention that for people who dont want to worry about finding an inductor."
TheElectrician said;"I added an 82 mH inductor and checked to see if the
non-linearity of the inductor added significant distortion. The inductor (the one
I used, anyway) added some detectable 2nd and 3rd harmonic distortion as seen at
the distortion analyzer residual output with a low distortion sine wave of 1 kHz
applied to the input of the filter. The two additional harmonics amounted to
about .1%. So, even with an inductor adding some distortion, it should be
possible to get well under 1% THD with a sine table that doesn't introduce 2nd harmonic."
MrAl said; "I have to wonder if the non linearity of the inductor might
actually introduce more distortion in real life than it takes away in theory.
This really should be looked into because it's a big waste if it doesnt help
or actually makes it worse, and we can not do that kind of analysis in theory
because we dont know the characteristics of the inductor."
My summary; It seems the inductor is very effective at reducing the 50kHz PWM
hash, although this is largely gone by the end of the 3stage RC filter anyway.
There does seem to be a possibility that the inductor may introduce its own
distortion to the sine, especially large mH inductors that are small in size.
If in doubt, especially if you have no test equipment to measure THD it may be
best just to leave the inductor out.
Testing capacitance using 1kHz sinewave
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
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. :)
In this test the resistor measured 721 ohms, so the calc goes;
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
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]