

Random Quote Board
The Five Methods for Frequency Demodulation
Yes, I've covered frequency demodulators before (Post #1, Post #2, Post #3). The problem is that I tend to use those posts as references. The information I need is scattered amongst those three posts. Here, I'm going to consolidate the ones that are unique to each other. I'm also going to add some details that I didn't understand (or even know) at the time of the original posts.
There are five unique methods (so far!) for frequency demodulating a signal using digital techniques. These are:
- The phase differential method, which provides two, different ways to frequency demodulate a signal.
- The FM-to-AM method, which also has two ways to demodulate a signal.
- The PLL method
- The delay line discriminator
- The zero crossing discriminator
Let's dig in.
Phase Differential
Frequency is a change of phase over time. Put in mathematical terms, this is:
\( \Large f = {\Delta \theta \over {\Delta t}} \)
where:
- f = frequency
- Δθ = the change (difference) in phase
- Δt = the change (difference) in time
There are two ways to calculate this phase difference. These are to calculate the phase, then calculate the difference. The second is to calculate the difference, then calculate the phase.
The Arctan-and-Derivative Method
The first phase differential method is just calculate the phase of each sample, then subtract the phase between samples. Straightforward, right? Not so fast. There's the +/-π phase boundary problem. My original solution for that was not elegant. Like, at all. Until I read a post on the DSPrelated.com website that explained that there is a way to make it work. It involves the use of integers. In math using integers, typically, if there's overflow (the numbers go past their limits), the numbers will "wrap-around". This means that, if they go past their upper or lower limit, the numbers will go to the other extreme and continue.
For example, using a signed 16-bit integer ("short"), if the value is at the upper limit (+32767), and one more is added, it will flip around to the lower extreme (-32768).
Here's an example using Gnu Radio Companion (GRC). The flowgraph uses a basic sinusoid which is converted from floating point numbers ("floats") to "shorts" (signed 16-bit integers). Due to the scaling at the input of the "Float to Short" block, the sinusoid amplitude is at the limits of what the "short" data type can handle (+/-215). The output is split to show how the addition of values changes the waveform and shows the "wrap-around" affect.


We can use this same concept for a frequency demodulator. First, calculate the phase of each sample. Second, convert that phase from floating point to integer. Finally, calculate the difference using integer math (so that any values that cross the +/-π boundary wrap around). I'm going to call this (in honor of Mark Napier, the engineer who allowed me to understand it) the "arctan and derivative" method.
A quick aside. You cannot do with this the floating point numbers, then convert them to integers and expect the "wrapping" to work. In Gnu Radio, any numbers outside of the limits of the integers will not wrap, they will be clipped. Hence, to make this work, you must convert to integer values first, then perform the math that requires the wrapping to occur.
Guess what? It works. Below is a flowgraph using this concept.


Personally, I think this works really well. My only issue is the conversion to an integer, specifically a "short" (16-bit integer). The 32-bit floating point numbers that GRC normally uses for processing provides 23 bits of dynamic range. Thus, we're losing 7 bits of dynamic range converting to the short. What if we used the GRC "integer" data type (32-bit integer)? Well, in that case, we'd gain 9 bits. Unfortunately, I've not been able to figure out how to make that work in GRC. Yet. I'll keep trying.
The Polar Discriminator
The second method for calculating the phase difference is to first calculate the difference, then calculate the phase. This is the basis of the (improperly-named) Quadrature Demod block in Gnu Radio. You might be wondering, "How do you calculate the difference of the phase before you actually calculate the phase?" Excellent question! It's one of those things that you can do with complex numbers, as James Shima explained in his 1995 paper. Complex numbers can be represented in either Cartesian format (e.g. x+jy) or in polar format (e.g. Mejω). They are equivalent representations. The values relate as follows:
\( \Large M = \sqrt{x^2 + y^2} \) <- Calculate the magnitude
\( \Large \omega = \arctan \left( {y \over x} \right) \) <- Calculate the phase
This leads to how we can calculate the difference before we calculate the actual phase. If you multiply two complex samples together using the polar notation, you get:
\( \Large M_1 \exp^{j \omega_1} \times M_2 \exp^{j \omega_2} \)
For our purposes, we don't care about the magnitudes. We only care about the phase. This reduces the equation to the following:
\( \Large \exp^{j \omega_1} \times \exp^{j \omega_2} \)
When you multiply two numbers of the same base, their exponents add. Thus, the equation becomes:
\( \Large \exp^{j \omega_1} \times \exp^{j \omega_2} = \exp^{j ( \omega_1 + \omega_2)} \)
This would give us the phase sum. We want the phase difference. To do this, we need to flip the sign of the second value. Since these are complex samples, there's an easy way to do this. That is to flip the sign of the imaginary component. The term for this is the complex conjugate. If we conjugate the second value, we wind up with the following equation:
\( \Large \exp^{j \omega_1} \times \exp^{-j \omega_2} = \exp^{j ( \omega_1 - \omega_2)} \)
This leads to the general flow of calculating the phase difference before you actually calculate the phase is as follows:
- Split the samples, with one sample being delayed (to allow for calculating phase between consecutive samples) while the other is unaltered.
- Calculate the complex conjugate of the delayed sample. This allows for the calculation of the phase difference.
- Multiply the two samples (the original sample and the delayed-and-conjugated sample).
Once you've completed these, three steps, you've calculated the phase difference even though you've not yet calculated the actual phase. The only thing left to do is to calculate the actual phase, which in GRC can be done using the "Complex to Arg" block (the "argument" in math terms is the same as the "arctangent").
At which point, the signal is frequency demodulated. We call this a polar discriminator because we're using the polar format of complex samples to effectively perform the demodulation. To be clear, we DO NOT have to change the complex samples to the polar format before we perform these calculations. We simply take two, consecutive samples, conjugate the previous one, and multiply them together. That's because the Cartesian forms and the polar forms are the same. Thus, looking at the flowgraph below implementing this concept, note that there are no "Cartesian to Polar" blocks. Just conjugate the delayed sample, multiply the two consecutive samples together, calculate the phase of the product sample and VIOLA! Instant frequency demodulation.
But, wait, you might ask. Why doesn't this method have to worry about the +/-π boundary problem? I had the same thought, but I figured out the reason why it works.
What this has done is to calculate the phase difference. But remember that frequency is a change of phase over time. Where's the time difference? Well, since this is a sampled signal, the time difference is the sample period (the time between samples). This leads to:
\( \Large f = { {\Delta\theta} \over {T_S}} \)
where:
- f = frequency
- Δθ = phase difference
- TS = sample period
Dividing by the sample period is the sample as multiplying by the sample rate. Which means the calculation can be:
\( \Large f = { {\Delta\theta} \times {f_S}} \)
where:
- f = frequency
- Δθ = phase difference
- fS = sample rate
The one problem left is that the units for this calculation would be in radians. As an engineer, we're used to hertz (Hz). The conversion from radians to Hz is to divide by 2π. The calculation now becomes:
\( \Large f = {{ {\Delta\theta} \times {f_S}} \over {2 \pi}} \) in Hz
where:
- f = frequency
- Δθ = phase difference
- fS = sample rate
The calculation above would provide a result in which the amplitude would be the actual frequency deviation of the original FM signal. For example, in the US, FM broadcast stations use a deviation of 75 kHz or higher (up to 82 kHz, in some cases). Even a relatively narrowband FM transmitter would still be several thousands of Hz. To account for this, the last part of our scaling will be to normalize the output amplitudes due to the deviation. This means to divide by the deviation value. The final equation becomes:
\( \Large f = {{ {\Delta\theta} \times {f_S}} \over {2 \pi \times deviation}} \) in Hz
where:
- f = frequency
- Δθ = phase difference
- fS = sample rate
- Deviation = deviation of the original FM signal, in Hz
This is where the "Gain" value that you find in the "Quadrature Demod" block comes from. To summarize, it breaks down as follows:
- Multiply by the sample rate ("samp_rate", by default in Gnu Radio). This is the same as dividing by the sample period. This is what converts the final value to Hz.
- Divide by 2π. This converts the radians to fractions of a cycle.
- Divide by the deviation. This normalizes the amplitudes so that they fall within +/-1, and is especially useful if the samples will be fed into an "Audio Sink" in Gnu Radio. (NOTE: The default variable name for this in the "Quadrature Demod" block is "fsk_deviation_hz".)
Putting this altogether into a flowgraph, we wind up with the following:


This frequency demodulation method is how GRC's "Quadrature Demod" block works. Thus, we could replace all of the blocks between the output of the lowpass filter and the input of the time and frequency sinks with the "Quadrature Demod" block, as shown below:


Note that the "Gain" value of the "Quadrature Demod" block is the scaling value we calculated (Gain: (sample rate)/(2*π*deviation)).
There are several variations of the polar discriminator. This includes:
- The polar discriminator without the arctangent function - the Lyons method
- The polar discriminator without the arctangent function - my method
- The polar discriminator using the arcsin function
FM-to-AM Conversion
This concept looks at taking the frequency deviation of the FM signal and applying a process that will create an AM signal based on the deviation. There are two methods for this. (NOTE: I originally thought of them as unique; on review, they're really the same just with different methods to create the AM component.) These are slope detection and differentiate and envelope detection. Both methods add an AM component to the FM signal, then AM detect the signal. The only difference is how they create the AM component. The slope detector uses a filter; the differentiate-and-envelope detector uses a differentiator.
Both rely on a frequency offset from the complex center frequency of 0 Hz. The slope detection method offsets a filter from 0 Hz; the differentiate-and-envelope detection method offsets the signal from 0 Hz.
Slope Detection
The idea of the slope detector is that we change the amplitude of the signal based on its instantaneous frequency using the slope of a filter . In other words, we add an amplitude modulation along with the frequency modulation. In other words, we make it both FM and AM at the same time. We create this effect by using a filter with a very wide transition width (the sloped part of the filter). The flowgraph appears as follows:

Slope detection requires the use of a filter with a wide transition width. The filter is a complex bandpass filter using complex taps. This allows for it to be offcenter in the spectrum. The lower transition band covers the FM signal, which after being filtered, is the sole signal centered at 0 Hz.


The result of this demodulator is shown below.

Comparing this demodulator with the polar discriminator above, it has (in my opinion) worse performance. If you look at the spectral display of the baseband output of the slope detector above, then compare it with the spectrum of the baseband from the polar discriminator, you see a lot more noise at the base of the 19 kHz pilot tone in the slope detector than from the polar discriminator. Further, adding an audio sink, the audio sounded worse (a slight noise present in the slope detector that was not present in the polar discriminator).
Differentiate-and-Envelope Detection
This method also adds an AM component to the FM signal, except it uses a differentiator to add the AM component as opposed to a filter as in the slope detector. The slope detector uses a filter that is offcenter from 0 Hz. In the differentiate-and-envelope detector, the signal is offcenter from 0 Hz before the differentiator is applied.
Why the offset? To understand that, we need to do a bit of math. The FM signal can be represented as the following complex signal:
\( \Large {s = M \exp^{(j \omega t + \theta )}} \)
If we differentiate this signal, we get the following:
\( \Large {{ds \over dt} = (j \omega + {{d \theta} \over dt}) M \exp^ {(j \omega t + \theta )}} \)
where:
- ω = the frequency offset set by the receiver
- dθ/dt = the frequency deviation of the original FM signal (you know, just as we discussed in the phase differential section).
This differentiated signal is the same equation as a full-carrier, double-sideband AM signal. The value of ω is the carrier amplitude, while the value dθ/dt is the information. The value of ω must be at least equal to the value dθ/dt; otherwise, you'll get "sideband splatter" (distortion of the AM signal because the information causes the carrier to cross the zero line). This means that we need to set the offset at least equal to the deviation in order to not have distortion on our signal.
But we don't want the offset to be too high, either. As the offset (ω) increases, the ratio of the carrier amplitude to the information amplitude also increases. This, in turn, will reduce the modulation index of the AM signal. That means you'll wind up with a lower SNR at the output of the receiver. The best offset is right at the deviation value. This will get you 100% modulation index. The index drops as the value of the offset increases beyond the deviation.
Let's talk briefly about how we will achieve this frequency offset...
The Frequency Shift Method for Processing
Remember how I said earlier that I've picked up a few things since my first posts on FM demodulators back in the dark ages of 2019? Here's one of those things. Rather than tuning the SDR directly to the frequency of the signal being demodulated, filtering it, then frequency shifting it, I'm simply going to tune my SDR offset from the signal center frequency, then filter using a bandpass filter. The output will be a signal whose center frequency is at some IF. The result is the same as if I had used the first method (tune directly to signal, filter, then frequency shift), only it saves the processing of creating the complex sinusoid and multiplying it with the incoming samples. As fred harris points out, the taps for the filter might have different values (due to the fact that I'm using complex taps for the bandpass filter vs the real taps of the lowpass filter), but the number of taps remains the same. This, in turn, means I'm not having to do any more processing for the bandpass vs lowpass filter. They're the same, processing-wise. This will be the method I use for this, the differentiate-and-envelope detection demodulator, as well as the delay line discriminator and the zero crossing discriminator, which I'll cover later.
Back to our differentiate-and-envelope detector. For this processing, I used the Lyons' 7-tap differentiator. To ensure that the differentiator stays within the linear portion of operation, the sample rate is not decimated after passing through the lowpass filter. The offset is just above the deviation (as discussed above) with an extra bit of offset to deal with noise.


The performance of this demodulator was slightly better than the slope detection method, perhaps because the differentiator is more linear than the slope of the filter, so that frequency changes map more closely to amplitude changes in the information signal. However, its performance will probably never match that of the phase difference methods for the reason posited by James Shima (my emphasis added):
The other issue with using the derivative formulation is that it is not as accurate as the atan version. Why? Because the first order difference in phase of the message is more accurate than the first order difference of the entire signal. In other words, for sinusoidal messages the atan version gives exact results for the true derivative, whereas this is not true for the derivative formulation you listed. As such, for more complex message signals atan version should show less error.
In other words, calculating the difference of the phase (phase differential) is a far more accurate demodulation method than calculating the difference of the entire signal (differential-and-envelope). Which explains why the differential-and-envelope method does not provide as clean a demodulation as does either the phase differential methods.
Summary
All told, the FM-to-AM conversion demodulators are probably the worst type of FM demodulators. Don't get me wrong; they work. Sort of. But they do not provide as clean a demodulation as the phase difference method. Further, there are some aspects that need to be tweaked. For example, both need a higher sample rate to ensure the differentiators work properly. The differentiate-and-envelope detector also needs its center frequency offset adjusted. These are things that do not exist in the phase difference methods.
The Phase Lock Loop
A phase lock loop (PLL) is a circuit that uses feedback to lock to the frequency of a signal. One of the uses of such a circuit is to demodulate signals, specifically FM signals.
Normally, I would try to make a PLL in Gnu Radio using individual components. Unfortunately, GRC does not have a mechanism to allow feedback within a flowgraph. The good news is that it does have a PLL block that we can use, specifically the "PLL Frequency Detector" block. This block has three parameters. These are:
- Loop Bandwidth: The loop bandwidth allows the circuit to determine how closely to track the target signal. If it is too low, it will not be agile enough to track the signal (the output bandwidth will be too low), while if it is too high, it will improperly track the signal such that it will be noisy. The loop bandwidth is the key parameter that defines how well this block will operate as a frequency demodulator. The best values appear to be 0.3 - 0.5, in my experience. The value that appears to work best for my purposes is (deviation)/(sample rate), where "sample rate" is the sample rate going into the PLL block, not necessarily the "samp_rate" value set in the "Variable" block. Just to be clear.
- Min phase/sample: This is the minimum phase change per sample allowed. The phase is measured in radians, and the best value for this (in my experience) appears to be -2π*deviation/(sample rate).
- Max phase/sample: Just as with the minimum phase change per sample, the phase is measured in radians. The best value is the positive version of the min phase change, which would be 2π*deviation/(sample rate).
The nice thing about the "PLL Frequency Detector" block is that, just as with the "Quadrature Demod" block, it is the only block required for demodulation. However, unlike with the "Quadrature Demod" block, the "PLL Frequency Detector" needs a bit of help with the output amplitude. Therefore, a "Multiply Const" block right after will typically be needed if you wish to use it for display or other processing purposes.


Demodulation with the "PLL Frequency Detector" may be as good as the phase differential methods. However, as the output requires constant amplitude tweaking, I still prefer the more-consistent output of the phase differential methods.
The Delay Line Discriminator
These last two are special in that they require the signal to be changed from complex to real in order to work. Every other frequency demodulator works from complex samples, though the FM-to-AM methods will also work from real samples. This one and the next one (the zero crossing discriminator) only work only with real samples. That means that the FM signal has to be shifted to an IF, since a real-only signal cannot cross the 0 Hz or Nyquist frequency boundaries. If it does so, it will alias.
We create this IF using the same frequency shift method as with the differentiate-and-envelope detect method.
The concept of the delay line discriminator is this: if you multiply a sinusoid with another sinusoid that is the same amplitude and frequency, but 90o (π/2 radians) out of phase with the first sinusoid, you get another signal. This is a sinusoid at twice the frequency of the original sinusoids. But what if the two sinusoids are not precisely 90o out of phase? What if they are either slightly more or less than 90o? Then the product of the multiplication will be a DC component plus the sinusoid at twice the frequency. If we filter out the 2x frequency component (say with a lowpass filter), you're left with the DC component.
Here's the good news. The amplitude of the DC component will be determined by how far off from 90o the relative phase is. As the relative phase moves further away and closer to 90o, the amplitude of this DC component will change accordingly. We can use this concept to frequency demodulate a signal. The way in which we do this is to frequency shift the signal to an IF. Then we split the signal; one-half goes directly to a multiplier. The other half is delayed by 1/4 of a cycle of the IF. For example, if the IF is 200 kHz, it would have a period of 5 μsec. If we can delay the second half of the split signal by precisely 1/4 of this (1.25 μsec), we'll have our circuit.
The way this circuit works is as follows:
- The FM signal at the desired IF enters the circuit, where it is split.
- One-half of the split goes directly to a multiplier.
- The other half goes through a delay of 1/4 cycle (90o or π/2 radians), then goes to the other input of the multiplier.
- The output of the multiplier passes through a lowpass filter to remove the 2x frequency component.
- If the signal is precisely at the center of the IF, the output from the filter will be zero signal.
- If the signal frequency is either higher or lower than the IF, then the two signals (original and delayed) will no longer be 90o out of phase. That's because the delay is set for precisely 90o at the IF. Any other frequency and the output will be a low frequency signal related to the amount of frequency offset from the IF. The greater the offset, the greater the amplitude (either positive or negative) at the output.
How do we implement this concept? Take the FM signal, frequency shift it to an intermediate frequency (IF), convert it to real, then multiply it with a delayed version of itself. It's the amount of delay that is important. We need a delay that is 1/4 cycle of the IF. The 1/4 cycle means the phase difference is 90o. This leads to needing a number of samples per cycle of the IF that is evenly divisible by 4. The number of samples per cycle cannot be too high, however. That's because the IF will be the sample rate divided by the samples per cycle. If you make the samples per cycle too high, the IF will be too low and the signal will be aliased once it is convered to real. There's also the filtering after the delay-and-multiplication. You also do not want any of the delayed-and-multiplied signal to fall within the lowpass filter passband. This means that the offset must be high enough that the frequency deviation is never less than 1/2 of the passband. Here's how I implemented this in Gnu Radio.

The results are not too shabby, though still not as good as the phase differential methods.

Zero Crossing Discriminator
This is my favorite method, though it is also the most computationally-expensive one. I like it because it's fun. The concept is this: shift the signal to a IF, convert it from complex to real, then turn each zero crossing of the IF sinusoid into an impulse. Essentially count the impulses. VOILA! The signal is demodulated. Why? Because, due to the frequency modulation, as the signal swings above the center frequency, the period will drop. (Remember, kids: Frequency is the inverse of the period, and the period is the inverse of the frequency.) As the period drops, the impulses will get closer together. This means more of them in a set time. The inverse is true as the frequency swings lower than the center frequency, the number of impulses will drop. These impulses can be "counted" through the straightforward method of lowpass filtering.
The downside to this method (and the reason why it's not a good method for implementing digitally) is that creating the impulses is effectively quantizing the levels based on the sample rate and the IF. The lower the sample rate or the higher the IF, the fewer the quantizing levels. In order to get performance equivalent to the phase differential methods, you need a reeeeeally high sample rate or a reeeeeally low IF. You're limited by the bandwidth of the signal to how low the IF can be. The limit is 1/2 of the bandwidth. For a FM broadcast station, this would be roughly 100 kHz. (NOTE: In the US, the deviation allowed is 75 kHz, with some cases allowing up to 82 kHz.) The maximum sample rate would be whatever your system can handle. In total, this means that this method is not a good one if you're looking to try this on a Raspberry Pi (though perhaps one of the newer ones might be able to handle it).

Using this flowgraph with two, different "interp" values (a value used to increase the sample rate), the results show that a higher sample rate definitely improves the output signal.


Again, this is my favorite demodulator despite the fact that it is not really practical for any actual, real-world situation. It's much more complicated, requires a lot more processing, and still will not get to the same accuracy as one of the phase differential methods.
Summary
There you have it. Pretty much every FM demodulator possible using digital techniques. I'm going to consider this my "reference page" for all things FM demodulation from here on. If I come across another demodulator, I probably won't add a blog post. I'll just update this page and add that new technique here.
Til next time!