Showing posts with label DDS. Show all posts
Showing posts with label DDS. Show all posts

Friday, March 31, 2017

A (somewhat convoluted) means of locking a "binary" (2^n Hz) frequency to a 10 MHz reference

DDS (Direct Digital Synthesis) chips are common these days with small boards containing an Analog Devices AD9850 board being available on EvilBay for a cost lower than one is likely able to buy the chip by itself!  While these boards are quite neat, they do have a problem (or quirk) in that you are not likely to be able to generate the exact frequency that you want - at least if it is to be an exact integer of Hz.

Let us take as an example one of those ADS9850 DDS boards available on EvilBay.  These come equipped with a 125 MHz crystal oscillator that will likely be within 10-20 ppm or so, but let us assume that it is exactly 125 MHz.

Other than the 125 MHz clock and some output filtering, the AD9850 DDS chip has nearly everything else that one would need to generate an output from DC to around 60 MHz - the precise limit depending on filtering - and its frequency is set using a 32 bit "tuning word".  The combination of the 125 MHz clock and the 32 bit tuning word means that our frequency resolution is:
  • 125,000,000 / (232) = 125,000,000 / 4,294,967,296 = 0.02910383045673370361328125... Hz per step - approximately.
For most purposes around 1/34th of a Hz resolution would seem to be good enough - and it probably is - but what if you wanted to be able to generate frequencies that were exact multiples of 1 Hz steps for frequency comparison purposes or to be able to generate precise, standard frequencies like 1, 5, 10 MHz, etc. - or even a very precise 1 kHz tone?

The quick answer to this is to pick a clock frequency that is an exact "power of two" Hz, and the closest 2n multiple to 125 MHz is 227 or 134.217728... MHz - slightly beyond the ratings of the AD9850, but it is likely to work.  (Depending on the high frequency requirements, half of this frequency - 226 Hz, or 65.108864 MHz might be used instead:  Other frequencies that are 2n divided by an integer such as 2n/10 are usable, too as an example.)

What does this change in clock frequency gain for us, then?
  • 227 / 232 = 0.03125 Hz per step, which is exactly 1/32nd Hz.
In this way, very precise frequencies that are a multiple of 1 Hz (and a half-Hertz as well) could be produced.

(Where does one get a 134.217728 or 65.108864 MHz oscillator?  This would likely require a custom-made crystal/oscillator or it could be produced using another synthesizer such as an SI5351A that, itself, uses a VCXO as its reference.)
Locking the DDS synthesizer to a 10 MHz frequency reference

It would make sense that if you actually needed to be able to set your frequency to exact 1 Hz multiples that you would also need to precisely control the reference frequency as well - likely with a 10 MHz precise reference from a GPS Disciplined Oscillator (GPSDO), a Rubium frequency reference or something similar.  Unfortunately, 227Hz is an awkward number that doesn't easily relate to a 10 MHz reference.

The most obvious way to do this is to use a second DDS generator board (they are cheap enough!) clocked from the same 227Hz source with its output to exactly 10 MHz using a frequency word of 320,000,000d, comparing it to the local standard and applying frequency corrections to (e.g. shift slightly) the actual frequency of the "227Hz" oscillator.

There is a less-obvious way to do this as well, so here is an example using 224 Hz - which is 16.777216 MHz:

For the 10 MHz chain:
  • Take the 10 MHz output and divide it by 625 to yield 16.000 kHz
  • Multiply the 16.000 kHz by 32 to yield 512.000 kHz
  • Divide 512 kHz by 125 to yield 4096 Hz
For the  2n Hz chain:
  • Divide any 2n Hz frequency down to 4096 Hz as a basis of comparison.  For 224 Hz we would divide-by 4096 using a binary divider.
(Depending on one's requirements, the precise method could vary with other frequency combinations possible.  The frequency of 512kHz was used because it was well within the operational range of good, old-fashioned 4000 series CMOS circuitry.)

Why would anyone use this second method?  Back in the 1980s I built a DDS synthesizer that used a 224 Hz reference (16.777216 MHz) that used a 24-bit tuning word to provide precise 1 Hz steps, but I also needed to lock that same synthesizer to a high-quality 10 MHz TCXO.  While it would have been possible to have built another synthesizer, a 1980s solution to this problem meant that an entire synthesizer circuit (or most of it, anyway) consisting of more than a dozen chips - some of them rather expensive - would have have to be replicated to do this one thing.

This seemingly convoluted solution required required only 6 inexpensive chips - a combination of 74HC (or LS-TTL) and some 4000 series CMOS devices.  For example:
  • Dividing the 10 MHz reference by 625:  A 74HC40103 wired as a divide-by-125 followed by a 4017 counter wired as a divide-by-5 to yield 16 kHz.
  • The multiplication of 16 kHz by 32 to 512 kHz:  A 4046 PLL and a 4040 counter wired as a divide-by-32 to form a synthesizer.
  • Division of 512 kHz to 4096 Hz:  Another 40103 wired as a divide-by-125.
  • Division of 16.777216 MHz down to 4096 Hz:  A 74HC4040 counter dividing by 4096.
The final step to lock the two frequency sources together was to use the venerable 4046 phase detector, outputting the correction voltage to the 16.777216 MHz oscillator.

A comment about using the 4046 PLL chip:

It's worth noting that because the 4096 Hz output from the divide-by-125 from the 512kHz source is a pulse rather than a square wave so it is not possible to use the "XOR" phase detector (Phase detector 1) of the 40406, but rather the flip-flip detector (Phase detector 2).  The "problem" with the flip-flop detector is that when the two frequencies are close, instead of having a constant train of pulses being output that are either at the reference frequency or twice the reference frequency, one will get occasional, brief pulses as the output of one of the flip-flops occasionally drops out of its high-impedance mode.

The problem with is that these occur (more or less) randomly and comparatively rarely, meaning that they they are at a rather low frequency and can get through the loop filter, causing extra jitter on the locked frequency - the 16.777216 MHz oscillator in this case.  The "fix" for this is to slightly bias the output of the phase comparator toward V+ or ground with a high-value resistor (100k-4.7 Meg, depending on the application) which will "pull" the output constantly toward one rail, forcing the loop to be corrected constantly meaning that instead of the occasional, narrow pulse, there will always be a string of pulses at a "high-ish" frequency that can be removed by the loop filter.  With the rather low "loop gain" of this VXCO configuration, "jitter" caused by the multiplication synthesis and divisions really doesn't show up in the 224 Hz crystal oscillator being locked.

Even though the 4046 CMOS with its built-in oscillator and phase/frequency detector is a bit "jittery", remember that this is being applied with a slow loop filter to a VCXO circuit with very low overall loop gain so this jitter averages out nicely.

(There are a number of modern phase/frequency detector chips that do not have this "jitter" problem.)
With the main 16.777216 MHz reference being a VCXO (Voltage-Controlled Crystal Oscillator) the above scheme worked very well, locking to the 10 MHz reference in a second or two.  Back in the 1980s the most accurate frequency reference that I had was a collection of OCXOs (Oven-Controlled Crystal Oscillators) and TCXOs (Temperature-Controlled Crystal Oscillators) with the 10 MHz units being easily referenced to the off-air signal from WWV to provide both an accuracy and stability of around one part in 107 or better.  Because, in our example, we are starting out at a much higher frequency (e.g. 134-ish MHz) we might divide this down to 4096 Hz - or whatever frequency our implementation required - using a combination of 74F or 74Axx logic and a (74HC)4040 counter.

(If our 134-ish MHz clock were produced using an SI5351A synthesizer, the PLL corrections in this scheme would be applied to its clock, which typically operates at around 27 MHz.)

Nowadays, with GPSDOs and second-hand rubidium references being affordable, the accuracy and stability can be improved by several orders of magnitude beyond that of the TCXO that I used those many years ago.

Having said all of this the question must be asked:  Is any of this still useful?

You never know!


[End]

This page stolen from ka7oei.blogspot.com
 

Wednesday, December 30, 2015

Adding FM transmit to the mcHF transceiver

In previous postings I wrote about how FM reception - including squelch and subaudible tone detection - was accomplished on the mcHF.  As is often the case, it is usually more difficult to receive a signal than to generate one and this is arguably the case with FM as well.

In writing the code to generate FM I found the above to be true:  It was comparatively trivial to produce an FM signal, particularly applying "tricks" that I'd already done in the demodulation.

Producing the FM carrier:

One of the features that I added to the mcHF many code releases back was that of "Frequency Translation" in which the local oscillator was "off-tuned" from the receive frequency, + or - 6 kHz for the mcHF with the "baseband" signals for receive and transmit being shifted by 6 kHz (in the opposite direction) in software.

One reason that this was done was to improve the performance of the transceiver by removing its receive and transmit passbands from the immediate vicinity of the "zero Hertz hole" which not only improves frequency response, but it reduces other issues related to thinks like "1/F" noise and, perhaps most importantly, greatly reduces the likelihood that other receiver audio (e.g. audio amplifier energy) will find its way back into the microvolt-level audio paths via power supply and ground loops and cause feedback!

Applying this to transmit, we soon realize that if wished to produce a signal with a constant carrier, such as AM or FM, we would have to remove ourselves from this "zero Hertz hole" as it would be, by definition, impossible to produce a carrier in that hole as a the carrier is, in fact, represented by DC.  (For SSB, which purposely has its carrier removed, this "hole" is nearly irrelevant...)

This explains another reason why this feature was added:  The eventual addition of AM transmission (and reception) several revisions ago, but this same feature used once again for FM, but in a different way:  Via the use of DDS (Direct Digital Synthesis) techniques.

The use of DDS techniques has been discussed on this blog before - see the article "Generating low-distortion audio sine waves using a PIC and DDS techniques." - link.

Using DDS techniques to generate an FM carrier:

In this technique one generates a sine wave (or any other arbitrary signal, for that matter) by jumping through a "lookup table".  In the case of the mcHF, with its 48 kHz sample rate, if we wanted to generate a 6 kHz sine wave this implies that we would need to step through this sine wave table once every 8 samples.  This sounds easy enough - but how would one do this?

Take a look at this bit of code:

loop:
   accumulator = accumulator + frequency_word
   table_index = accumulator > (size of accumulator in bits - size of table index in bits)
   amplitude = sine_table[table_index]

To explain the above:

- The variables "accumulator" and "frequency_word" are both integers.  Let us presume 16 bits, unsigned, each, which means that each value would range from 0-65535.  Incremented past 65535, it would return to zero.
- "sine table" is a lookup table containing values mapped to a sine wave.  Let us presume that our sine table contains 1024 entries - a number that may be represented by precisely 10 bits.
- "table_index" is used to index the table.  It must be able to index all of the sine table (10 bits) so we will use a 16 bit value for this.
- "amplitude" is the result from the sine table.  This could be an integer or floating point value - whatever format your system ultimately requires.

To calculate the value of "table index" we need to take the top 10 bits of the "accumulator", which means that we can obtain by taking the accumulator value and shifting it to the right by 6 bits (e.g. size of accumulator in bits, minus the size of table index in bits, which are 16 and 10, respectively.)  By doing this we can see that as the value of "accumulator" increases, it also points farther along the sine table.  When the value of accumulator "rolls over" back to zero, the pointer into the sine table also resets back to the beginning.

To understand how the frequency is generated, let us now assume that "frequency word" is set to 1.  We can see that every 65536 times through the loop we will "roll" through an entire sine wave, but since our sample rate is 48 kHz, we know that the produced frequency will be:

48000 / 65536 = 0.732 Hz (approx.)

If we want to generate an arbitrary frequency, we would take the above ratio and use it to calculate the "frequency word" as in:

desired frequency / (48000/65536)

or, rewriting a bit:

(desired frequency * 65536) / 48000

or, reducing the fraction even more:

(desired frequency * 512) / 375

If we wanted to generate a frequency of precisely 6 kHz, the above equation would yield a "frequency word" value of 8192 - which just happens to be exactly 1/8th of 65536, which makes sense since we have already figured out that since 6 kHz is 1/8th of our sample rate of 48 kHz, it would therefore take 8 samples to produce such a sine wave!

Modulating our carrier:

We now know how to generate a carrier, but how to modulate it?

We know that FM is simply "Frequency Modulation", and we also know that by varying the value of "frequency_word" above, we can change the frequency, does this mean that if we superimpose audio on our value of "frequency_word" that we can modulate our signal?

Yes, it does.

Let us rewrite the above code a bit:

loop:
   accumulator = accumulator + frequency_word + audio[audio_index++]
   table_index = accumulator > (size of accumulator in bits - size of table index in bits)
   amplitude_I = sine_table[table_index]
   table_index = table_index + 256
   if(table_index >= 1024)
      table_index = table_index - 1024
   amplitude_Q = sine_table[table_index]

(Let us assume that "audio_index" is updated each time through the loop and represents one sample of the audio, also sampled at 48 kHz, to be modulated onto the carrier.)

Let us first take a look at the first line after the start of the loop where we added the term "audio".  Because our audio is already represented digitally as a numerical value that goes above zero for a positive voltage and below zero for a negative voltage, it would make sense that we could simply add this to our "frequency_word" value.

In other words (pun intended!) when the audio voltage increased above zero, our frequency would increase, but as it went below zero, our frequency would decrease - just as FM would.  What's more, because this is an exact numerical representation, our frequency change would be proportional to the audio applied - which is just want we want to occur for low-distortion, faithful representations of our audio.

Figure 1:
A demonstration of a typical FM signal modulated with a tone as
displayed on the mcHF's waterfall display.
(This picture doesn't have much to do with transmitting, but
I wanted to include some color in this posting!) 
There is another modification to the above code as well.  If you look, you will see that we do two look-ups in the "sine_table".  The first one is our original value, now called "amplitude_I" (In-phase) but we now see that we have taken our table index and added 256 to it which is precisely 1/4th the size of our sine table:  One quarter of a sine wave is, of course, represented by 90 degrees.  After "fixing" that value so that it is always lower than 1024, we look up into the sine table again and call this value "amplitude_Q".

What we have done here is generated two sine waves exactly 90 degrees apart from the same frequency synthesis operation.  As you will recall from your understanding of the "phasing" required to generate an SSB signal, you need both an "I" and "Q" signal for transmit and unlike the generation of quadrature audio for SSB which requires some fairly "hairy" math, we have handily done this for FM with almost no math at all!

Comment:  In reality one would employ modulus operators rather than "greater-than and subtract" or even logically "AND" the table index value with 1023 (decimal) after adding 256 to it, either being a much quicker operation for a computer than in the example shown above.

Additional audio processing:

As was mentioned in the discussion about the demodulator, for amateur radio purposes we don't actually want to transmit an "FM" signal, but really a "PM" (Phase Modulated) signal.  For our purposes, a PM signal is really an FM signal in which the audio is pre-emphasized at a rate of 6dB per octave - which is a fancy way of saying that a signal voltage that causes +/- 1 kHz of deviation with a modulation frequency of 1 kHz would cause +/- 2 kHz of deviation with a modulation frequency of 2 kHz.  As noted in previous postings, this is done to improve the overall signal-noise performance of the system as it boosts the "highs" in the audio at about the same rate as the noise increases on weak signals.

There are some practical issues with this pre-emphasis that must be considered.  If you were to start your pre-emphasis at 1 Hz, by the time you get to 2048 Hz would have pre-emphasized your audio by 66 dB or so (if I've done my math right) - a ridiculous amount, and any audio content that might be present at higher frequencies would be boosted even more!  Such high frequency content would also cause high amounts of deviation which, in turn, would greatly expand the occupied bandwidth of the transmitted signal - something that is neither necessary or neighborly!

Clearly, this implies that we must do two things:
  • Limit the frequency range over which we do our pre-emphasis
  • Filter the the audio to the desired range for speech communications
If we start our pre-emphasis at around 200 Hz, instead, we can see that by the time we get to 3200 Hz we need to boost only by 36 dB - a far more reasonable value than the 66 dB mentioned above!

For speech we need only reproduce audio from around 250 Hz to something in the area of 2500-2700 Hz.  Our low-frequency limit is imposed by our desire to include the encoding of "subaudible" tones on our transmitted signal and it is important that we remove a reasonable amount of energy in that frequency range so that spectral content of the human voice - particularly that of the adult male - does not encroach in that area and cause reliability problems with decoding on the receiving end.

Fortunately, such tools are already at hand!

Pre-emphasis:

We already met the differentiator algorithm in our receiver as it was used to reduce the low-frequency, subaudible tones from received audio.  This algorithm reproduced below.

loop:
  filtered = α * (old_input + input - old_filtered)
  old_filtered = filtered
  old_input = input

Where:
  "α" is the the equivalent of the time constant in that a "small" α implies an R/C circuit with a fast time-constant strongly affecting "low" frequencies.
  "input" is the new audio sample.
  "filtered" is the high-pass filtered (differentiated) audio

In the case of the receiver we used it as a high-pass filter with a cut-off below the speech range, but for transmit we can adjust the "knee" of this differentiator such that it is just above the speech range, instead.  As it turns out, an "α" value of 0.05 is suitable for our purposes.

Filtering:

Having done pre-emphasis, we still need to do filtering, but I'd already implemented a "transmit" filter on the mcHF for both SSB and AM and all I needed to do was redesign the filter to suit the FM audio characteristics.  I used MatLab and the filter designing plug in for this, but the "Iowa Hills" filter designer suite (free and easily found via a web search) could be used to produce suitable sets of coefficients.  As are most of the filters used on the mcHF, these filters were IIR since one can get a lot of "bang for the buck" in terms of good, "sharp" filtering with relatively few computation cycles.

With a fairly compact filter with fairly low computational overhead I was able to achieve >20dB of voice rejection in the upper frequencies used for subaudible tones and well over 50 dB of attenuation above 3200 Hz - much better than that achieved in a typical, analog FM transmitter.  At the low end, audio below 250 Hz was attenuated by at least 20dB with over 40 dB reduction for audio content below 200 Hz - this, to prevent "pollution" of the frequencies occupied by subaudible tones.

Comment:  Because I was using floating-point math, the order in which pre-emphasis or filtering is done is unimportant.  If fixed-point/integer math was used, instead, you would need to carefully analyze the signal path and the resulting values to assure that nothing "blew up" (e.g. exceeded the integer range or, at the other extreme, was so "small" that resolution was compromised and distortion/noise introduced) at the expected audio levels at all frequencies!

Limiting:

One necessary function employed in typical amateur FM transmitters is that of the limiter to "clip" the audio to an absolute maximum level.  This device improves overall intelligibility by allowing the designer to set the microphone gain to a somewhat excessive level, but the clipper forcing a maximum loudness.  The result of this is that somewhat low audio from soft-spoken users is boosted to promote intelligibility while those who have "hot" microphones and/or speak loudly do not cause excess amounts of deviation of the transmitted signal.

The mcHF does not have a clipper, per se, but it does have an audio compressor that was implemented many versions ago to improve usability on SSB.  Like a limiter, this device prevents the audio from exceeding an absolute maximum level and it also adjusts the gain upwards during quiet portions to reduce the "peak-to-average" ratio of the audio, thereby improving intelligibility.

I did experiment with both a "hard" and a "soft" limiter (or clipper) in software.  A "hard" limiter is one that sets an absolute ceiling on the amplitude of the signal present while a "soft" limiter, as the name implies, is less abrupt, more like the "knee" of a diode with some sort of logarithmic-like action.  Because they alter the waveforms, both of these methods generate harmonics and intermodulation products - the "soft" limiter being a bit less aggressive - which require that filtering be done.  Since we are low-pass filtering the audio, the higher-frequency harmonics outside the speech range will not contribute to the occupied bandwidth of the signal but the increased energy in the upper speech frequencies from harmonics of the lower-frequency audio components coupled with the pre-emphasis can somewhat broaden the signal.  Finally, because the signal is distorted by the clipping action, high audio levels that result in a lot of clipping are likely to result in audio that "sounds" degraded.

In comparing the sounds of the limiter/clipper to that of the audio compressor, I decided to use the latter as it was more "pleasing" to the ear and more versatile, overall since there are a number of available adjustments (e.g. the amount of audio into the variable gain stage and the decay rate of the variable gain stage.) As noted, I eventually decided not to use a clipper and used the already-existing compressor, instead.

Without either this compressor or a limiter, an FM transmitter would have the problem of their signal being "too wide" for loud-speaking operators and "too quiet" for those that were soft spoken - neither condition being desirable for communications!

Subaudible tone:

A desirable feature of a modern FM transmitter is that of the Subaudible Tone, discussed previously.  This signalling method consists of the generation of a low-level sine wave in the range of approximately 67 to 250 Hz that is superimposed on the transmitted audio which is used by the receiver to validate the presence of signal.  While this was traditionally used in commercial radio to allow several groups of users to "share" the same frequency, amateurs have typically used it as interference mitigation techniques to prevent the receiver - that of the repeater or the user - from responding to noise or signals for other sources.

For additional information about subaudible tone signalling, read the Wikipedia article - link.

Since it is just a sine wave, it is very easy to generate - and we already know how!

Re-using the DDS algorithm, above, we need only generate a single tone, unmodulated this time, and sum it with our transmitted audio.  We would of course, do this after we have done our pre-emphasis, filtering and limiting/compressing, placing this tone generator just before the DDS that produced our FM signal as the code snippet below illustrates.


[Filtering and limiting/clipping of audio already done]

if(tone_generator=TRUE) {
      tone_accumulator = accumulator + tone_frequency_word
      table_index = tone_accumulator > (size of tone accumulator in bits - size of table index in bits)
      tone = sine_table[table_index]
      audio = audio + (tone * amplitude)
}

[The code that follows is the DDS that generates the FM signal as shown above]

As we can see, only if the tone generator is turned on do we go through the loop - something that we'd do to save processing power.  Included in the above code snipped is an additional parameter, "amplitude" which would be used to scale the value from the sine lookup table such that it yielded the proper amount of deviation on the transmitted signal - typically in the area of 15-20% of peak deviation.

In the case of generating the audio tone we'd need to make certain that we had enough frequency resolution to accurately produce the tone, and as we already calculated we know that with a 16 bit counter at a 48 kHz sample rate our resolution is approximately 0.732 Hz. Assuming no sample rate errors, this would imply that we could generate the desired frequency to within half that resolution worst-case, or approximately 0.366 Hz.

This frequency resolution is adequate for generation of these tones, again assuming that there are no additional error sources related to sample rate, but if you were not satisfied with that amount of resolution it would be a fairly simple matter to increase the number of bits used by the accumulator and frequency word to improve the resolution, just as was suggested for the frequency modulation.

For the calculation of the frequency words, all that was required was that the code include a table containing the frequency, in Hertz, of each of the subaudible tones:  Since we already know the sample rate and the number of bits - and therefore the maximum counts for our accumulator - we can calculate, on the fly, the needed "frequency word".

Tone burst:

There is one more tone signalling scheme occasionally encountered on FM repeater systems, and that is the "tone burst", sometimes called "Whistle-up".  Although it has largely disappeared from use, it is reportedly used in some areas in Europe.

In this system a short burst of a specific tone, typically 1750 or 2135 Hz, is transmitted to "wake up" a repeater for use, and once this is done, it may be used normally.  Once the repeater has again become dormant, a timer expires and it will no longer respond to signals until it, again, receives a burst.

For a Wikipedia article that includes a section about single-tone signalling, look here:  link

This is generated in exactly the same way as a subaudible tone, namely with a bit of DDS code that looks just like the above!  From a purely practical standpoint, unless one absolutely needed to generate both a subaudible tone and a tone burst at the same time, one could actually use the same bit of code - provided that the amplitudes of the different tones (subaudible, burst) were taken into account.

Unlike a subaudible tone, a tone burst is typically transmitted only at the beginning of a transmission and for a fairly short period - perhaps one second.  While one could rely on the user to time the duration of the tone burst, on the mcHF the duration of the burst was timed by counting the number of interrupt cycles called to process the audio, making the process semi-automatic:  The user needed only activate push-to-talk and then press-and-hold the button that produced the tone and the rest would be completed automatically.

"DCS" codes:

Not mentioned previously there is one additional signalling scheme sometimes found on amateur frequencies, and that is "DCS" (Digital Coded Squelch) which consists of a binary signal with a base frequency of 134.4 Hz modulated with a specific bit pattern.  This signalling scheme is quite rare in the amateur radio community - and even rarer on HF (10 meter) repeaters where this radio is likely to be used - so there has been no serious consideration in its support


How well does it work?

Generating a sine wave with a low-distortion audio generator and feeding the modulated signal into a communications test set (a.k.a. "Service Monitor") - a device specially designed to analyze the quality of communications gear - the modulation was tested at several audio frequencies and found that the distortion was at approximately the level of detection of the instrument to at least +/- 5 kHz deviation.

Testing was also done using speech at various levels, including attempts to overdrive the audio input and on a spectrum analyzer the occupied bandwidth was observed to be contained within the expected bandwidth mask for both the "narrow" (+/- 2.5 kHz) and "wide" (+/- 5 kHz) deviation settings with no audible distortion present nor were there any unexpected spectral components outside the frequency range typical of such an FM signal - even though the "accumulator" of the frequency-modulating DDS is only 16 bits and the audio represented by it will have even lower resolution (e.g. on the order of 12 bits, maximum.)

At the present time I can't think of any additional features that would need to be added to the FM mode so it is, for now, "good to go."


[End]

This page stolen from "ka7oei.blogspot.com".

Monday, August 31, 2015

A PIC-based audio source for locking a VHF oscillator

Several years ago I decided to build a weather satellite receiver from scratch.  It is described here - link.

I didn't really need a weather satellite receiver, and I could have easily bought a kit somewhere else - or bought a second-hand one via EvilBay, but I just wanted to go through the exercise of throwing everything together and making it work using parts on hand - and I wanted to try out some ideas.

Locking a VCO to an audio DDS reference:
Figure 1:
The front panel of the VHF weather satellite receiver.
This receiver has been in continuous operation for several years, working
flawlessly in that time.
Click on the image for a larger version.

One of these ideas was to use a PIC to lock the VHF local oscillator.  On the face of it, this isn't unique - except that the PIC was to be the sole source of the precise frequency to which the PLL (Phase Locked Loop) for the local oscillator:  No divide-by-N chips here!

For this receiver the local oscillator operated 10.7 MHz below the receive frequency nominally at about 126 MHz.  Since I was already using a 100 MHz oscillator (a VCXO) that I'd pulled from some scrapped commercial satellite gear, I used a simple 3-transistor mixer/amplifier circuit to convert this to about 26 MHz (137 MHz-10.7 MHz-100 MHz) and this allowed me to use a 74HC4040 12-stage binary ripple counter to bring a representation of the local oscillator down to the audio range - about 6.3 kHz.

As it so-happened, I'd chosen the 100 MHz oscillator on purpose - mostly because it was free, but it also provided a nice, stable 20 MHz clock for the PIC by dividing its output by 5 using a 74F191 so both the down-conversion and the PIC's clock were referenced from the same source.

The goal was to provide a minimum tuning step size of at least 1 kHz, and because I'd already divided the local oscillator by 4096 this meant that my audio-frequency step size was on the order of 1/4 of one Hz - but that was no problem since I was going to use DDS techniques in the PIC.

The DDS:

A DDS (Direct Digital Synthesis - see the Wikipedia article about DDS techniques here - link) is fairly simple in operation:  Typically, one takes a register (called an "accumulator") and on every clock cycle you add to it a constant number (we'll call it a "frequency word") allowing it to "wrap around" once the accumulator's capacity is exceeded or, in other words, you do unsigned binary addition.

If you were to keep track of how often the accumulator overflows you'd notice that if you added a smaller number to it, it would overflow less often which makes sense since it would take more clock cycles to overflow!  What you might notice is that one can easily predict the rate at which it will overflow:

( (frequency word) / (maximum accumulator value) ) * clock frequency

Typically, the "maximum accumulator value" is the maximum number (plus one) that can be represented by the number of bits used by the accumulator (e.g. 8 bits = 256, 16 bits = 65536, 32 bits = 4294967296).

In my case, it was easy to make the PIC do 32 bit unsigned addition.

The last step is to take the upper-most bits of the accumulator and apply them to a D/A converter via a sine-wave lookup table.  To take a table that is "8 bits" in size (256 entries) one would take the top byte of our exemplar 32 bit accumulator, use those bits to point to a sine wave and then send the output of that sine wave lookup to the D/A converter.  Clearly, the more bits of lookup (e.g. the larger the sine wave table) and the more resolution that one has available for the D/A converter, the better!

Figure 2:
The PIC controller board that generates the precise audio frequency
based on a PIC16F88 and driven from a 20 MHz clock source.  This PIC
also drives the LCD and does the serial data communications,
receiving frequency tuning commands from the host computer.
Click on the image for a larger version.

Hardware:

The PIC that I used (a PIC16F88) can be clocked to 20 MHz and among other things it contains a PWM generator that can operate as a simple D/A (Digital-to-Analog) converter with as much as 10 bits of resolution.  As such, it has a 10-bit timer and with the PWM operating at (up to) 10 bits of resolution it will sample at up to 1/1024th of the clock frequency, or:

20 MHz / 1024 = 19.53125 kHz

Since we have 232 (4 billion+) counts in our 32 bit accumulator, and we clock it at as high as 19.53125 kHz, that means that our frequency resolution is about one four-billionth of 19.53125, or:

19.53125 kHz / (232) = 0.000004547 Hz - or about one five-millionths of one Hertz resolution!

There's one more step in generating a useful frequency output.  If one watches the MSB (most-significant bit) of the accumulator, we can see that it flips between 0 and 1 at the desired frequency, but we don't want a digital output:  Even if we did take the MSB which is, on average, at the desired frequency, it typically has a lot of phase jitter that makes it unsuitable for most frequency control purposes.

If, instead, as noted above, we take the top several bits of the accumulator and feed them to a lookup table that has a sine wave and then outputting that value to a D/A converter, we get a more analog-looking signal with much less phase jitter:  The more bits we have, the better job we can do in representing a sine wave.

Now, remember that we divided our mixed-down local oscillator by 4096, so this means that our effective resolution would be reduced by that much, but if you do the math, that still means that we have - when multiplied by 4096 - a step size of 0.0186 Hz or so at the VHF LO frequency!

If you've been following along, you might noticed that I skipped several steps, so let me explain:

The idea was to divide down a representation of the 126 MHz local oscillator to audio and we did this by first subtracting 100 MHz from it and then dividing-down the 26 MHz by 4096 to audio.  We would then generate a precise audio frequency at one-4096th of that 26 MHz frequency and using a PLL, lock our local oscillator to it!

Simple - almost.

The DDS technique is imperfect when implemented using hardware that doesn't have infinite resolution - and the PIC's hardware and software capabilities are rather limited - in my case, I managed to implement the equivalent of a 1 "ksample" sine wave with 10 bits of resolution.  (Actually, it was just 1/4th of a sine wave - which is enough if you flip the pieces upside-down and/or play it backwards in the right order as needed!)

So now I had a precision audio generator that could output a reasonable facsimile of a sine wave at any frequency from about 5 milliHertz (including DC, if you want to be pedantic) to something less than 1/2 of the sample rate - about 9 kHz!  The PWM output from the PIC is really a bunch of samples of a 19 kHz variable duty-cycle digital waveform and it needed to be filtered a bit so I ran it through a simple op-amp bandpass filter - and then converted it back into a square wave - before passing it on to the a 4046 chip and into the edge-triggered phase detector.  In the 4046 this was compared with the converted/divided signal from my local oscillator and with the magic of the PLL, my VHF oscillator was nicely locked to the precise audio frequency from the PIC!

Almost...

At this point, the imperfection of the DDS became apparent.

One of the satellite frequencies is 137.62 MHz with a local oscillator frequency of 26.92 MHz.  When this was divided by 4096, this yielded a frequency of 6.5723 kHz approximately.

If one takes a close look at the spectrum produced by any DDS-type synthesizer, a myriad of low-level (and some not-so-low-level) spurious signals will be generated because of rounding-off errors related to the finite resolution of the D/A converter, the size of the sine table, and the relationship between the desired frequency and the clock frequency.  As one approaches frequencies that are related to an integer sub-multiple of the higher order bits (e.g. multiples of 1/2, n/4, n/8, n/16, n/32, n/64, etc. of the clock frequency) these low-level spurs get closer and closer to those multiples mentioned above.  As these sub-multiples get "smaller", the amplitude of these spurious components decrease as well.

In the case of the 6.5723 kHz signal required to synthesize 137.62 MHz frequency, this was very close to 43/128ths of the clock frequency - or about 10.986 Hz off.  What this caused was a very low-level 11-ish Hz modulation of the generated frequency which, when effectively multiplied upwards by the 4096 division - which increased the apparent loop gain - appeared as a very obvious tone (more of a buzz, actually!) at the local oscillator frequency.

Normally, loop filtering would take care of this, but this rather low frequency (just 11 Hz!) could get through the filter too well - and further-slowing of the loop filter wasn't particularly attractive - but this is software and we can do sleight-of-hand to fix this!  What I did was to pick a slightly different clock frequency - 20 MHz / 896 = 22.32142857... kHz instead and this moved the spurious signals from the DDS far enough away that they were effectively removed by the loop filtering.

The end result was a VCO that would tune anywhere within the designed range in less than a second and have very low-level spurious signal content from the DDS!

Locking a VCXO to an audio DDS reference:

As it turns out, locking a VCO - essentially a free-running oscillator with an implied, wide tuning range - is a comparatively "worst-case" scenario when it comes to the minimization of things like "reference sidebands" - the frequency/phase modulation of the generated carrier from residual AC on the tuning line - owing to the very high loop gain involved which can arise from both the "tuning sensitivity" of the VCO itself and if high divisor ratios are used.  If one starts out with an oscillator with a comparatively narrow tuning range - such as a VCXO (Voltage Controlled Crystal Oscillator) - in which the tuning sensitivity can be orders of magnitude smaller - and the lock time may be longer, particularly if high divisor ratios are used since it may take some time for the phase fo the comparison signal to "slide" into alignment - it is much easier to keep those already low-level spurious signals down to levels that may be ignored in typical applications.

A practical implementation of this technique has been employed in the W7SP Synchronous/Voting repeater system operated by the Utah Amateur Radio Club (described here - link) in which the transmit frequency is referenced from 10 MHz OCXOs (Oven Controlled Crystal Oscillators) and held within 1-2 Hz of the intended frequency.  Using DDS techniques with 32 bit accumulators operating at approximately 3.2 kHz, the transmit frequency can be controlled - via the audio frequency - to a resolution of 0.0023 Hz at the two meter transmit frequency - an accuracy that far exceeds the accuracy and stability of the reference oscillators themselves!

Producing exact frequencies:

The difficulty with using DDS techniques arises when an exact frequency is desired, such as for a frequency standard - at least unless one is willing to crunch a few numbers and/or make a few compromises.  For example, since the typical DDS algorithm is based on binary counters and thus has denominators of 2n power, one will likely not end up with the precise frequency desired.  In our example, above, with a 32 bit counter, we can likely get the frequency to with a fraction of a Hertz, but not exactly where it should be.

There are several ways around this, including one or more of the following:
  • Extending the resolution of the binary counter used in the DDS with even more bits to get ridiculous resolution so that the resulting frequency is "good enough."  If enough processor time is available and 32 bits of resolution is not enough, 48 or even 64 bits of addition may be implemented to do unsigned math.
  • The careful selection of a clock frequency such that the divisors result in the exact frequency desired.  The difficulty here is that if it is an "exact" frequency that is desired, many reference frequencies - such as 10 MHz - are not "binary friendly", requiring a bit of clever math to come up with exact relationships with the target frequency.
  • Designing the DDS counter to use something other than a binary (2n) counter.  If, say, a 10 MHz clock is used, the software DDS may be implemented using counters that will roll over at 10n instead of 2n, driven by a hardware divisor set to a base-10 relatable value to yield exact frequencies.
  • Implementing "dithering" of the DDS count to achieve fractional tuning.  This involves switching between two or more frequencies at a specific rate to achieve a third, averaged frequency.

 The last method, dithering, must be used with care as it will, by its nature, introduce spectral components that are necessarily lower in frequency than that of the reference being generated by the DDS - possibly very much lower if the fraction being represented by the dithering is complex - and these lower frequencies can greatly complicate effective loop filtering!  In most cases it would be more beneficial to simply extend the resolution of the software DDS (e.g. more bits) rather than implement dithering making this technique most useful if one us using a hardware-based DDS.

Comment:
If one needed to provide exactly 1 Hz steps, a DDS reference frequency based on 2^n Hz would be appropriate.  For example, if you chose 2^24 Hz (16.777216 MHz) you can lock that (awkward) frequency to 10 MHz as follows using only a few chips:
  • Divide 10 MHz by 625 to obtain 16 kHz (using a 74HC103 as a divide-by-125 and a 4017 to further divide-by-five.)
  • Using a PLL, multiply 16 kHz by 32 to yield 512 kHz (the lowly 4046 and a 4040 binary counter work well for this.)
  • Divide 512 kHz by 125 to yield 4096 Hz (using another 74HC103 to divide by 125)
  • Divide the 16.777216 MHz DDS reference oscillator by 4096 using a binary counter to 4096 Hz for the frequency comparison (a 74HC4040 works well as the divider here.)
The above steps may be done many different ways to get different frequencies, but the above is one example as to how to tie the two disparate frequency references together.

Final thoughts:

While there are definite limitations in using a DDS reference to lock a high frequency oscillator, namely the need to suppress the inevitable reference sidebands that result from the DDS synthesis itself by filtering, careful selection of reference frequencies and/or choice of the type of oscillator, but appropriate application of these methods can produce a reliable, versatile - even simple - frequency source.

[End]

This page stolen from "ka7oei.blogspot.com".

Thursday, September 12, 2013

Generating low-distortion audio sine waves using a PIC and DDS techniques

Over the years I have collected a number of service monitors (see the postings about the IFR-1000 and Cushman CE-50A) but the one that I use most often is a rather strange bird, a Wavetek/Schlumberger 4031.

The problem is this:  Many amateur repeaters require subaudible tones for access, so when testing the receiver for things like SINAD, sensitivity, etc. it is necessary to generate both the subaudible tone and a standard 1 kHz tone - something impossible when you have exactly one tone generator, as is the case of my '4031 without this optional extra.
Figure 1:
The completed 1 kHz tone generator.
Click on the image for a larger version.

Fortunately, this "extra" tone generator need not do too much:  Simply generating a low distortion, 1 kHz sine wave will suffice!  After all, many service monitors have, as their "second" tone generator, one that generates only a 1 kHz tone!

The hardware:

I decided to throw a PIC at the problem, specifically the PIC12F683, an 8-pin processor that has quite a few useful features, most notably a hardware PWM generator and an A/D converter. I wanted this device to be quite small and battery-powered as it would be kept with the service monitor at all times.  Throwing a piece of paper on the workbench, I sketched out a circuit that quickly evolved into that depicted below in Figure 2.

The main power switch is Q1, a PNP transistor in series with the Batt+ lead and when SW, a momentary pushbutton switch, is pressed, Q1's base is pulled low through R2 causing it to conduct and provide power to the rest of the circuits.  Once the software in the PIC (U1) has determined that the button has been held down for a long enough time (>1 second) pin 7 is set high which activates Q2 which, in turn keeps Q1 turned on.  Diodes D1 and D2 provide isolation for the pushbutton so that the PIC can detect if the user is pressing the button independently of what Q2 is doing.

The PWM signal is output from pin 5 using the PIC's hardware, the DC is blocked with C8 and then low-pass filtered in two stages, first by R9/C9 and again by R10/C10 to both (mostly) remove the PWM's 20 kHz energy and also to somewhat attenuate higher-level harmonics of the 1 kHz tone itself.  R11 is used to establish an operating point for U2 and is derived from a mid-supply voltage source produced by R5 and R6 and filtered by C2 and ultimately used to bias both halves of U2 to a mid-supply voltage.

Figure 2:
Schematic of tone generator unit.  The only critical components are C10-C12 which should be
temperature-stable (plastic) units rather than ceramic.
NOTE:  There is an error in the schematic:  The anode of D1 should have been shown connecting
to the collector of Q2!  (I'll get around to fixing it some day...)
Click on the image for a larger version.
U2, a TS462, is a "rail-to-rail" op amp, this type being chosen to maximize the output signal level available from the limited supply voltage, particularly when the 9 volt battery is nearing the end of its useful life (approx. 7 volts for this application) and it is capable of driving 600 ohm resistive loads.  U2a is used as a unity-gain follower to buffer the rather high impedance output from the initial R/C PWM filtering (R9-11, C8-C10) and it feeds U2b which is configured as a 2 pole 1 kHz bandpass filter to further clean up the 1 kHz sine wave being generated.  Since U2b has some gain, the values of C10 and R11 were chosen to attenuate the input to U2a enough so that even at a relatively low battery voltage (7.0 volts) it avoids clipping when hitting the power supply rails, providing about 4.5 volts RMS.  C13 is used as a DC block on the output and R15 assures that the op amp's output will always see a resistive load to assure stability.

Preserving the battery:

One problem with portable, battery-powered devices that are used  infrequently is that they often get left on - either because they weren't shut off in the first place, or the power switch got bumped.  To prevent this, a momentary pushbutton switch was used so that a brief "bump" is less likely to leave it in the "on" state.  In addition to this, the pushbutton itself is physically recessed, making it less likely that something being carried along with the unit (e.g. connectors, tools, etc.) will push and hold the button in the "on" position and run the battery down.

Figure 3:
Inside the 1 kHz tone generator.  If you look carefully, you can
see the the blue "power" LED is illuminated.
Click on the image for a larger version.
To eliminate the other likely cause of a dead battery - forgetting to turn it off - the unit is designed to detect if its audio output actually connected to something.  To do this, R8 pulls pin 6, configured as an A/D input, up to the +5 volt rail and it, in turn, is connected via R16 to the audio output.  If the audio output is connected to a device with a resistive load on its input of less than 100k or so (such as the external audio input of the service monitor) the PIC will see the DC voltage on pin 6 as being below a software-predefined threshold (3/4 of the supply voltage) and it will remain powered up.  If the output is disconnected from a load, this voltage will rise above the threshold and if this condition persists for more than 3 seconds the PIC will set pin 7 low, turn off Q2, "un-bias" Q1 and disconnect the battery.

A software timer has also been implemented that will automatically turn off the unit after 30 minutes with an alert tone sounding 20 seconds before power-off so that the timer can be reset by pressing this button momentarily:  This feature was added just in case the unit was left connected to the service monitor and I happen to forget about it!

LED1 (a blue LED) is used used to show when the unit is powered up and since a high-brightness, focused-lens blue LED was used, only a milliamp or two (as set by R4) is needed to provide adequate power for it to be visible - even in bright light.  Finally, D3 and self-resetting 300mA thermal fuse F1 provide protection against accidental reverse voltage when one is fumbling about trying to connect the battery.

In total, the unit consumes about 12 milliamps (approximately 4 milliamps of this is U2) when operating and an undetectable amount of current (well under 100 nanoamps) when it is turned off.  What this means is that when powered down, the battery life will essentially be that of its shelf life - and if you happen to use a lithium 9 volt battery, that could well exceed 10 years!

The mechanical construction:

When I make a "one-off" project I almost never lay out and make a circuit board:  In the time it would take me to do this, I would have already completed the project in the manner shown, having wired it on a piece of prototype board that was selected to be just big enough to accommodate all of the circuitry.

As with all other projects that I build using through-hole techniques on prototype board, this material has an array of holes on 0.1" centers with small, etched copper rings around each hole on the bottom side to make both electrically and mechanically secure connections.  For interconnections I used #30 AWG "Kynar" wire-wrap wire, the advantage of this material is that soldering will "heat strip" the connections:  I've built hundreds of projects over the years using this technique and it has proven to be very reliable once one masters the technique!

In rummaging around my collection of project boxes I didn't find anything that was quite the right size so I determined the minimum footprint required to accommodate the board, the switch and a 9 volt battery and cut some pieces of double-sized glass-epoxy circuit board using a very heavy-duty paper cutter.  Soldering five pieces together (the bottom and four sides) I soon had a very sturdy box that was also well shielded from RF - an important consideration when using equipment at a site with many high-power transmitters!  In retrospect I could have made the box a bit "thinner", but this worked out nicely.

The board itself is mounted using two hexagonal metal standoffs from Radio Shack, each one having been sawed in half and then filed down so that the cut was flat and each was of equal height.  Since these standoffs are nickel-plated brass, they solder quite easily to the circuit board and make an extremely rugged support.

The sixth piece of copper-clad is the lid of the box, sized exactly the same as the bottom piece.  To attach it, two more hexagonal standoffs were cut in half and the four pieces were soldered into the corners as shown in Figure 3.  In the lid, matching holes were drilled to allow the screws included with the standoffs to be used to secure it into place.  Not shown is a small piece of foam that was attached to the bottom side of the lid with RTV ("Silicone") adhesive that keeps the 9 volt battery from rattling around when the cover is in place.

The momentary pushbutton switch was centered over a countersunk hole that I drilled in the side of the box as shown in Figure 1 and was initially tacked into place using a very small amount of cyanoacrylate adhesive ("Super" glue) and I was very careful to avoid getting any of it into the button's works!  Once this adhesive had set I soldered the pins of the switch that would connect to ground directly to the case for more mechanical support and then I used some epoxy around the switch for further reinforcement.  Next to the switch can be seen the blue power indicator LED (in the clear lens) which was epoxied into place at the same time as the switch.

The output cable is a piece of RG-174 coax that I found in my junk box with an already-attached male BNC connector.  At the BNC connector end of the cable I added two overlapping pieces of heat-shrink tubing to mechanically strengthen the crimp connection and, as can be seen in Figure 3, I also added a piece of heat shrink tubing at the point where the RG-174 entered the box through the drilled hole of the box to relieve strain there, too.  At this same point, a small wire tie was attached to the cable on the inside of the box to keep it from being pulled out while a piece of heavy wire was attached to the shield and connected to the case and the center conductor attached to the audio output.

The software:

A DDS (Direct Digital Synthesis) algorithm was chosen to generate the sine waves and with this technique one indexes a table containing a sine wave at a known rate and step size to generate an arbitrary frequency.

An article on the operation of a DDS may be found here:   

http://en.wikipedia.org/wiki/Direct_digital_synthesizer.


I programmed the PIC's interrupt and the PWM rates to precisely 20.000 kHz - fairly easy to do with the 20 MHz crystal that I used - and wrote a DDS algorithm using 32 bit integer counters.  In doing the math, the use of a 32 bit "Frequency Control Word" yielded the following:

20 kHz sample rate / 2^32 = 0.0000046566 Hz frequency steps.

Clearly, this amount of resolution was far in excess of the stability and accuracy of the standard CPU-grade crystal that I used as the master timing reference as each "step" would have represented approximately 0.18 Hz at the 20 MHz clock frequency.  If I'd chosen to use 16 bit counters, instead, my frequency step size would have been 1/65536th of this, or 0.305 Hz and I'd have gotten 1000.061 Hz (about 1.2 kHz error at the 20 MHz crystal frequency) which would have been more than good enough, but since my little PIC didn't need to be doing anything else I figured that there was no harm at all in making it crunch 32 bit numbers!

For a Digital-to-Analog converter I used the PIC's built-in PWM generator which is capable of  approximately 10 bits of resolution when used with the hardware timing parameters that I'd chosen to achieve a 20.000 kHz sample rate, but I knew that, in theory, only 8 bits of resolution would be required to achieve an adequately clean sine wave - especially if I followed the output with some sort of audio filter.  What I ended up doing was to use the PWM in 10 bit mode and left-justify the 8 bit sine data and discarding the lowest two bits.

For more info on PWM techniques, read this article:   

http://en.wikipedia.org/wiki/Pulse-width_modulation.


PWM has the advantage of being very easy to produce in hardware as it is simply a matter of timing the width of the output pulses and in so-doing, the output voltage (after smoothing) is proportional to the duty cycle of those pulses.  The use of PWM does throw in a bit of a complication when it comes to generating complex analog signals using simple hardware:
  • With simple R/C filtering the output voltage's rate-of-change may not exactly be what is expected for all frequencies at all amplitudes and slopes.
  • Simple PWM hardware/software has the problem that only one edge of the stored samples are being used rather than an averaged, "middle" value between two subsequent steps.
The upshot of these factors - particularly the second one - is that any sine wave generated using this method is likely to have some distortion, this being caused by the fact that the samples being generated are slightly offset in time from the actual "center" of the sample and the net result is that there ends up being a residual amount of phase modulation which, in turn, causes a slight amount of harmonic distortion.  The amplitude of these harmonics depends on several factors such as the PWM frequency, the sample rate (the two don't need to be the same, but it's a good idea that they be at least harmonically related to avoid other artifacts), the PWM resolution (and that of the sine table's entries), the actual size of the sine table, and the type of hardware used to filter the PWM output.

In my particular case I measured 0.7% total harmonic distortion + noise on the output of the tone generator - this, on the output of U2b, the 1 kHz bandpass filter.  While perfectly adequate for SINAD measurements out to 30dB or so, I decided that I could do better!

Note:  The bandpass filter reduced the 2nd harmonic's amplitude by approximately 25dB, so the distortion was actually worse than this at the output of U2a, "before" the 1 kHz bandpass filter.

Adding Predistortion:

In theory one could calculate these effects "on the fly" within the DDS algorithm and cancel them out but with the rather limited computational horsepower of the PIC there is only so much one can do - not to mention the amount of time I wanted to spend on this project!  As I was interested in  generating only 1 kHz for this particular project I could simply "pre-distort" the sine table itself, optimizing it for this one frequency.

Many years ago (when GWBASIC was still commonly used) I wrote a simple BASIC program that generated sine wave tables of arbitrary size and span and wrote them to a text file that could be imported into source code so I started with that, adding some extra terms to produce additional harmonics in the manner of the formula below:

   Amplitude = sin(w) + (a * sin(w * 2)) + (b * sin(w * 3))

Where:
  • Amplitude is the value of the sine output plus the distortion.  This gets scaled and offset according to the requirements of the sine table.  (e.g. for a table consisting of unsigned 8 bit values it might range from 0 through 255.)
  • w is the input value (in radians) scaled to the size of the table.  (e.g.  a full sine table with 256 entries would scale 0-2π radians to an index range of 0-255.)
  • a is the scaling factor for the 2nd harmonic's amplitude.
  • b is the scaling factor for the 3rd harmonic's amplitude.

One could add additional harmonics, but having only the 2nd and 3rd is enough for our purposes.

In this project I used an 8 bit, 256 entry sine table and using "a" and "b" I could introduce into this table some 2nd and 3rd harmonic distortion and depending on correction needed, "a" and "b" could be either positive or negative.

When adding these extra terms for the 2nd and 3rd harmonics with "a" and "b" I did have to slightly rescale the "span" of the output from 255 to 251 or 252 to keep the resulting values within the range of 0-255 since the harmonics did add a bit of extra amplitude to the overall sine output:  Ultimately I scaled the output to achieve a range of 1 to 254 since the use of 20.0 kHz PWM rate (a divisor of 250) rather than a 19.52 kHz rate (a divisor of 256) implied that my PWM hardware's resolution was actually just a hair under 10 bits.  (I actually tried it both ways and it didn't matter!)

Figure 4:
The "waterfall" display from the Spectrum Lab program showing the 1 kHz fundamental and up through the 9th harmonic after tweaking the sine table.  Not shown is the output of the script that displays the percentage distortion of the harmonics through the 6th and the totals.
Click on the image for a larger version.


Determining scaling factors "a" and "b":

For determining the "cleanliness" of the sine wave I used my desktop computer with an Asus 24 bit sound card running the "Spectrum Lab" software to analyze the harmonics on the output of U2b.  Spectrum Lab has a built in, interpreted scripting language (see "Conditional Actions" in the Spectrum Lab documentation) and with it I wrote a simple program to determine the precise frequency and amplitude of the peak output (nominally 1 kHz) and measure the amplitude of each of the harmonics through the 6th, individually determine their power contribution (and thus,  percentage content) and display those values and their sum to yield an approximate THD (Total Harmonic Distortion) value.  (The measurement taken with Spectrum Lab did not include noise at frequencies other than the fundamental and the harmonics through the 6th so it was not a "THD+Noise" reading.)


Another instrument that I had handy, also connected to U2b's output, was an old HP-332A distortion analyzer.  This device, made in the mid/late 1960's, is still useful today and can measure the distortion+noise of a signal as low as 5 Hz and as high as 600 kHz.  A bit finicky to operate (it takes a gentle touch and some practice) it will reliably measure distortion+noise down to 0.02% or lower.

I determined, through rough calculation of measured harmonics with a "pure" sine table (e.g. no added harmonics) and then through later iterative means that a reasonable value for "a" was +0.085 and "b" was +0.001 - but your mileage may vary!

In using both Spectrum Lab on the computer and with the HP-332A I measured well under 0.035% distortion at the output of U2b, the 1 kHz bandpass filter, with each method:  With a bit of additional tweaking I may have been able to reduce the distortion even more, but I was approaching the point of diminishing returns and I was starting to approach the limit of the HP-332A, anyway!

Figure 5:
The 1 kHz tone generator connected to the input of the
service monitor and operating.
0.6% distortion is about as low as this service monitor will measure
 - at least until I get around to tweaking it's notch filter....
Click on the image for a larger version.
Comment:

At the output of U2a, prior to the 1 kHz bandpass filter, Spectrum Lab showed that the harmonic distortion at the end of tweaking was on the order of 0.4%, but the bandpass filter reduces the 2nd harmonic by about 25dB and the higher-order harmonics (and noise) by even more.

The results:

The upshot of this is that with this tone generator, the ability to measure the SINAD exceeds that of the service monitor (it reads in excess of 50dB when the generator is connected to the input) and it is, in fact, "cleaner" than the instrument's own built-in tone generator which is on the order of 0.1% THD+noise.

[End]

This page stolen from ka7oei.blogspot.com