Digital Communication

Digital systems convert information to bits and bits to waveforms. Learn sampling and PCM (bit rate, quantisation SNR), line coding (NRZ, Manchester), pulse shaping and inter-symbol interference, Nyquist bandwidth and raised-cosine filters, Eb/N0, bit-error rate and eye diagrams — with a BER simulation.

Voice calls, streaming video and IoT sensors all travel as bits. Digital communication theory tells us how many bits per second a channel can carry, how to shape pulses so they don't interfere, and how likely errors are for a given signal power.

An analogy

Sending bits is like flashing a torch in Morse code across a foggy valley: the brighter the flash compared with the fog (Eb/N0), the fewer mistakes the receiver makes.

From analog to bits

Sample (Nyquist), quantise (n bits), encode. Telephone PCM: 8 kHz × 8 bits = 64 kbps. Compression (MP3, AAC, Opus, H.264) then removes redundancy.

Line coding and pulse shaping

NRZ (simple, DC content), Manchester (self-clocking, Ethernet 10BASE-T), AMI, 8b/10b and 64b/66b (high-speed links). Sharp pulses need infinite bandwidth; raised-cosine filters limit bandwidth while avoiding ISI at sampling instants (Nyquist criterion).

Errors

Additive white Gaussian noise causes random bit errors; BER falls steeply with Eb/N0. Eye diagrams visualise noise, jitter and ISI — an open eye means reliable decisions.

Receiver techniques

Matched filters maximise SNR at decision time; equalisers (linear, DFE) undo channel ISI; timing and carrier recovery synchronise the receiver; channel coding adds several dB of gain.

Formulas

Worked example: Telephone PCM

Given: f_s = 8 kHz, 8 bits/sample

Find: Bit rate and SQNR.

Answer: 64 kbps, ≈ 50 dB

Worked example: BER at 9.6 dB

Given: BPSK, E_b/N₀ = 9.6 dB

Find: BER.

Answer: ≈ 10⁻⁵

Monte-Carlo BER of BPSK over AWGN

import numpy as np

# Monte-Carlo BER of BPSK over AWGN vs theory
rng = np.random.default_rng(0)
n = 1_000_000
bits = rng.integers(0, 2, n)
symbols = 2 * bits - 1                        # 0 -> -1, 1 -> +1
for ebn0_db in (0, 4, 8):
    ebn0 = 10 ** (ebn0_db / 10)
    noise = rng.normal(0, np.sqrt(1 / (2 * ebn0)), n)
    rx_bits = (symbols + noise) > 0
    ber = np.mean(rx_bits != bits)
    from math import erfc, sqrt
    theory = 0.5 * erfc(sqrt(ebn0))
    print(f"Eb/N0 {ebn0_db} dB: simulated {ber:.2e}, theory {theory:.2e}")
# Eb/N0 0 dB: simulated 7.85e-02, theory 7.86e-02
# Eb/N0 4 dB: simulated 1.24e-02, theory 1.25e-02
# Eb/N0 8 dB: simulated 2.08e-04, theory 1.91e-04

Simulation adds Gaussian noise with variance N₀/2 = 1/(2·Eb/N₀) to ±1 symbols and counts decision errors — matching theory closely. This is how new modems are verified before hardware exists.

Common mistakes

Applications

Key takeaways

Going further