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 here 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:
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:
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.
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!)
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
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!
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.
filtered = α * (old_input + input - old_filtered)
old_filtered = filtered
old_input = input
"α" 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.
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!
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!
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]
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".
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.
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."
This page stolen from "ka7oei.blogspot.com".