diff --git a/include/encoder/Interleaver.h b/include/encoder/Interleaver.h index 40d8296..14fab73 100644 --- a/include/encoder/Interleaver.h +++ b/include/encoder/Interleaver.h @@ -180,7 +180,10 @@ private: * @brief Sets the matrix dimensions based on baud rate and interleave setting. */ void setMatrixDimensions() { - if (baud_rate == 2400) { + if (baud_rate == 4800) { + rows = 0; + columns = 0; + } else if (baud_rate == 2400) { rows = 40; columns = (interleave_setting == 2) ? 576 : 72; } else if (baud_rate == 1200) { diff --git a/include/encoder/ModemController.h b/include/encoder/ModemController.h index 2e070ca..c572d69 100644 --- a/include/encoder/ModemController.h +++ b/include/encoder/ModemController.h @@ -51,7 +51,7 @@ public: interleaver(baud_rate, interleave_setting, is_frequency_hopping), input_data(std::move(_data)), mgd_decoder(baud_rate, is_frequency_hopping), - modulator(baud_rate, 48000, 0.5, is_frequency_hopping) {} + modulator(baud_rate, 48000, is_frequency_hopping) {} /** * @brief Transmits the input data by processing it through different phases like FEC encoding, interleaving, symbol formation, scrambling, and modulation. @@ -72,12 +72,13 @@ public: // Step 3: Interleaving processed_data = interleaver.interleaveStream(fec_encoded_data); } - + // Step 4: MGD Decoding std::vector mgd_decoded_data = mgd_decoder.mgdDecode(processed_data); - // Step 4: Symbol Formation. This function injects the sync preamble symbols. Scrambling is built-in. + // Step 5: Symbol Formation. This function injects the sync preamble symbols. Scrambling is handled internally. std::vector symbol_stream = symbol_formation.formSymbols(mgd_decoded_data); + // Step 6. Modulation. The symbols are applied via 2400-bps 8-PSK modulation, with a 48 KHz sample rate. std::vector modulated_signal = modulator.modulate(symbol_stream); return modulated_signal; @@ -116,9 +117,10 @@ private: size_t fec_flush_bits = 144; // FEC encoder flush bits size_t interleave_flush_bits = interleaver.getFlushBits(); size_t total_flush_bits = fec_flush_bits + ((interleave_setting == 0) ? 0 : interleave_flush_bits); - while ((eom_data.getMaxBitIndex() + total_flush_bits) % interleave_flush_bits) - total_flush_bits++; - + if (interleave_flush_bits > 0) { + while ((eom_data.getMaxBitIndex() + total_flush_bits) % interleave_flush_bits) + total_flush_bits++; + } size_t total_bytes = (total_flush_bits + 7) / 8; // Round up to ensure we have enough bytes to handle all bits. BitStream flush_bits(std::vector(total_bytes, 0), total_flush_bits); eom_data += flush_bits; diff --git a/include/encoder/SymbolFormation.h b/include/encoder/SymbolFormation.h index 72c177b..f5a4068 100644 --- a/include/encoder/SymbolFormation.h +++ b/include/encoder/SymbolFormation.h @@ -21,16 +21,10 @@ std::vector baud75_normal_3 = {0, 4, 4, 0}; class SymbolFormation { public: - SymbolFormation(size_t baud_rate, size_t interleave_setting, bool is_voice, bool is_frequency_hopping) : interleave_setting(interleave_setting), baud_rate(baud_rate), is_voice(is_voice), is_frequency_hopping(is_frequency_hopping) {} - - std::vector formSymbols(std::vector& symbol_data) { - // Generate and scramble the sync preamble - std::vector sync_preamble = generateSyncPreamble(); - sync_preamble = scrambler.scrambleSyncPreamble(sync_preamble); - + SymbolFormation(size_t baud_rate, size_t interleave_setting, bool is_voice, bool is_frequency_hopping) : interleave_setting(interleave_setting), baud_rate(baud_rate), is_voice(is_voice), is_frequency_hopping(is_frequency_hopping) { // Determine the block sizes - size_t unknown_data_block_size = (baud_rate >= 2400) ? 32 : 20; - size_t interleaver_block_size; + unknown_data_block_size = (baud_rate >= 2400) ? 32 : 20; + known_data_block_size = (baud_rate >= 2400) ? 16 : 20; if (baud_rate == 2400) { interleaver_block_size = (interleave_setting == 2) ? (40 * 576) : (40 * 72); @@ -42,8 +36,17 @@ class SymbolFormation { interleaver_block_size = (interleave_setting == 2) ? (20 * 36) : (10 * 9); } + total_frames = interleaver_block_size / (unknown_data_block_size + known_data_block_size); + } + + std::vector formSymbols(std::vector& symbol_data) { + // Generate and scramble the sync preamble + std::vector sync_preamble = generateSyncPreamble(); + sync_preamble = scrambler.scrambleSyncPreamble(sync_preamble); + size_t set_count = 0; size_t symbol_count = 0; + size_t current_frame = 0; std::vector data_stream; size_t current_index = 0; @@ -71,9 +74,9 @@ class SymbolFormation { // Insert probe data if we are at an interleaver block boundary if (baud_rate > 75) { - bool is_at_boundary = (symbol_count % interleaver_block_size) == 0; - std::vector probe_data = generateProbeData(!is_at_boundary); + std::vector probe_data = generateProbeData(current_frame, total_frames); data_stream.insert(data_stream.end(), probe_data.begin(), probe_data.end()); + current_frame = (current_frame + 1) % total_frames; } } @@ -93,6 +96,10 @@ class SymbolFormation { int interleave_setting; bool is_voice; bool is_frequency_hopping; + size_t interleaver_block_size; + size_t unknown_data_block_size; + size_t known_data_block_size; + size_t total_frames; Scrambler scrambler = Scrambler(); std::vector mapChannelSymbolToTribitPattern(uint8_t symbol, bool repeat_twice = false) { @@ -212,59 +219,60 @@ class SymbolFormation { return preamble; } - std::vector generateProbeData(bool is_inside_block) { + std::vector generateProbeData(size_t current_frame, size_t total_frames) { std::vector probe_data; - // Determine interleaver block size based on baud rate and interleave setting - size_t interleaver_block_size; - if (baud_rate == 2400) { - interleaver_block_size = (interleave_setting == 2) ? (40 * 576) : (40 * 72); + // Set the known symbol patterns for D1 and D2 based on Table XI + uint8_t D1, D2; + if (baud_rate == 4800) { + D1 = 7; D2 = 6; + } else if (baud_rate == 2400 && is_voice) { + D1 = 7; D2 = 7; + } else if (baud_rate == 2400) { + D1 = (interleave_setting <= 1) ? 6 : 4; + D2 = 4; } else if (baud_rate == 1200) { - interleaver_block_size = (interleave_setting == 2) ? (40 * 288) : (40 * 36); - } else if ((baud_rate >= 150) || (baud_rate == 75 && is_frequency_hopping)) { - interleaver_block_size = (interleave_setting == 2) ? (40 * 144) : (40 * 18); + D1 = (interleave_setting <= 1) ? 6 : 4; + D2 = 5; + } else if (baud_rate == 600) { + D1 = (interleave_setting <= 1) ? 6 : 4; + D2 = 6; + } else if (baud_rate == 300) { + D1 = (interleave_setting <= 1) ? 6 : 4; + D2 = 7; + } else if (baud_rate == 150) { + D1 = (interleave_setting <= 1) ? 7 : 5; + D2 = 4; + } else if (baud_rate == 75) { + D1 = (interleave_setting <= 1) ? 7 : 5; + D2 = 5; } else { - interleaver_block_size = (interleave_setting == 2) ? (20 * 36) : (10 * 9); + throw std::invalid_argument("Invalid baud rate for generateProbeData"); } - // If we are inside an interleaver block, the probe data is filled with zeros - if (is_inside_block) { - probe_data.resize(interleaver_block_size, 0x00); - } else { - // Set the known symbol patterns for D1 and D2 based on Table XI - uint8_t D1, D2; - if (baud_rate == 4800) { - D1 = 7; D2 = 6; - } else if (baud_rate == 2400 && is_voice) { - D1 = 7; D2 = 7; - } else if (baud_rate == 2400) { - D1 = (interleave_setting <= 1) ? 6 : 4; - D2 = 4; - } else if (baud_rate == 1200) { - D1 = (interleave_setting <= 1) ? 6 : 4; - D2 = 5; - } else if (baud_rate == 600) { - D1 = (interleave_setting <= 1) ? 6 : 4; - D2 = 6; - } else if (baud_rate == 300) { - D1 = (interleave_setting <= 1) ? 6 : 4; - D2 = 7; - } else if (baud_rate == 150) { - D1 = (interleave_setting <= 1) ? 7 : 5; - D2 = 4; - } else if (baud_rate == 75) { - D1 = (interleave_setting <= 1) ? 7 : 5; - D2 = 5; - } else { - throw std::invalid_argument("Invalid baud rate for generateProbeData"); - } - - // Generate the known symbol patterns D1 and D2, repeated twice + // If the current frame is not the last two frames, set probe data to zeros + if (current_frame < total_frames - 2) { + probe_data.resize(known_data_block_size, 0x00); + } + // If the current frame is the second-to-last frame, set probe data to D1 pattern + else if (current_frame == total_frames - 2) { std::vector d1_pattern = mapChannelSymbolToTribitPattern(D1, true); - std::vector d2_pattern = mapChannelSymbolToTribitPattern(D2, true); - probe_data.insert(probe_data.end(), d1_pattern.begin(), d1_pattern.end()); + + // Fill the remaining symbols with zeros if necessary + if (probe_data.size() < known_data_block_size) { + probe_data.resize(known_data_block_size, 0x00); + } + } + // If the current frame is the last frame, set probe data to D2 pattern + else if (current_frame == total_frames - 1) { + std::vector d2_pattern = mapChannelSymbolToTribitPattern(D2, true); probe_data.insert(probe_data.end(), d2_pattern.begin(), d2_pattern.end()); + + // Fill the remaining symbols with zeros if necessary + if (probe_data.size() < known_data_block_size) { + probe_data.resize(known_data_block_size, 0x00); + } } return probe_data; diff --git a/include/modulation/PSKModulator.h b/include/modulation/PSKModulator.h index cbb4e90..5aaa4d1 100644 --- a/include/modulation/PSKModulator.h +++ b/include/modulation/PSKModulator.h @@ -10,7 +10,7 @@ class PSKModulator { public: - PSKModulator(double baud_rate, double sample_rate, double energy_per_bit, bool is_frequency_hopping) + PSKModulator(double baud_rate, double sample_rate, bool is_frequency_hopping) : sample_rate(sample_rate), carrier_freq(1800), phase(0.0) { initializeSymbolMap(); symbol_rate = 2400; // Fixed symbol rate as per specification (2400 symbols per second) diff --git a/main.cpp b/main.cpp index 40c3d1f..ecaed72 100644 --- a/main.cpp +++ b/main.cpp @@ -13,18 +13,18 @@ int main() { std::vector sample_data(sample_string.begin(), sample_string.end()); // Convert sample data to a BitStream object - BitStream bitstream(sample_data, sample_data.size() * 8); + BitStream input_data(sample_data, sample_data.size() * 8); // Configuration for modem - size_t baud_rate = 150; + size_t baud_rate = 2400; bool is_voice = false; // False indicates data mode bool is_frequency_hopping = false; // Fixed frequency operation - size_t interleave_setting = 2; // Short interleave + size_t interleave_setting = 1; // Short interleave // Create ModemController instance - ModemController modem(baud_rate, is_voice, is_frequency_hopping, interleave_setting, bitstream); + ModemController modem(baud_rate, is_voice, is_frequency_hopping, interleave_setting, input_data); - const char* file_name = "modulated_signal_150bps_longinterleave.wav"; + const char* file_name = "modulated_signal_2400bps_voice.wav"; // Perform transmit operation to generate modulated signal std::vector modulated_signal = modem.transmit();