AM Modulation¶

In [5]:
import numpy as np
import matplotlib.pyplot as plt

t = np.linspace(0, 1, 1000)

fm = 2;
fc = 20;

message = 1 + 0.5*np.sin(2*np.pi*fm*t)   # slow signal
carrier = np.sin(2*np.pi*fc*t)          # fast signal

y = message * carrier
#noise = 0.2*np.random.randn(len(t));
#y = message * carrier + noise # uncomment to see response with noise

plt.plot(t, y)
plt.title("Measured Signal")
plt.show()
No description has been provided for this image
In [6]:
envelope = np.abs(y)
plt.plot(t, envelope)
Out[6]:
[<matplotlib.lines.Line2D at 0x269e2970f50>]
No description has been provided for this image
In [7]:
window = 50
# We are averaging nearby points to remove fast changes
smoothed = np.convolve(np.abs(y), np.ones(window)/window, mode='same')

plt.plot(t, smoothed)
Out[7]:
[<matplotlib.lines.Line2D at 0x269e2971710>]
No description has been provided for this image
In [8]:
from scipy.signal import butter, filtfilt

b, a = butter(3, 0.05)
filtered = filtfilt(b, a, np.abs(y))

plt.plot(t, filtered)
Out[8]:
[<matplotlib.lines.Line2D at 0x269e4252a90>]
No description has been provided for this image
In [9]:
plt.plot(t, message, label="Original Message")
plt.plot(t, np.abs(y), label="Abs (raw envelope)", alpha=0.5)
plt.plot(t, smoothed, label="Moving Average")
plt.plot(t, filtered, label="Low-pass filter")

plt.legend()
plt.show()
No description has been provided for this image

FM Modulation¶

In [10]:
# FM Modulation
import numpy as np
import matplotlib.pyplot as plt

t = np.linspace(0, 1, 2000)

# Message (slow signal)
message = np.sin(2*np.pi*2*t)

# Carrier base frequency
fc = 20

# Frequency deviation (how much it changes)
kf = 1000  # Change this to see what happens

# Instantaneous frequency
f_inst = fc + kf * message

# Build signal by integrating frequency → phase
phase = 2*np.pi * np.cumsum(f_inst) / len(t)

# FM signal
y_r = np.sin(phase)

#noise = 0.2*np.random.randn(len(y_r))
#y_r = y_r + noise

# Plot
plt.figure(figsize=(10,4))
plt.plot(t, y_r)
plt.title("FM Signal (Frequency Changes Over Time)")
plt.xlabel("Time")
plt.ylabel("Amplitude")
plt.show()

plt.plot(t[:300], y_r[:300])
plt.title("Zoomed FM Signal")
plt.show()
No description has been provided for this image
No description has been provided for this image
In [11]:
# easiest method to recover information
zero_crossings = np.where(np.diff(np.sign(y_r)))[0]

zc_times = t[zero_crossings]

# time differences between crossings
dt = np.diff(zc_times)

# frequency estimate (2 crossings per cycle)
freq_est = 1 / (2 * dt)

# time axis for estimated frequency
t_est = zc_times[:-1]

plt.plot(t_est, freq_est)
plt.title("Estimated Frequency")
plt.show()

window = 20
freq_smooth = np.convolve(freq_est, np.ones(window)/window, mode='same')

plt.figure(figsize=(10,4))
plt.plot(t, message, label="Original Message")
plt.plot(t_est, (freq_smooth - fc)/kf, label="Recovered (scaled)")
plt.legend()
plt.title("FM Recovery via Zero Crossings")
plt.show()
No description has been provided for this image
No description has been provided for this image

“We can detect how fast the signal is oscillating, but we don’t know whether the frequency increased or decreased.”

“We recovered part of the signal, but we lost information.”

To recover the full signal, you need:

  • phase information
  • or derivative with sign
  • or quadrature (I/Q) signals

👉 That’s exactly what SDR will give us later

In [12]:
# Simple Trick (if you want it to look better visually)
recovered = (freq_smooth - fc)/kf
recovered = recovered - np.mean(recovered)

# --- Plot ---
plt.figure(figsize=(10,4))
plt.plot(t, message, label="Original Message")
plt.plot(t_est, (freq_smooth - fc)/kf, label="Recovered (scaled)")
plt.plot(t_est, recovered, label="Recovered (Centered)")
plt.legend()
plt.title("FM Recovery via Zero Crossings (Centered)")
plt.xlabel("Time")
plt.ylabel("Amplitude")
plt.show()
No description has been provided for this image

“FM is more robust to noise—but not always better in every situation.”

“The way you encode information determines how sensitive it is to noise.”

AM Advantages¶

🟢 1. Long-Distance Communication (Big One) AM signals can:

  • travel hundreds to thousands of miles
  • reflect off the ionosphere (especially at night) 👉 That’s why:
  • AM radio stations can be heard across states or countries

🟢 2. Simpler Receivers (Low Complexity) AM is easy to decode:

  • envelope detection (like your abs() demo!)
  • minimal electronics needed 👉 historically:
  • cheaper radios
  • simpler systems

🟢 3. Lower Bandwidth Requirements AM uses:

  • less bandwidth
  • simpler signal structure 👉 good for:
  • voice communication
  • constrained systems

🟢 4. Better in Weak Signal Conditions When signal is very weak:

  • FM → drops out suddenly (“cliff effect”)
  • AM → degrades gradually (still intelligible)

🟢 5. Used in Critical Systems AM is still used in:

  • aviation communication
  • some emergency systems 👉 because:
  • simple
  • reliable
  • predictable behavior

“Engineering is not about the ‘best’ solution—it’s about the right solution for the constraints.”

In [ ]: