Project 9: The Mobile Whisper (GSM BCCH Decoder - Education Only)

Build a passive, non-decrypting GSM BCCH decoder that extracts System Information (SI) messages and cell metadata from captured IQ data. This project is education-only and explicitly avoids traffic channels or decryption.

Quick Reference

Attribute Value
Difficulty Level 5: Master
Time Estimate 4-6 weeks
Main Programming Language Python or C (Alternatives: Rust)
Alternative Programming Languages C++, Go
Coolness Level Very High
Business Potential 6/10 (RF measurement, network research tooling)
Prerequisites IQ handling, FFT, digital filtering, basic coding theory
Key Topics GSM TDMA structure, GMSK demodulation, FCCH/SCH sync, convolutional decoding

1. Learning Objectives

By completing this project, you will:

  1. Locate a GSM downlink carrier and correct coarse frequency offset.
  2. Detect FCCH and SCH bursts to establish GSM frame timing and cell identity.
  3. Demodulate GMSK bursts into raw bits with stable timing recovery.
  4. Deinterleave and decode BCCH blocks using convolutional and block codes.
  5. Parse System Information to extract cell ID, LAC, MCC/MNC, and neighbor list.

2. All Theory Needed (Per-Concept Breakdown)

2.1 GSM Air Interface: ARFCN, Channel Types, and TDMA Framing

Fundamentals

GSM is a circuit-switched cellular system that divides spectrum into 200 kHz channels and divides time into repeating frames. Each carrier frequency is identified by an ARFCN (Absolute Radio Frequency Channel Number) that maps to a specific downlink frequency in a given GSM band. On each carrier, GSM uses TDMA: a 4.615 ms frame containing eight time slots. Each time slot can carry a burst. For the BCCH carrier, specific bursts are reserved for broadcast and synchronization. The BCCH itself carries System Information messages that describe the cell and surrounding network. To decode BCCH, you must understand which bursts appear where, how the 51-frame multiframe is structured, and how FCCH and SCH are used to acquire timing. This knowledge is essential because GSM is not a continuous stream of data; it is a precise time-structured system with short bursts and long gaps.

Deep Dive into the Concept

GSM frequency planning begins with ARFCN mapping. In GSM-900, the downlink frequencies are 935 to 960 MHz, spaced at 200 kHz. Each ARFCN corresponds to a carrier and has a paired uplink frequency 45 MHz lower. GSM-1800 uses a different range with 95 MHz duplex spacing. A practical decoder does not need uplink, but it must translate ARFCN to downlink frequency so you can tune correctly or validate what you are seeing. Many decoders use a scan step of 200 kHz and look for the strongest carriers, then verify GSM structure via FCCH.

The time structure is central. A GSM TDMA frame is 4.615 ms and contains 8 time slots, each 577 microseconds. Bursts are not continuous; each time slot is mostly payload plus guard time. Control channels are organized into a 51-frame multiframe. This multiframe repeats and allocates specific frames for FCCH (Frequency Correction Channel), SCH (Synchronization Channel), BCCH (Broadcast Control Channel), and CCCH (Common Control Channel). The FCCH burst is a pure tone (all zeros before modulation) that appears at known positions; it lets the receiver estimate and correct frequency offset. The SCH burst carries the training sequence and the BSIC (Base Station Identity Code) plus the frame number. Once you decode SCH, you know the absolute frame position and can schedule where BCCH bursts should appear.

Understanding burst types matters. The normal burst carries 114 data bits with a 26-bit training sequence, tail bits, and guard. The FCCH burst is a special case: a sequence of zeros that produces a constant frequency offset in the baseband. The SCH burst is another special case with a fixed training sequence. For BCCH decoding, you generally only need to demodulate normal bursts that carry the BCCH blocks, but you must still detect FCCH and SCH for timing. Without that timing, you cannot align interleaving across bursts, and the convolutional decoder will fail.

The 51-frame multiframe schedule is deterministic. BCCH uses specific frames (e.g., frame 2 in the multiframe for BCCH, with SCH and FCCH interleaved at fixed positions). The exact schedule depends on the network configuration, but the relative pattern of FCCH and SCH is fixed and is what you use for acquisition. A robust decoder builds a frame counter after SCH and then predicts when BCCH bursts should arrive. This is why timing accuracy matters: if you drift by even a few symbol periods, the burst boundaries blur and the training sequence correlation will degrade.

Another critical detail is that GSM bursts include guard times and use a known symbol rate of 270.833 ksym/s. This determines the samples-per-symbol ratio for a given IQ sample rate. If your sample rate is not an integer multiple of the symbol rate, you must resample. If you do not, you will not land on symbol boundaries and timing recovery will be unstable. Many SDR captures use 2.4 MSPS or 2.0 MSPS, which are not integer multiples of the GSM symbol rate, so resampling is essential. A proper understanding of the air interface lets you derive the exact resampling ratio and plan the DSP pipeline accordingly.

How this fits on projects

  • You will use ARFCN mapping and multiframe scheduling in Section 3.1, Section 3.5, and Section 4.1.
  • You will apply the FCCH/SCH timing plan in Section 5.10 Phase 1 and Phase 2.

Definitions & key terms

  • ARFCN: Absolute Radio Frequency Channel Number, maps to a GSM carrier frequency.
  • TDMA frame: 4.615 ms frame containing 8 time slots.
  • Time slot: 577 microseconds segment that carries a burst.
  • 51-frame multiframe: Control channel structure containing FCCH, SCH, BCCH, and CCCH.
  • BCCH: Broadcast Control Channel carrying System Information.

Mental model diagram (ASCII)

Carrier (ARFCN) -> TDMA frames -> 51-frame multiframe -> FCCH/SCH/BCCH bursts

How it works (step-by-step, with invariants and failure modes)

  1. Choose a GSM band and map ARFCN to downlink frequency.
  2. Capture IQ centered on that frequency at sufficient bandwidth.
  3. Detect FCCH bursts (pure tone) to estimate CFO and timing.
  4. Detect SCH bursts to decode frame number and BSIC.
  5. Build a multiframe counter and schedule BCCH burst extraction.

Invariants:

  • Symbol rate is 270.833 ksym/s.
  • FCCH and SCH appear at fixed positions in the 51-frame multiframe.

Failure modes:

  • Wrong band mapping yields incorrect tuning and no FCCH detection.
  • Timing drift causes BCCH bursts to be sliced incorrectly.

Minimal concrete example

# ARFCN to downlink frequency for GSM-900 (simplified)
def arfcn_to_freq_mhz(arfcn):
    return 935.0 + 0.2 * (arfcn - 1)

print(arfcn_to_freq_mhz(45))  # ~943.8 MHz

Common misconceptions

  • “GSM is continuous like FM.” It is bursty and time-structured.
  • “Any sample rate works.” You must match symbol timing via resampling.
  • “BCCH decoding does not need SCH.” It does, for timing and frame count.

Check-your-understanding questions

  1. What is the length of a GSM TDMA frame and how many time slots does it contain?
  2. Why are FCCH and SCH bursts needed before decoding BCCH?
  3. What does ARFCN represent in GSM?

Check-your-understanding answers

  1. A frame is 4.615 ms and contains 8 time slots.
  2. They provide frequency correction and absolute timing so BCCH bursts can be aligned.
  3. ARFCN is the channel number that maps to a specific carrier frequency.

Real-world applications

  • Network measurement tools and spectrum monitoring.
  • Cell planning verification and interference analysis.

Where you’ll apply it

  • This project: Section 3.1 (What You Will Build), Section 5.10 Phase 1.
  • Also used in: P04 ADS-B Decoder for burst detection concepts.

References

  • “The GSM System for Mobile Communications” by Mouly and Pautet, Chapters 2-4
  • 3GPP TS 45.002 (multiplexing and multiple access)

Key insights

GSM decoding begins with understanding time and frequency structure, not just demodulation.

Summary

You learned how GSM maps channels to frequencies, how TDMA frames organize bursts, and why FCCH/SCH are mandatory for BCCH decoding.

Homework/Exercises to practice the concept

  1. Compute the downlink frequency for ARFCN 62 in GSM-900.
  2. Sketch a 51-frame multiframe and mark FCCH and SCH positions.
  3. Calculate the duration of a single time slot in microseconds.

Solutions to the homework/exercises

  1. 935 + 0.2*(62-1) = 947.2 MHz.
  2. FCCH and SCH appear in fixed positions; mark frames 0 and 1 in the multiframe and repeat the pattern.
  3. 4.615 ms / 8 = 576.9 microseconds.

2.2 GMSK Demodulation and Burst Timing

Fundamentals

GSM uses GMSK (Gaussian Minimum Shift Keying), a continuous-phase frequency shift keying scheme. GMSK shapes the frequency transitions with a Gaussian filter (BT=0.3 in GSM) to reduce bandwidth and spectral splatter. For an SDR decoder, this means the baseband signal has a smoothly varying phase rather than sharp transitions. A common demodulation approach is to compute the instantaneous phase of the complex baseband signal and take its derivative; the sign of the phase change indicates the transmitted bit. However, because GSM is bursty, you must find the burst boundaries and align symbol timing before you can reliably sample. Training sequences inside each burst provide a known pattern you can correlate against to find the exact start and adjust timing.

Deep Dive into the Concept

GMSK can be viewed as MSK (minimum shift keying) filtered by a Gaussian filter. In MSK, the frequency deviation is exactly half the bit rate, creating orthogonal signals with continuous phase. GSM applies a Gaussian filter to limit bandwidth, which introduces intersymbol interference (ISI) but keeps spectral emissions within the 200 kHz channel. This is an intentional trade-off: the signal becomes harder to decode but stays within regulatory masks. A decoder must counteract this by using appropriate filtering and timing recovery.

In practice, a GSM receiver first converts the RF carrier to complex baseband and applies a channel filter, typically around 200 kHz. The next step is to remove any residual carrier frequency offset (CFO). CFO rotates the complex samples, which appears as an additional phase ramp that can overwhelm the true phase changes from GMSK. If you do not correct CFO, the discriminator output is biased and the symbol decisions will drift. FCCH provides a clean way to estimate CFO because it is a pure tone; you can measure its frequency offset and correct subsequent bursts.

After CFO correction, you demodulate GMSK by computing the complex phase difference between consecutive samples: angle(x[n] * conj(x[n-1])). This yields an instantaneous frequency estimate. You then low-pass filter and sample at the symbol rate to produce bits. However, the symbol rate is 270.833 ksym/s, and your sample rate is often not an integer multiple, so you must resample or use a timing recovery loop. A fractional resampler with a timing error detector (TED) and loop filter can align the sampling instants. For a simpler offline decoder, you can resample to an integer multiple (e.g., 1.083332 MSPS gives 4 samples per symbol) and then use a known offset to pick the best sampling phase.

Burst timing is the other half of the problem. GSM bursts begin with tail bits, then data and training sequence. The training sequence is known and differs by burst type. By correlating the demodulated soft bits with the expected training sequence, you can find the burst start and also refine timing. This correlation effectively acts as a matched filter. A robust approach is to slide a window over the demodulated samples, compute correlation against the training sequence, and pick the peak. The peak location provides the best alignment; the peak value provides a confidence measure.

Because GMSK is continuous-phase, the demodulated signal contains memory. This means naive hard slicing can perform poorly at low SNR. A better approach is to keep soft values (e.g., the discriminator output before slicing) and feed them into the Viterbi decoder later. Soft decisions improve error correction performance by several dB. This is why your demodulator should output soft bits or log-likelihood ratios rather than binary decisions. Even if you ultimately hard-slice for debugging, keep the soft pipeline in place.

Finally, you must handle burst edges. The guard time at the end of a burst can be noisy. If you include it in your correlation or decoding, you will introduce errors. The correct approach is to locate the burst boundaries precisely, then extract only the 148-symbol burst payload region. The correct alignment makes the difference between a clean decode and complete failure. This is one reason GSM is considered advanced: the demodulator and timing are tightly coupled to the channel coding stage.

How this fits on projects

  • You will implement GMSK demodulation in Section 5.4 and Section 5.10 Phase 2.
  • Burst timing logic feeds directly into the deinterleaver in Section 4.4 and Section 6.2.

Definitions & key terms

  • GMSK: Gaussian Minimum Shift Keying, continuous-phase FSK.
  • BT: Bandwidth-time product of the Gaussian filter (0.3 in GSM).
  • CFO: Carrier frequency offset.
  • Training sequence: Known bit pattern inside a burst for timing and channel estimation.
  • Soft decision: Demodulator output that preserves confidence, not just 0/1.

Mental model diagram (ASCII)

IQ -> CFO correction -> GMSK discriminator -> timing recovery -> training corr -> bits

How it works (step-by-step, with invariants and failure modes)

  1. Filter the baseband to ~200 kHz.
  2. Estimate CFO using FCCH and correct it.
  3. Compute phase difference to get instantaneous frequency.
  4. Resample or apply timing recovery to align symbol centers.
  5. Correlate with training sequence to align burst start.
  6. Extract 148 symbols and output soft bits.

Invariants:

  • Symbol rate is fixed at 270.833 ksym/s.
  • Training sequence location inside the burst is fixed.

Failure modes:

  • Poor CFO correction yields biased discriminator output.
  • Wrong timing leads to low correlation and Viterbi failure.

Minimal concrete example

# simple phase discriminator
phi = np.angle(samples[1:] * np.conj(samples[:-1]))
# low-pass filter phi to symbol rate, then slice

Common misconceptions

  • “GMSK is just FM.” It is continuous-phase FSK with shaped transitions.
  • “Training sequence is optional.” It is essential for timing and channel estimation.
  • “Hard slicing is fine.” Soft decisions greatly improve decode performance.

Check-your-understanding questions

  1. Why does GSM use a Gaussian filter in GMSK?
  2. What does the training sequence provide that raw data cannot?
  3. Why are soft decisions better for convolutional decoding?

Check-your-understanding answers

  1. To reduce spectral splatter and fit within the 200 kHz channel mask.
  2. A known pattern for timing alignment and channel estimation.
  3. They preserve confidence and improve Viterbi performance.

Real-world applications

  • GSM baseband receivers and measurement tools.
  • SDR-based compliance testing of GSM emissions.

Where you’ll apply it

  • This project: Section 4.4 (Algorithm Overview), Section 5.10 Phase 2.
  • Also used in: P06 AIS Decoder for burst timing concepts.

References

  • “Digital Communications” by Proakis, Chapters 4-6
  • 3GPP TS 45.004 (modulation)

Key insights

Accurate GMSK demodulation depends on CFO correction and precise burst timing.

Summary

You learned how GMSK encodes bits as continuous phase, why timing and training sequences matter, and how to output soft bits for decoding.

Homework/Exercises to practice the concept

  1. Simulate a GMSK signal and plot the phase trajectory.
  2. Implement a simple CFO estimator using a pure tone.
  3. Correlate a known training sequence inside noisy data and locate the peak.

Solutions to the homework/exercises

  1. The phase should change smoothly, never jumping abruptly between symbols.
  2. Estimate the tone frequency by unwrapping phase and fitting a slope.
  3. The correlation peak identifies the best alignment index.

2.3 Channel Coding, Interleaving, and BCCH Decoding

Fundamentals

GSM control channels are heavily protected by error correction because the radio environment is noisy and bursts can be lost. BCCH blocks begin with 184 information bits. A Fire code adds 40 parity bits, then tail bits are appended, and the result is convolutionally encoded at rate 1/2, producing 456 bits. These 456 coded bits are interleaved across four consecutive bursts. This means you cannot decode a single burst in isolation; you must collect and reorder bits from four bursts before running the Viterbi decoder. The decoder then outputs a corrected 184-bit block that can be parsed into System Information messages. Understanding this coding chain is essential, because most GSM decode failures are actually coding failures caused by timing or interleaving errors.

Deep Dive into the Concept

GSM channel coding is a layered process. For BCCH, the 184-bit information block is first protected by a Fire code (a cyclic redundancy code optimized for burst errors). The Fire code adds 40 parity bits, creating a 224-bit block, and then 4 tail bits are appended to terminate the convolutional encoder, resulting in 228 bits. This block is then passed through a rate-1/2 convolutional encoder with constraint length 5. The output is 456 coded bits. This convolutional coding provides strong forward error correction and is specifically designed to handle random errors typical of fading channels.

After convolutional encoding, the 456 bits are interleaved across four normal bursts. The interleaving pattern is fixed and deterministic: bits are distributed so that adjacent coded bits are separated in time, reducing the impact of burst errors or fades. This means the decoder must buffer four bursts, then deinterleave to recover the original coded bit order. If you misalign the burst boundaries or the multiframe schedule, the interleaver will assemble the wrong sequence, and the Viterbi decoder will output garbage. This is why accurate timing from FCCH/SCH is essential for BCCH decoding.

The Viterbi decoder is the standard algorithm for convolutional codes. It builds a trellis of possible states and chooses the most likely path based on the soft input metrics. Soft decisions improve decoding by providing more information than simple 0/1 bits. The output of the Viterbi decoder is the 228-bit sequence; you then remove the tail bits and verify the Fire code to confirm integrity. If the Fire code fails, you discard the block. This is a critical quality gate because a single bit error can corrupt the decoded System Information fields.

BCCH messages are organized into System Information types (SI1, SI2, SI3, SI4, etc.). Each has a specific bit layout. For example, SI3 contains MCC/MNC, LAC, cell identity, and cell selection parameters. Parsing these fields requires careful bit-level extraction according to the 3GPP specification. It is also common to see multiple SI messages repeated in the multiframe to improve reliability. A good decoder caches the latest valid SI blocks and reports them with timestamps.

A practical decoder should also support partial decoding. Even if you fail the Fire code on one block, you may succeed on another soon after. Because BCCH repeats, you can keep scanning and improve confidence over time. This is why you should structure your pipeline to continuously decode and update SI information rather than treat decoding as a one-shot event.

How this fits on projects

  • You will implement deinterleaving and Viterbi decoding in Section 4.4 and Section 5.10 Phase 3.
  • The error-checking pattern mirrors CRC usage in P04 ADS-B Decoder.

Definitions & key terms

  • Fire code: A cyclic error-detecting code optimized for burst errors.
  • Convolutional code: FEC code that encodes bits based on current and previous bits.
  • Viterbi decoder: Optimal decoder for convolutional codes.
  • Interleaving: Reordering of bits across time to spread errors.
  • Soft bits: Demodulator outputs representing confidence levels.

Mental model diagram (ASCII)

184 info bits -> Fire code -> conv encoder -> 456 bits -> interleave -> bursts
                                      ^
                                      |
                               Viterbi decode

How it works (step-by-step, with invariants and failure modes)

  1. Collect four consecutive bursts and extract their 114 data bits.
  2. Deinterleave to rebuild the 456 coded bit stream.
  3. Run Viterbi decoding with soft inputs.
  4. Remove tail bits and check Fire code parity.
  5. Parse SI fields if parity passes.

Invariants:

  • BCCH coding always yields 456 coded bits from 184 information bits.
  • Interleaving spans exactly four bursts.

Failure modes:

  • Incorrect burst alignment corrupts deinterleaving.
  • Hard decisions reduce Viterbi performance and increase errors.

Minimal concrete example

# toy deinterleaver example (8-bit demo for clarity)
interleave_map = [0, 4, 1, 5, 2, 6, 3, 7]
coded = np.zeros(8)
for i, bit in enumerate(burst_bits[:8]):
    coded[interleave_map[i]] = bit

Common misconceptions

  • “CRC is enough.” GSM uses both Fire code and convolutional coding.
  • “You can decode one burst.” BCCH requires four bursts due to interleaving.
  • “Hard slicing is fine.” Soft inputs dramatically improve Viterbi results.

Check-your-understanding questions

  1. How many bursts are needed to decode one BCCH block?
  2. Why is interleaving used in GSM?
  3. What is the role of the Fire code?

Check-your-understanding answers

  1. Four bursts, because the 456 coded bits are interleaved across them.
  2. To spread errors over time and improve correction effectiveness.
  3. It detects residual errors after convolutional decoding.

Real-world applications

  • Cellular measurement equipment and GSM protocol analyzers.
  • Research on legacy network behavior.

Where you’ll apply it

  • This project: Section 3.5 (Data Formats), Section 5.10 Phase 3, Section 6.2 (Critical Test Cases).
  • Also used in: P08 POCSAG Decoder for coding parallels.

References

  • 3GPP TS 45.003 (channel coding)
  • “Error Control Coding” by Lin and Costello, Chapters 11-12

Key insights

Correct interleaving and soft-decision decoding are the difference between total failure and stable SI output.

Summary

You learned the BCCH coding chain, why four bursts are required, and how Viterbi decoding and Fire codes protect GSM control data.

Homework/Exercises to practice the concept

  1. Implement a small convolutional encoder and verify Viterbi decoding on noisy bits.
  2. Create a toy interleaver and deinterleaver and verify round-trip recovery.
  3. Simulate a burst loss and observe how interleaving spreads the errors.

Solutions to the homework/exercises

  1. Use a constraint length 3 or 5 code and confirm zero errors at high SNR.
  2. Apply a known permutation and invert it; the sequence should match.
  3. The errors are distributed across the deinterleaved stream rather than clustered.

3. Project Specification

3.1 What You Will Build

A passive GSM BCCH decoder that takes captured IQ data (or a live SDR stream) and outputs decoded System Information for the strongest GSM carrier. The tool must detect FCCH/SCH for timing, demodulate GMSK bursts, decode BCCH blocks, and print or export structured cell information. It must not decode traffic channels and must not attempt decryption.

3.2 Functional Requirements

  1. Carrier Detection: Scan a band, detect GSM carriers, and select one ARFCN.
  2. Frequency Correction: Estimate and correct CFO using FCCH bursts.
  3. Timing Synchronization: Decode SCH to obtain frame number and BSIC.
  4. Burst Extraction: Extract normal bursts at predicted BCCH positions.
  5. Demodulation: Convert bursts to soft bit streams.
  6. Decoding: Deinterleave, Viterbi decode, and verify Fire code.
  7. Parsing: Decode SI messages (SI1, SI2, SI3 at minimum).
  8. Output: Print results and optionally save JSON output.

3.3 Non-Functional Requirements

  • Performance: Must decode at least one SI block per minute from a 2.0-2.4 MSPS capture on a laptop.
  • Reliability: Must reject invalid blocks (Fire code failure) without crashing.
  • Usability: CLI flags for band, frequency, sample rate, and input file.

3.4 Example Usage / Output

$ python gsm_bcch.py --iq gsm_900.iq --fs 2.4e6 --band gsm900
[GSM] ARFCN 45  | BSIC 0x12 | MCC/MNC 310/260 | LAC 0x03F2 | Cell ID 0x1A2B
[GSM] Neighbors: 42, 44, 49, 60

3.5 Data Formats / Schemas / Protocols

IQ Input (interleaved uint8 IQ):

I0 Q0 I1 Q1 I2 Q2 ...

Metadata (optional JSON):

{
  "fs": 2400000,
  "center_freq": 943800000,
  "format": "u8iq",
  "timestamp": "2025-12-31T12:00:00Z"
}

Decoded Output (JSON):

{
  "arfcn": 45,
  "band": "gsm900",
  "bsic": 18,
  "mcc": "310",
  "mnc": "260",
  "lac": "0x03F2",
  "cell_id": "0x1A2B",
  "neighbors": [42, 44, 49, 60],
  "si_types": [1, 2, 3],
  "confidence": 0.92
}

3.6 Edge Cases

  • Capture contains multiple carriers; choose the strongest but verify GSM structure.
  • CFO too large; FCCH detection may fail.
  • Sample rate mismatch; bursts drift over time.
  • SI blocks repeat; ensure deduplication rather than spamming output.

3.7 Real World Outcome

You will run the decoder on a recorded GSM capture. The output should show stable, repeated SI messages and consistent cell identity.

3.7.1 How to Run (Copy/Paste)

python gsm_bcch.py --iq samples/gsm900.iq --fs 2400000 --band gsm900 --out out.json

3.7.2 Golden Path Demo (Deterministic)

  • Use the provided samples/gsm900.iq capture and fixed options.
  • Expect the same ARFCN, BSIC, and SI fields every run.

3.7.3 CLI Transcript (Exact)

$ python gsm_bcch.py --iq samples/gsm900.iq --fs 2400000 --band gsm900
[GSM] ARFCN 45  | BSIC 0x12 | MCC/MNC 310/260 | LAC 0x03F2 | Cell ID 0x1A2B
[GSM] Neighbors: 42, 44, 49, 60
[OK] 3 SI blocks decoded in 8.2 s

3.7.4 Failure Demo (Bad Input)

$ python gsm_bcch.py --iq samples/noise.iq --fs 2400000 --band gsm900
[ERROR] No FCCH bursts detected. Check frequency, gain, or sample rate.
$ echo $?
2

4. Solution Architecture

4.1 High-Level Design

IQ Capture
   |
   v
[Band Scan] -> [FCCH Detector] -> [CFO Correction] -> [SCH Decoder]
   |                                    |
   v                                    v
[BCCH Scheduler] -> [Burst Extractor] -> [GMSK Demod] -> [Deinterleave+Viterbi]
   |
   v
[SI Parser] -> [CLI/JSON Output]

4.2 Key Components

Component Responsibility Key Decisions
Band Scanner Locate GSM carriers FFT size vs resolution
FCCH Detector Estimate CFO and timing Thresholding strategy
SCH Decoder Extract BSIC and frame number Training sequence correlation
Burst Extractor Slice burst samples Timing tolerance window
Demodulator Produce soft bits Discriminator vs matched filter
Decoder Deinterleave + Viterbi Soft vs hard inputs
Parser Extract SI fields SI type coverage

4.3 Data Structures (No Full Code)

struct Burst {
    float soft_bits[148];
    int frame_number;
    int timeslot;
};

struct SIInfo {
    int arfcn;
    int bsic;
    int mcc;
    int mnc;
    int lac;
    int cell_id;
    int neighbors[32];
    int neighbor_count;
};

4.4 Algorithm Overview

Key Algorithm: BCCH Decode Pipeline

  1. Scan spectrum to find GSM carriers.
  2. Detect FCCH to estimate CFO and align timing.
  3. Decode SCH to set frame counter and BSIC.
  4. Extract BCCH bursts on schedule.
  5. Demodulate to soft bits.
  6. Deinterleave and Viterbi decode.
  7. Verify Fire code and parse SI fields.

Complexity Analysis:

  • Time: O(N log N) for scanning + O(N) for burst processing
  • Space: O(N) for buffers and interleaver

5. Implementation Guide

5.1 Development Environment Setup

python3 -m venv .venv
source .venv/bin/activate
pip install numpy scipy

5.2 Project Structure

project-root/
+-- src/
|   +-- gsm_bcch.py
|   +-- demod.py
|   +-- viterbi.py
|   +-- si_parser.py
+-- tests/
|   +-- test_viterbi.py
|   +-- test_interleave.py
+-- samples/
|   +-- gsm900.iq
+-- README.md

5.3 The Core Question You’re Answering

“How do you turn short, bursty GSM signals into reliable system information without decrypting any traffic?”

5.4 Concepts You Must Understand First

Stop and research these before coding:

  1. TDMA framing and multiframe schedule
    • What is a 51-frame multiframe and why does BCCH repeat?
  2. GMSK demodulation basics
    • How does phase difference map to bits?
  3. Convolutional coding and Viterbi
    • Why do soft decisions improve reliability?

5.5 Questions to Guide Your Design

  1. How will you detect FCCH reliably in noise?
  2. How will you choose resampling ratio for symbol alignment?
  3. Where will you store bursts while waiting for interleaving?

5.6 Thinking Exercise

Sketch a 51-frame multiframe and label FCCH, SCH, and BCCH positions. Then mark which four bursts you must collect to decode one BCCH block.

5.7 The Interview Questions They’ll Ask

  1. Why is FCCH used before SCH?
  2. What is the role of the training sequence in GSM bursts?
  3. Why is interleaving necessary for BCCH?

5.8 Hints in Layers

  1. Start by detecting the FCCH tone via FFT peak tracking.
  2. Use SCH correlation to establish frame count and BSIC.
  3. Store four bursts before you attempt Viterbi decode.
  4. Only accept SI blocks with valid Fire code parity.

5.9 Books That Will Help

Topic Book Chapter
GSM air interface “The GSM System for Mobile Communications” Ch. 2-4
Coding theory “Error Control Coding” (Lin, Costello) Ch. 11
DSP fundamentals “Understanding Digital Signal Processing” (Lyons) Ch. 5-6

5.10 Implementation Phases

Phase 1: Acquisition and FCCH Detection (1-2 weeks)

Goals:

  • Detect GSM carriers and FCCH bursts.
  • Estimate CFO and correct it.

Tasks:

  1. Implement FFT-based scan to find strong 200 kHz carriers.
  2. Detect FCCH by searching for a narrowband tone.
  3. Apply CFO correction to a buffered IQ stream.

Checkpoint: You can see stable FCCH detections every multiframe.

Phase 2: Timing + SCH Decode (1-2 weeks)

Goals:

  • Decode SCH to obtain frame number and BSIC.
  • Align burst timing to slot boundaries.

Tasks:

  1. Implement training sequence correlation for SCH.
  2. Extract SCH payload bits and verify parity.
  3. Build a frame counter and schedule BCCH bursts.

Checkpoint: You can predict BCCH burst positions within 1-2 symbols.

Phase 3: BCCH Decode and Parsing (1-2 weeks)

Goals:

  • Demodulate bursts into soft bits.
  • Deinterleave, Viterbi decode, and parse SI blocks.

Tasks:

  1. Build a GMSK demodulator and soft-bit pipeline.
  2. Implement deinterleaver and Viterbi decoder.
  3. Parse SI3 fields and print cell ID, MCC, MNC, LAC.

Checkpoint: You decode SI3 consistently with valid Fire code.

5.11 Key Implementation Decisions

Decision Options Recommendation Rationale
Demod method phase diff vs matched filter phase diff Simpler and works for offline decoding
Sample rate 2.0 vs 2.4 MSPS 2.4 MSPS Higher oversampling improves timing recovery
Decoder input hard vs soft soft Better Viterbi performance

6. Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Tests Verify math blocks Viterbi on known codewords
Integration Tests End-to-end decode Known GSM capture with expected SI
Edge Case Tests Handle failures Noise-only capture

6.2 Critical Test Cases

  1. FCCH Detection: Detect a pure tone embedded in noise at -15 dB SNR.
  2. Viterbi Decode: Recover a known BCCH block with 2% bit flips.
  3. SI Parsing: Extract MCC/MNC and verify against expected values.

6.3 Test Data

FCCH tone IQ, SCH burst IQ, BCCH burst IQ, noise-only IQ

7. Common Pitfalls & Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Wrong band No FCCH detected Verify ARFCN mapping and band
Bad timing Viterbi fails Re-check SCH timing and burst alignment
Hard slicing High error rate Use soft decisions into Viterbi

7.2 Debugging Strategies

  • FFT Snapshot: Confirm a 200 kHz-wide carrier with strong center.
  • Training Correlation Plot: Visualize SCH correlation peaks.
  • Soft-Bit Histogram: Validate discriminator output distribution.

7.3 Performance Traps

  • Large FFT sizes slow scanning without improving detection.
  • Excessive averaging hides short bursts.

8. Extensions & Challenges

8.1 Beginner Extensions

  • Add a CSV output with decoded SI fields.
  • Plot FCCH frequency offset over time.

8.2 Intermediate Extensions

  • Decode SI2 neighbor list with ARFCN mapping.
  • Implement basic AFC loop to track CFO drift.

8.3 Advanced Extensions

  • Add support for GSM-1800 band.
  • Build a live streaming mode with ring buffers.

9. Real-World Connections

9.1 Industry Applications

  • Cellular measurement equipment for coverage verification.
  • RF compliance and interference investigations.
  • gr-gsm: GNU Radio GSM receiver stack.
  • osmocom-bb: Legacy GSM baseband research project.

9.3 Interview Relevance

  • TDMA systems and burst timing.
  • Convolutional decoding and Viterbi implementation.

10. Resources

10.1 Essential Reading

  • “The GSM System for Mobile Communications” by Mouly and Pautet (Air interface chapters)
  • 3GPP TS 45.002 and TS 45.003 for framing and coding

10.2 Video Resources

  • GSM signal processing lectures (university DSP courses)
  • SDR demodulation tutorials for GMSK

10.3 Tools & Documentation

  • rtl-sdr: IQ capture utilities
  • numpy/scipy: DSP computations

11. Self-Assessment Checklist

11.1 Understanding

  • I can explain the GSM TDMA frame and multiframe structure.
  • I can describe how FCCH and SCH enable synchronization.
  • I can explain why BCCH decoding needs deinterleaving.

11.2 Implementation

  • FCCH detection and CFO correction work reliably.
  • SCH decode yields stable BSIC and frame count.
  • BCCH blocks decode with valid Fire code.

11.3 Growth

  • I documented errors and how I fixed them.
  • I can explain this project in an interview.

12. Submission / Completion Criteria

Minimum Viable Completion:

  • Detect FCCH and decode SCH in a recorded capture.
  • Decode at least one SI3 block with valid Fire code.
  • Output MCC/MNC, LAC, and Cell ID.

Full Completion:

  • Decode SI1, SI2, and SI3 repeatedly for 5 minutes.
  • Output neighbor list and confidence metrics.

Excellence (Going Above & Beyond):

  • Live decoding with AFC loop and drift tracking.
  • Support multiple bands and carriers.