

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 demodulated 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 we 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
What we've just calculated is a scaling factor that will be used to put the output of the demodulator into more concrete values that we can use.
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.
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. Further, the offset of the signal from 0 Hz plays an important part in how well the demodulation works. I've not yet found what I think of as the optimal value for this offset, though it is definitely based on the bandwidth of the signal. A high sample rate is also required to ensure that the signal will not be aliased.


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 is (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 there are a couple that can also work from real samples, such as both of the FM-to-AM methods). This one and the next one (the zero crossing discriminator) only work 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. Let's talk about how to get the signal to an IF for a moment.
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 the delay line discriminator and the zero crossing discriminator.
Back to the delay line discriminator. The concept of it is this: if you multiply a sinusoid with one that is the same frequency but 90o (π/2 radians) out of phase with it, then you lowpass filter the product to get rid of the 2x frequency component, the result should be zero. But what if they're not exactly 90o out of phase? Then the result you get depends on whether the out-of-phaseness is more or less than 90o. As the phase is less than 90o, then the result will be DC value less than 0; greater than 90o means a DC value above 0.
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. 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!