Showing posts with label mcHF SDR transceiver. Show all posts
Showing posts with label mcHF SDR transceiver. Show all posts

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".

Friday, November 20, 2015

FM squelch and subaudible tone detection on the mcHF

In a previous installment  ("Adding FM to the mcHF SDR Transceiver" - link) I described how the demodulation of FM signals was added to the mcHF SDR transceiver but being able to receive FM implies the addition of a few other features, namely that of squelch "circuitry" - of both "carrier" and "tone" types.

Determining the "squelch" status of a received signal:

One of the most obvious ways to determine the presence of a signal is to compare the signal strength against a pre-set threshold:  If the signal is above that threshold it is considered to be "present" and an audio gate is opened so that it may be heard.

This sounds like a good way to do it - except that it isn't, really, at least not with FM signals.

If you were listening to an FM signal on 10 meters that was fading in and out (as it often does!) one would have to set the threshold just above that of the background noise - or "open" (e.g. disable) it completely to prevent it from disappearing when the signal strength dove into a minimum during QSB.  If the background noise were to vary - as it can over the course of a day and with propagation - the squelch would be prone to opening and closing as well.

As it turns out, typical FM squelch circuits do not operate on signal strength as there are better methods for determining the quality of the signal being received that can take advantage of the various properties of the FM signals themselves.

Making "Triangle Noise" useful:

Mentioned in the previous entry on this topic was "Triangle Noise", so-called by the way it is often represented graphically.
Figure 1:
A graph representing the relative amplitude of noise with strong weak FM signals.  It is the upward tilt of the noise energy to which "Triangle" noise refers - the angle getting "steeper" as the signal degrades.  Also represented is a high-pass filter that removes the modulated audio, leaving only the noise to be detected.
From this diagram one can begin to see why pre-emphasizing audio along a curve similar to the "weak signal noise" line can improve weak-signal intelligibility by boosting the high-frequency audio on transmit (and doing the inverse on receive) to compensate for the noise that encroaches on weak signals.

As can be seen in Figure 1 the noise in a recovered FM signal increases as the signal get weaker - but notice something else:  The noise increases more quickly at higher frequencies of audio than it does at lower audio frequencies.  Looking at Figure 1 you might make another observation:  Because there is typically some low-pass filtering of the transmitted audio to limit its occupied bandwidth, there is no actual (useful) audio content above that frequency from the distant station, but the noise is still there.

High-pass filtering to detect (only) "squelch noise":

From the above drawing in Figure 1 it can be recognized that if we only "listen" to the high-frequency audio energy that passes through the "Squelch noise" high-pass filter all we are going to detect is the noise level, independent of the modulated audio.  If we base our signal quality on the amount of noise that we detect at these high frequencies - which are typically above the typical hearing range (usually ultrasonic, above 10 kHz) - we can see that we don't need to know anything about the signal strength at all.

This method works owing to an important property of FM demodulators:  The amount of recovered audio does not change with the signal strength as the demodulator is "interested" only in the amount of frequency change, regardless of the actual amplitude.  What does change is the amount of noise in our signal as thermal noise starts to creep in, causing uncertainty in the demodulation.  In other words, we can gauge the quality of the signal by looking only at the amount of ultrasonic noise coming from our demodulator.
Figure 2: 
An representation of an analog squelch circuit with hysteresis.  The high-pass filter removes the "program" audio modulated onto the carrier (e.g. voice) which is then amplified as necessary and then rectified/filtered to DC to derive a voltage proportional to the amount of ultrasonic noise present:  The higher the voltage, the "weaker" and noisier the signal.
The resulting voltage is then fed with a comparator that includes hysteresis to prevent it from "flapping" when it is near the squelch threshold.

An analog representation of a squelch circuit may be seen in Figure 2.  For the simplest circuit, the high-pass filter could be as simple as an R/C differentiator followed by a single-transistor amplifier, and the same sorts of analogs (pun intended!) could be applied in software.

After getting the mcHF FM demodulator to be functional I tried several different high-pass filter methods - including a very simple differentiator algorithm such as that described in the previous posting - except, of course, that the "knee" frequency was shifted far upwards.  The absolute value was then taken from the output of the high-pass filtered and smoothed and printed on the screen while the input signal, modulated with a 1 kHz audio sine wave and fed to a SINAD meter (read about SINAD here - link) while signal level was varied:  In this way I could see how the output of the noise detection circuit behaved with differing signal conditions.

In doing this testing I noted that a simple differentiator did not work as well as I'd hoped - likely due to the fact that unlike an analog circuit in which the high-frequency energy can continue to increase in intensity with frequencies well into the 10's or 100's of kHz, in the digital domain we have a "hard" limit enforced by Nyquist, stopping at 23 kHz or so on the mcHF with its 48 ksps rate.

With less high frequency spectral noise energy (overall) to work with it is necessary to amplify the output of a simple differentiator more, but this also brings up the lower frequency (audio) components, causing it to be more affected by speech and other content, requiring a better filter.  Ultimately I determined that 6-pole IIR high-pass audio filter with a 15 kHz cut-off frequency, capable of reducing "speech" energy and its second and third harmonics below 9-10 kHz by 40-60dB, worked pretty well:  In testing I also tried a similar filter with an 8 kHz cut-off, but it was more-affected by voice modulation and its immediate harmonics.

Comment:

If the FM demodulation is working properly the result will be a low-distortion, faithful representation of the original audio source with little/no energy above the low-pass filter's cut-off in the transmitter.  If the signal is distorted in some way - such as with multipath distortion, being off-frequency or with excess deviation, energy from this distortion can appear in the ultrasonic region which cannot be easily distinguished from "squelch" noise.
If this energy is high enough, the squelch can close inadvertently since the signal may be "mistaken" as being weak:  This is referred to as "squelch clamping" and is so-called as it is often seen on voice peaks of signals degraded by multipath and/or off-frequency.

Determining noise energy:

In short, the algorithm to determine the squelch energy was as follows:

loop:

   squelch_avg = (1-α) * squelch_avg + sqrt(abs(hpf_audio)) * α
   if(squelch_avg > MAX_VALUE)
      squelch_avg = MAX_VALUE

Where:
   α = "smoothing" factor
   hpf_audio = audio samples that have been previously high-pass filtered to remove speech energy
   squelch_avg = the "smoothed" squelch output

If you look at the above pseudocode example you'll notice several things:
  • The square root value of the absolute value of the high-pass noise energy is taken.  It was observed that as the signal got noisier, the noise amplitude climbed very quickly:  If we didn't "de-linearize" the squelch reading based on the noise energy - which already has a decidedly non-linear relationship to the signal level - we would find that the majority of our linear squelch adjustment was "smashed" toward one end of the range.  By taking the square root our value increases "less quickly" with noisier signals than it otherwise would.
  • The value "squelch_avg" is integrated (low-pass filtered) to "smooth" it out - not surprising since it is a measurement of noise which, by its nature, is going to vary wildly - particularly since the instantaneous signal level can be anything from zero to peak values.  What we need is a (comparatively) long-term average.
  • The "squelch_avg" value is capped at "MAX_VALUE".  If we did not do this the value of "squelch_avg" would get very high during periods of no signal (maximum noise) and take quite a while to come back down when a signal did appear, causing a rather sluggish response.  The magnitude of "MAX_VALUE" was determined empirically by observing "squelch_avg" with a rather noisy signal - the worst that would be reasonably expected to open a squelch.
Obtaining a usable basis of comparison:

The above "squelch_avg" value increases as the quieting of the received FM signal decreases which means that we must either invert this value or, if a higher "squelch" setting means that a better signal is required for opening the squelch, that same "squelch setting" variable must have its sense inverted as well.

I chose the former approach, with a few additional adjustments:
  • The "squelch_avg" value was rescaled from its original range to approximately  24 representing no-signal conditions to 3 representing a full-quieting signal with modulation with hard limits imposed on this range (e.g. it is not allowed to exceed 24 or drop below 3).
  • The above number was then "inverted" by subtracting it from 24, setting its range to 2 representing no signal to 22 for one that is full-quieting with modulation.
It is not enough to simply compare the derived "squelch_avg" number after scaling/inversion with the squelch setting, but rather a bit of hysteresis must also be employed or else the squelch is likely to "flap" about the threshold.  I chose a value of 10% of the maximum range, or a hysteresis range of +/-2 which seemed to be about right.

The final step was to make sure that if the squelch was set to zero that it was unconditionally open - this, to guarantee so that no matter what, some sort of signal could be heard without worrying about the noise threshold occasionally causing the squelch to close under certain conditions that might cause excess ultrasonic energy to be present.

The result is a squelch that seems to be reasonably fast in response to signals, weak or strong, but very slightly slower in response to weak signals.  This slight asymmetry is actually advantageous as it somewhat reduces the rate-of-change that might occur under weak-signal conditions (e.g. squelch-flapping) - particularly during "mobile flutter."  The only downside that is currently noted is that despite the "de-linearization" the squelch setting is still somewhat compressed with the highest settings being devoted to fairly "quiet" signals" and most of the range representing somewhat noisier signals - but in terms of intelligibility and usability, it "feels" pretty good.

Subaudible tone decoding:

One useful feature in an FM communications receiver is that of a subaudible tone (a.k.a. CTCSS) decoder.  For an article about this method of tone signalling, refer to the Wikipedia article here - link.

In short, this method of signalling uses a low-frequency tone, typically between 67 and 250 Hz, to indicate the presence of a signal and unless the receiver detects this tone on the received signal it is ignored.  In the commercial radio service this was typically used to allow several different users to share the same frequency but to avoid (always) having to listen to the others' conversations.  In amateur radio service it is often used as an interference mitigation technique:  The use of carrier squelch and subaudible tone greatly reduces the probability that the receiver's squelch will falsely open if no signal is present or, possibly, if the wrong signal - in the case where a listener is an an area of overlapping repeaters - is present - but this works only if there is a tone being modulated on the desired signal in the first place.

The Goertzel algorithm:

There are many ways to detect tones, but the method that I chose for the mcHF was the Goertzel algorithm.  Rather than explain exactly how this algorithm works I'll point the reader to the Wikipedia article on the subject here - link.  The use of the Goertzel algorithm has several distinct advantages:
  • Its math-intensive parameters may be calculated before-hand rather than on the fly.
  • It requires only simple addition/subtraction and one multiplication per iteration so it need only take a small amount of processor overhead.
  • Its detection bandwidth is very scalable:  The more samples that are accumulated, the narrower it is - but also slower to respond.
The Goertzel algorithm, as typically implemented, is capable of "looking" at only one frequency at a time - unlike an FFT which looks at many - but since it is relatively "cheap" in terms of processing power (e.g. the most intensive number-crunching is done before-hand) it is possible that one could implement several of them and still use fewer resources than an FFT.

The Goertzel algorithm, like an FFT, will output a number that indicates the magnitude of the signal present at/about the detection frequency, but by itself this number is useless unless one has a basis of comparison.  One approach sometimes taken is to look at the total amount of audio energy, but this is only valid if it can be reasonably assured that no other content will be present such as voice or noise, which may be generally true when detecting DTMF, but this cannot be assured when detecting a subaudible tone in normal communications!

"Differential" Goertzel detection:

I chose to use a "differential" approach in which I set up three separate Goertzel detection algorithms:  One operating at the desired frequency, another operating at 5% below the desired frequency and the third operating at 4% above the desired frequency and processed the results as follows:
  • Sum the amplitude results of the -5% Goertzel and +4% Goertzel detections.
  • Divide the results of the sum, above, by two.
  • Divide the amplitude results of the on-frequency Goertzel by the above sum.
  • The result is a ratio, independent of amplitude, that indicates the amount of on-frequency energy.  In general, a ratio higher than "1" would indicate that "on-frequency" energy was present.
By having the two additional Goertzel detectors (above and below) frequency we accomplish several things at once:
  • We obtain a "reference" amplitude that indicates how much energy there is that is not on the frequency of the desired tone as a basis of comparison.
  • By measuring the amplitude of adjacent frequencies the frequency discrimination capability of the decoder is enhanced without requiring narrower detection bandwidth and the necessarily "slower" detection response that this would imply.
In the case of the last point, above, if we were looking for a 100 Hz tone and a 103 Hz tone was present, our 100 Hz decoder would "weakly-to-medium" detect the 103 Hz tone as well but the +4% decoder (at 104 Hz) would more strongly detect it, but since its value is averaged in the numerator it would reduce the ratiometric output and prevent detection.

Setting the Goertzel bandwidth:

One of the parameters not easily determined in reading about the Goertzel algorithm is that of the detection bandwidth.  This parameter is a bit tricky to discern without using a lot of math, but here is a "thought experiment" to understand the situation when it comes to being able to detect single-frequency (tone) energy using any method.

Considering that the sample rate for the FM decoder is 48 ksps and that the lowest subaudible tone frequency that we wish to detect is 67.0 Hz, we can see that at this sample rate it would take at least 717 samples to fully represent just one cycle at 67.0 Hz.  Logic dictates that we can't just use a single cycle of 67 Hz to reliably detect the presence of such a tone so we might need, say, 20 cycles of the 67 Hz tone just to "be sure" that it was really there and not just some noise at a nearby frequency that was "near" 67 Hz.  Judging by the very round numbers, above, we can see that if we had some sort of filter we might need around 15000 samples (at 48 ksps) in order to be able to filter this 67 Hz signal with semi-reasonable fidelity.

As it turns out, the Goertzel algorithm is somewhat similar.  Using the pre-calculated values for the detection frequency, one simply does a multiply and a few adds and subtractions of each of the incoming samples:  Too few samples (fewer than 717 in our example, above) and one does not have enough information with which to work at low frequencies to determine anything at all about our target frequency of 67 Hz, but with a few more samples one can start to detect on-frequency energy with greater resolution.  If you let the algorithm run for too many samples it will not only take much longer to obtain a reading, but the effective "detection bandwidth" becomes increasingly narrow.  The trick is, therefore, to let the Goertzel algorithm operate for just enough samples to get the desired resolution, but not so many that it will take too long to obtain a result!  In experimentation I determined that approximately 12500 samples were required to provide a tradeoff between adequately-narrow frequency resolution and reasonable response time.

This is part of the reason for the "differential" Goertzel energy detection in which we detect energy at, above and below the desired frequency:  This allows us to use a somewhat "sloppier" - but faster - tone detection algorithm while, at the same time, getting good frequency resolution and, most importantly, the needed amplitude reference to be able to get a useful ratiometric value that is independent of amplitude.

Debouncing the output:

While an output of greater than unity from our differential Goertzel detection generally indicates on-frequency energy, one must use a significantly higher value than that to reduce the probability of false detection.  At this point one can sort of treat the output of the tone detector as a sort of noisy pushbutton switch an apply a simple debouncing algorithm:

loop:

   if(goertzel_ratio >= threshold)   {
      debounce++
      if(debounce > debounce_maximum)
         debounce = debounce_maximum
   }
   else   {
      if(debounce > 0)
         debounce--
   }
   if(debounce >= detect_threshold)
      tone_detect = 1
   else
      tone_detect = 0

where:

   "goertzel_ratio" is the value "f/((a+b)/2))" described above where:
      f = the on-frequency Goertzel detection amplitude value
      a = the above-frequency Goertzel detection amplitude value
      b = the below-frequency Goertzel detection amplitude value
   "threshold" is the ratio value above which it is considered that tone detection is likely.  I found 1.75 to be a nice, "safe" number that reliably indicated on-frequency energy, even in the presence of significant noise.
   "detect_threshold" = the number of "debounce" hits that it will take to consider a tone to be valid.  I found 2 to be a reasonable number.
   "debounce_maximum" is the highest value that the debounce count should attain:  Too high and the it will take a long time to detect the loss of tone!  I used 5 for this which causes a slight amount of effective hysteresis and a faster "attack" than "decay" (e.g. loss of tone).

With the above algorithm - called approximately once every 12500 samples (e.g. just under 4 times per second with a 48ksps sample rate) - the detection is adequately fast and quite reliable, even with noisy signals.

Putting it all together:

Figure 3:
An FM signal with a subaudible tone being detected, indicated by
the "FM" indicator in red.
If tone decoding is not enabled, the Goertzel algorithms are not called at all (to save processor overhead) and the variable "tone_detect" is set to 1 all of the time.  For gating the audio a logical "AND" is used requiring that both the tone detect and squelch be true - unless the squelch setting is 0, in which case the audio is always enabled.

Finally, if the squelch is closed (audio is muted) the audio from the FM demodulator is "zeroed".


* * *

In a future posting I'll describe how the the modulation part of this feature was accomplished on the mcHF along with the pre-emphasis of audio, filtering and the generation of burst and subaudible tones.


[End]

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