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:
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-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.
A DDS (Direct Digital Synthesis - see the Wikipedia article about DDS techniques here - link) circuit 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 without overflow.
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 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, 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!
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 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 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!
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" 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, 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.
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.