Skip to content

Commit e135764

Browse files
secupclaude
andcommitted
Add 500 Hz narrowband OFDM mode (OFDM_NARROW) for low-SNR operation
Adds a 500 Hz narrowband OFDM mode that provides ~7.5 dB noise bandwidth advantage over wideband, enabling reliable communication at SNR 5-10 dB where wideband fails. The entire session stays within 500 Hz. - FFT=2048, 21 carriers, 23.4 Hz bin spacing, 492 Hz occupied BW - Narrowband chirp sync (1250-1750 Hz, 1000ms) + MC-DPSK handshake (4 carriers) - Dual-listen: RX detects both wideband and narrowband chirps when idle - ARQ window=1 (stop-and-wait) with ~7s timeout for long frame times - LTS threshold lowered to 0.50 for narrowband (fewer carriers = weaker correlation) - isOFDMMode() helper unifies OFDM_CHIRP/OFDM_COX/OFDM_NARROW checks - ~103 bps (R1/4) to ~230 bps (R1/2), 10x slower but works where wideband cannot - Tested: AWGN SNR=8 100%, good fading SNR=8 100% data + all messages delivered Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent be87252 commit e135764

22 files changed

+445
-84
lines changed

CLAUDE.md

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,25 @@
7474
- **Preamble:** Light preamble (LTS only) for data after handshake
7575
- **Key files:** `decodeFixedFrame()` in frame_v2.cpp
7676

77+
### Mode 3: OFDM_NARROW (SNR 5-10 dB, 500 Hz bandwidth)
78+
- **When:** Narrowband chirp detected (1250-1750 Hz), low SNR where wideband fails
79+
- **Waveform:** OFDM with narrowband chirp sync, FFT=2048, 21 carriers, 492 Hz BW
80+
- **ARQ:** Stop-and-wait (window=1) - same as MC-DPSK due to long frame times (~3s)
81+
- **Frame format:** Same as wideband OFDM (4 CW data, 1 CW control)
82+
- **Interleaving:** Frame-level + optional channel interleaving (same as OFDM)
83+
- **Preamble:** Light preamble (LTS only) for data after handshake
84+
- **Dual-listen:** RX listens for both wideband AND narrowband chirps when idle
85+
- **Throughput:** ~103 bps (R1/4) to ~230 bps (R1/2) — 10× slower than wideband but works at 7.5 dB lower SNR
86+
7787
### Mode Selection Flow
78-
1. **Connection starts:** Always MC-DPSK for PING/PONG/CONNECT
79-
2. **After CONNECT_ACK:** SNR is measured, mode is negotiated
80-
- SNR < 10: Stay in MC-DPSK
81-
- SNR ≥ 10: Switch to OFDM
82-
3. **enterConnected():** Sets ARQ window based on mode (1 vs 4)
83-
4. **StreamingEncoder/Decoder:** Check `mode_` to use correct path
88+
1. **Connection starts:** MC-DPSK for PING/PONG/CONNECT (wideband or narrowband chirp)
89+
2. **Dual-listen:** RX detects chirp type → sets BandwidthMode (WIDE or NARROW)
90+
3. **After CONNECT_ACK:** SNR is measured, mode is negotiated
91+
- SNR < 10 + wideband: Stay in MC-DPSK
92+
- SNR ≥ 10 + wideband: Switch to OFDM_CHIRP
93+
- Narrowband detected: Switch to OFDM_NARROW
94+
4. **enterConnected():** Sets ARQ window based on mode (1 for MC-DPSK/NARROW, 4 for wideband OFDM)
95+
5. **StreamingEncoder/Decoder:** Check `mode_` to use correct path, `isOFDMMode()` for OFDM family
8496

8597
### NEVER MIX THESE:
8698
- MC-DPSK frames through OFDM encoder (corrupts control frames)
@@ -98,8 +110,10 @@
98110
| OFDM_CHIRP | AWGN | 15+ | 100% |
99111
| OFDM_CHIRP | Good fading | 15 | **100%** |
100112
| OFDM_CHIRP | Moderate fading | 15 | ~90% |
113+
| OFDM_NARROW | AWGN | 8+ | 100% |
114+
| OFDM_NARROW | Good fading | 8 | 100% data, 90%+ ACK |
101115

102-
**Current state (2026-02-11):**
116+
**Current state (2026-03-01):**
103117
- MC-DPSK: WORKING - 100% at SNR=10 with moderate fading
104118
- OFDM_CHIRP DQPSK R1/4 AWGN: WORKING - 100% at SNR=15 and SNR=20 (0 retries)
105119
- OFDM_CHIRP DQPSK R1/4 Good fading SNR=15: WORKING - 100% (0 retries, 0 failures)
@@ -118,6 +132,8 @@
118132
- OFDM_CHIRP DQPSK R3/4 Good fading: NOT RECOMMENDED (23 retx / 5 seeds — AWGN only)
119133
- 1-CW ACK frames: WORKING - control frames use 1 CW (3x faster ACK)
120134
- Variable-CW frames: WORKING - CONNECT/DISCONNECT use exact CW count (2 at R1/2, 3 at R1/4)
135+
- OFDM_NARROW DQPSK R1/4 AWGN: WORKING - 100% at SNR=8 (0 retransmissions)
136+
- OFDM_NARROW DQPSK R1/4 Good fading SNR=8: WORKING - 100% data decode, 93% ACK, all messages delivered via ARQ
121137
- OFDM_COX: WORKING - DATA phase passes at SNR=20 dB
122138
- OTFS: EXPERIMENTAL - See OTFS Status section below
123139
- cli_simulator: FULLY WORKING - all phases pass on AWGN and fading
@@ -300,13 +316,15 @@ make -j4
300316
| Mode | Sync Method | SNR Range | Max Throughput | CFO Tolerance | Fading |
301317
|------|-------------|-----------|----------------|---------------|--------|
302318
| **MC-DPSK** | Dual Chirp | -3 to 10 dB | 938 bps | ±50 Hz | Good |
319+
| **OFDM_NARROW** | NB Chirp + LTS | 5-10 dB | ~230 bps | ±50 Hz | Good (R1/4) |
303320
| **OFDM_CHIRP** | Dual Chirp + LTS | 10-17 dB | 3.4 kbps | ±50 Hz | Good (R1/4) |
304321
| **OFDM_COX** | Schmidl-Cox | 17+ dB | 7.9 kbps | Needs testing | Poor |
305322
| **OTFS** | Dual Chirp | 15+ dB | ~2 kbps | ±50 Hz | **Poor** (experimental) |
306323
| **SC-DPSK** | Barker-13 | -8 to -3 dB | 125 bps | N/A | Good |
307324

308325
**Waveform Selection:**
309326
- Poor HF channels (2ms delay): Use MC-DPSK
327+
- Low SNR (5-10 dB) with good/moderate fading: Use OFDM_NARROW (~103 bps R1/4, ~230 bps R1/2)
310328
- Moderate/Good HF: Use OFDM_CHIRP (10-17 dB) or OFDM_COX (17+ dB)
311329
- Very low SNR: Use SC-DPSK or MC-DPSK
312330
- **DO NOT use OTFS on fading channels** - it's experimental and underperforms OFDM_CHIRP

docs/CHANGELOG.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,64 @@ This log tracks all bug fixes and behavioral changes to prevent re-doing work du
1010

1111
---
1212

13+
## 2026-03-01: Add OFDM_NARROW 500 Hz narrowband mode
14+
15+
**What was added:**
16+
New 500 Hz narrowband OFDM mode (OFDM_NARROW) for reliable operation at much lower SNR than wideband.
17+
Provides ~7.5 dB noise bandwidth advantage, enabling communication at SNR 5-10 dB where wideband fails.
18+
19+
**Key parameters:**
20+
- FFT=2048, 21 carriers, 23.4 Hz bin spacing, 492 Hz occupied bandwidth
21+
- Narrowband chirp: 1250-1750 Hz sweep, 1000ms duration
22+
- Narrowband MC-DPSK handshake: 4 carriers @ 1300-1700 Hz
23+
- Symbol duration: 46.7ms (2240 samples), CP=192 samples (MEDIUM)
24+
- ARQ: window=1 (stop-and-wait), timeout ~7.16s
25+
- Pilots: 0 for R1/4 (21 data carriers), 3 for R1/2+ (18 data carriers)
26+
27+
**Files changed:**
28+
- `include/ultra/types.hpp` - BandwidthMode enum, chirp fields in ModemConfig, narrowband presets
29+
- `src/protocol/frame_v2.hpp/.cpp` - WaveformMode::OFDM_NARROW (0x06), isOFDMMode() helper
30+
- `src/psk/multi_carrier_dpsk.hpp` - mc_dpsk_presets::narrowband() (4 carriers, 1300-1700 Hz)
31+
- `src/waveform/ofdm_chirp_waveform.hpp/.cpp` - Config-driven chirp parameters, mode_ field
32+
- `src/waveform/waveform_factory.hpp/.cpp` - OFDM_NARROW creation, createNarrowbandMCDPSK()
33+
- `src/protocol/waveform_selection.hpp` - SNR 5-10 recommends OFDM_NARROW
34+
- `src/gui/modem/streaming_decoder.cpp` - Dual-listen (wideband + narrowband chirps), narrowband LTS thresholds
35+
- `src/gui/modem/streaming_encoder.hpp/.cpp` - narrowband_control_ flag, narrowband MC-DPSK persistence
36+
- `src/gui/modem/modem_engine.cpp` - bandwidth_mode_ propagation, OFDM_NARROW in mode checks
37+
- `src/protocol/connection.cpp/.cpp` - isOFDMMode() throughout, OFDM_NARROW timing
38+
- `tools/cli_simulator.cpp` - --waveform ofdm_narrow, dual-listen, extended narrowband timeouts
39+
- `src/main.cpp`, `src/gui/app.cpp` - CLI and GUI support
40+
41+
**Key design decisions:**
42+
1. Dual-listen: RX always listens for both wideband and narrowband chirps when idle
43+
2. Narrowband chirp auto-identifies the mode — no manual pre-agreement needed
44+
3. narrowband_control_ flag persists across encoder mode switches during handshake
45+
4. LTS threshold lowered to 0.50 for narrowband (21 carriers produce ~0.71 correlation vs 59-carrier ~0.95)
46+
5. Legacy (wide-only) stations won't detect narrowband chirps → caller sees normal PING timeout
47+
48+
**Verification:**
49+
```
50+
# AWGN
51+
./build/cli_simulator --snr 8 --waveform ofdm_narrow --rate r1_4 --test
52+
# → TEST PASSED: 100% frame success, 0 retransmissions
53+
54+
# Good fading
55+
./build/cli_simulator --snr 8 --fading good --waveform ofdm_narrow --rate r1_4 --test
56+
# → TEST PASSED: 100% RX frame success, 92.9% TX (ACK loss), all 7 messages delivered via ARQ
57+
58+
# Wideband regression
59+
./build/cli_simulator --snr 15 --fading good --rate r1_4 --test
60+
# → TEST PASSED: 100% frame success, 0 retransmissions (no regression)
61+
```
62+
63+
**Performance:**
64+
| Condition | Rate | Frame Success | Throughput |
65+
|-----------|------|--------------|------------|
66+
| AWGN SNR=8 | R1/4 | 100% | ~103 bps |
67+
| Good fading SNR=8 | R1/4 | 100% (data), 93% (ACK) | ~60 bps (with retx) |
68+
69+
---
70+
1371
## 2026-02-11: Alpha gate harness + OFDM SR-ARQ window stabilization
1472

1573
**What was broken:**

include/ultra/types.hpp

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,40 @@ struct PilotConfig {
139139
return total_carriers - num_pilots;
140140
}
141141

142-
// Create pilot config for a given code rate (59 carriers)
143-
// R1/4: 0 pilots, max data, LDPC handles fading
144-
// R1/2, R2/3: 6 pilots every ~10 carriers for per-symbol tracking
145-
// R3/4: 4 pilots every ~15 carriers for light fading/AWGN
142+
// Create pilot config for a given code rate
143+
// For wideband (59 carriers):
144+
// R1/4: 0 pilots, max data, LDPC handles fading
145+
// R1/2, R2/3: 6 pilots every ~10 carriers for per-symbol tracking
146+
// R3/4: 4 pilots every ~15 carriers for light fading/AWGN
147+
// For narrowband (≤25 carriers):
148+
// R1/4: 0 pilots (all 21 carriers are data)
149+
// R1/2+: 3 pilots at {0, N/3, 2N/3} (18 data carriers)
146150
static PilotConfig forCodeRate(CodeRate rate, int num_carriers = 59) {
147151
PilotConfig cfg;
148152

153+
// Narrowband: fewer carriers need different pilot layout
154+
if (num_carriers <= 25) {
155+
switch (rate) {
156+
case CodeRate::R1_4:
157+
case CodeRate::R1_3:
158+
default:
159+
// 0 pilots - all carriers data, LDPC handles fading
160+
cfg.num_pilots = 0;
161+
cfg.pilot_indices.clear();
162+
break;
163+
164+
case CodeRate::R1_2:
165+
case CodeRate::R2_3:
166+
case CodeRate::R3_4:
167+
// 3 pilots evenly spaced across narrowband carriers
168+
cfg.num_pilots = 3;
169+
cfg.pilot_indices = {0, num_carriers / 3, 2 * num_carriers / 3};
170+
break;
171+
}
172+
return cfg;
173+
}
174+
175+
// Wideband (59 carriers)
149176
switch (rate) {
150177
case CodeRate::R3_4:
151178
// 4 pilots for light fading/AWGN - every 15th carrier
@@ -181,6 +208,12 @@ struct PilotConfig {
181208
}
182209
};
183210

211+
// Bandwidth mode for narrowband vs wideband operation
212+
enum class BandwidthMode : uint8_t {
213+
WIDE = 0, // Standard 2.8 kHz bandwidth (59 carriers)
214+
NARROW = 1, // 500 Hz narrowband (21 carriers, FFT=2048)
215+
};
216+
184217
// Channel quality estimate
185218
struct ChannelQuality {
186219
float snr_db; // Estimated SNR in dB
@@ -234,6 +267,12 @@ struct ModemConfig {
234267
// Default 40x gives RMS ~0.4, matching chirp amplitude ~0.5
235268
float output_scale = 40.0f;
236269

270+
// Chirp sync parameters (wideband defaults, backward compatible)
271+
// Narrowband mode overrides these to 1250-1750 Hz @ 1000ms
272+
float chirp_f_start = 300.0f; // Chirp start frequency (Hz)
273+
float chirp_f_end = 2700.0f; // Chirp end frequency (Hz)
274+
float chirp_duration_ms = 500.0f; // Chirp duration (ms)
275+
237276
// Simulation: TX carrier frequency offset (Hz)
238277
// Simulates radio tuning error - shifts ALL frequencies by this amount
239278
// Default 0 = no CFO. Set to e.g. ±20 Hz for testing CFO tolerance.
@@ -384,6 +423,39 @@ inline ModemConfig high_speed() {
384423
return cfg;
385424
}
386425

426+
// Narrowband OFDM: 500 Hz bandwidth, FFT=2048, 21 carriers
427+
// 7.5 dB noise bandwidth advantage over wideband (2.8 kHz)
428+
// For low-SNR conditions (3-10 dB) where wideband doesn't work
429+
inline ModemConfig narrowbandOFDM() {
430+
ModemConfig cfg;
431+
cfg.fft_size = 2048; // 23.4 Hz bin spacing
432+
cfg.num_carriers = 21; // 492 Hz occupied bandwidth
433+
cfg.sample_rate = 48000;
434+
cfg.center_freq = 1500;
435+
cfg.cp_mode = CyclicPrefixMode::MEDIUM; // 192 samples = 4.0ms at 2048 FFT
436+
cfg.modulation = Modulation::DQPSK; // Differential for fading
437+
cfg.code_rate = CodeRate::R1_4; // Most robust
438+
cfg.use_pilots = true;
439+
cfg.pilot_spacing = 10; // Will be adjusted by PilotConfig
440+
cfg.chirp_f_start = 1250.0f; // Narrowband chirp: 1250-1750 Hz
441+
cfg.chirp_f_end = 1750.0f;
442+
cfg.chirp_duration_ms = 1000.0f; // 1000ms for processing gain
443+
cfg.speed_profile = SpeedProfile::CONSERVATIVE;
444+
return cfg;
445+
}
446+
447+
// Narrowband MC-DPSK: 4 carriers @ 1300-1700 Hz
448+
// Used for PING/PONG/CONNECT handshake in narrowband sessions
449+
inline ModemConfig narrowbandMCDPSK() {
450+
ModemConfig cfg;
451+
cfg.sample_rate = 48000;
452+
cfg.center_freq = 1500;
453+
cfg.chirp_f_start = 1250.0f; // Narrowband chirp
454+
cfg.chirp_f_end = 1750.0f;
455+
cfg.chirp_duration_ms = 1000.0f;
456+
return cfg;
457+
}
458+
387459
// Get config for given speed profile
388460
inline ModemConfig forProfile(SpeedProfile profile) {
389461
switch (profile) {

src/gui/app.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ static const char* waveformDisplayName(protocol::WaveformMode mode) {
192192
case protocol::WaveformMode::MFSK: return "MFSK";
193193
case protocol::WaveformMode::OTFS_EQ:
194194
case protocol::WaveformMode::OTFS_RAW: return "OTFS";
195+
case protocol::WaveformMode::OFDM_NARROW: return "OFDM Narrow";
195196
case protocol::WaveformMode::OFDM_CHIRP:
196197
case protocol::WaveformMode::OFDM_COX:
197198
default: return "OFDM";
@@ -563,6 +564,7 @@ App::App(const Options& opts) : options_(opts), sim_ui_visible_(opts.enable_sim)
563564
case protocol::WaveformMode::OTFS_EQ: mode_name = "OTFS"; break;
564565
case protocol::WaveformMode::OTFS_RAW: mode_name = "OTFS"; break;
565566
case protocol::WaveformMode::OFDM_CHIRP: mode_name = "OFDM"; break;
567+
case protocol::WaveformMode::OFDM_NARROW: mode_name = "OFDM Narrow"; break;
566568
case protocol::WaveformMode::OFDM_COX: mode_name = "OFDM"; break;
567569
default: mode_name = "OFDM"; break;
568570
}

src/gui/modem/modem_engine.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ ModemEngine::ModemEngine() {
9494

9595
startupTrace("ModemEngine", "decoder-set-ping-callback-enter");
9696
streaming_decoder_->setPingCallback([this](float snr_db, float cfo_hz) {
97+
// If narrowband chirp detected, switch control waveform for PONG/CONNECT_ACK
98+
if (streaming_decoder_->getDetectedBandwidth() == BandwidthMode::NARROW) {
99+
if (streaming_encoder_) {
100+
streaming_encoder_->setNarrowbandControl(true);
101+
}
102+
LOG_MODEM(INFO, "Narrowband chirp detected, switching control waveform");
103+
}
97104
if (ping_received_callback_) {
98105
ping_received_callback_(snr_db);
99106
}
@@ -165,9 +172,7 @@ void ModemEngine::setConfig(const ModemConfig& config) {
165172

166173
// Propagate OFDM config to StreamingDecoder for OFDM modes
167174
// This allows custom FFT/carrier settings (like NVIS mode with 1024 FFT)
168-
if (streaming_decoder_ &&
169-
(waveform_mode_ == protocol::WaveformMode::OFDM_COX ||
170-
waveform_mode_ == protocol::WaveformMode::OFDM_CHIRP)) {
175+
if (streaming_decoder_ && protocol::isOFDMMode(waveform_mode_)) {
171176
streaming_decoder_->setOFDMConfig(config_);
172177
LOG_MODEM(INFO, "setConfig: StreamingDecoder OFDM config updated (FFT=%d, carriers=%d)",
173178
config_.fft_size, config_.num_carriers);
@@ -268,8 +273,7 @@ std::vector<float> ModemEngine::transmit(const Bytes& data) {
268273
LOG_MODEM(INFO, "[%s] TX: Connected+handshake -> waveform_mode_=%d",
269274
log_prefix_.c_str(), static_cast<int>(tx_waveform_mode));
270275
}
271-
bool is_ofdm = (tx_waveform_mode == protocol::WaveformMode::OFDM_CHIRP ||
272-
tx_waveform_mode == protocol::WaveformMode::OFDM_COX);
276+
bool is_ofdm = protocol::isOFDMMode(tx_waveform_mode);
273277

274278
// ========================================================================
275279
// 2. Determine modulation and code rate

src/gui/modem/modem_mode.cpp

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,15 @@ void ModemEngine::setWaveformMode(protocol::WaveformMode mode) {
5050
// When disconnected, always use MC_DPSK for PING detection (chirp-based sync)
5151
if (streaming_decoder_) {
5252
protocol::WaveformMode decoder_mode = connected_ ? mode : protocol::WaveformMode::MC_DPSK;
53-
if (connected_ &&
54-
(mode == protocol::WaveformMode::OFDM_COX ||
55-
mode == protocol::WaveformMode::OFDM_CHIRP)) {
53+
if (connected_ && protocol::isOFDMMode(mode)) {
5654
streaming_decoder_->setConnectedOFDMMode(mode, config_, data_modulation_, data_code_rate_);
5755
LOG_MODEM(INFO, "setWaveformMode: StreamingDecoder connected OFDM config set (FFT=%d, carriers=%d)",
5856
config_.fft_size, config_.num_carriers);
5957
} else {
6058
streaming_decoder_->setMode(decoder_mode, connected_);
6159

6260
// For OFDM modes, propagate the current config (for custom FFT/carriers like NVIS mode)
63-
if (mode == protocol::WaveformMode::OFDM_COX ||
64-
mode == protocol::WaveformMode::OFDM_CHIRP) {
61+
if (protocol::isOFDMMode(mode)) {
6562
streaming_decoder_->setOFDMConfig(config_);
6663
LOG_MODEM(INFO, "setWaveformMode: StreamingDecoder OFDM config set (FFT=%d, carriers=%d)",
6764
config_.fft_size, config_.num_carriers);
@@ -72,8 +69,7 @@ void ModemEngine::setWaveformMode(protocol::WaveformMode mode) {
7269
// Update StreamingEncoder to match
7370
if (streaming_encoder_) {
7471
streaming_encoder_->setMode(mode);
75-
if (mode == protocol::WaveformMode::OFDM_COX ||
76-
mode == protocol::WaveformMode::OFDM_CHIRP) {
72+
if (protocol::isOFDMMode(mode)) {
7773
streaming_encoder_->setOFDMConfig(config_);
7874
}
7975
}
@@ -91,6 +87,11 @@ void ModemEngine::setWaveformMode(protocol::WaveformMode mode) {
9187
config_.num_carriers);
9288
break;
9389

90+
case protocol::WaveformMode::OFDM_NARROW:
91+
LOG_MODEM(INFO, "OFDM_NARROW mode active: %d carriers, 500 Hz narrowband",
92+
config_.num_carriers);
93+
break;
94+
9495
case protocol::WaveformMode::OFDM_COX:
9596
default:
9697
LOG_MODEM(INFO, "OFDM mode active: %d carriers, %s",
@@ -147,8 +148,7 @@ void ModemEngine::setConnected(bool connected) {
147148
streaming_decoder_->setMode(waveform_mode_, true); // true = connected
148149

149150
// For OFDM modes, propagate the correct config (with proper pilot settings)
150-
if (waveform_mode_ == protocol::WaveformMode::OFDM_COX ||
151-
waveform_mode_ == protocol::WaveformMode::OFDM_CHIRP) {
151+
if (protocol::isOFDMMode(waveform_mode_)) {
152152
streaming_decoder_->setConnectedOFDMMode(
153153
waveform_mode_, config_, data_modulation_, data_code_rate_);
154154
}
@@ -164,8 +164,7 @@ void ModemEngine::setConnected(bool connected) {
164164
// Update StreamingEncoder for connected state
165165
if (streaming_encoder_) {
166166
streaming_encoder_->setMode(waveform_mode_);
167-
if (waveform_mode_ == protocol::WaveformMode::OFDM_COX ||
168-
waveform_mode_ == protocol::WaveformMode::OFDM_CHIRP) {
167+
if (protocol::isOFDMMode(waveform_mode_)) {
169168
streaming_encoder_->setOFDMConfig(config_);
170169
streaming_encoder_->setDataMode(data_modulation_, data_code_rate_);
171170
}
@@ -232,9 +231,7 @@ void ModemEngine::setDataMode(Modulation mod, CodeRate rate) {
232231
// Update StreamingDecoder's waveform configuration
233232
// CRITICAL: Set OFDM config BEFORE setDataMode so decoder has correct pilot layout
234233
if (streaming_decoder_) {
235-
if (connected_ &&
236-
(waveform_mode_ == protocol::WaveformMode::OFDM_CHIRP ||
237-
waveform_mode_ == protocol::WaveformMode::OFDM_COX)) {
234+
if (connected_ && protocol::isOFDMMode(waveform_mode_)) {
238235
streaming_decoder_->setConnectedOFDMMode(
239236
waveform_mode_, config_, mod, rate);
240237
} else {
@@ -350,6 +347,7 @@ fec::CodecType ModemEngine::getCodecForWaveform(protocol::WaveformMode mode) {
350347
return fec::CodecType::LDPC;
351348

352349
case protocol::WaveformMode::OFDM_CHIRP:
350+
case protocol::WaveformMode::OFDM_NARROW:
353351
case protocol::WaveformMode::OFDM_COX:
354352
default:
355353
return fec::CodecType::LDPC;

0 commit comments

Comments
 (0)