Corrected probe data formation, added 4800 bps case in interleaver and EOM generator

This commit is contained in:
RecklessAndFeckless 2024-10-11 20:46:34 -04:00
parent b9502ebe86
commit 9f2d79617e
5 changed files with 81 additions and 68 deletions

View File

@ -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) {

View File

@ -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<uint8_t> 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<uint8_t> 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<int16_t> 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<uint8_t>(total_bytes, 0), total_flush_bits);
eom_data += flush_bits;

View File

@ -21,16 +21,10 @@ std::vector<uint8_t> 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<uint8_t> formSymbols(std::vector<uint8_t>& symbol_data) {
// Generate and scramble the sync preamble
std::vector<uint8_t> 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<uint8_t> formSymbols(std::vector<uint8_t>& symbol_data) {
// Generate and scramble the sync preamble
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> probe_data = generateProbeData(!is_at_boundary);
std::vector<uint8_t> 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<uint8_t> mapChannelSymbolToTribitPattern(uint8_t symbol, bool repeat_twice = false) {
@ -212,59 +219,60 @@ class SymbolFormation {
return preamble;
}
std::vector<uint8_t> generateProbeData(bool is_inside_block) {
std::vector<uint8_t> generateProbeData(size_t current_frame, size_t total_frames) {
std::vector<uint8_t> 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<uint8_t> d1_pattern = mapChannelSymbolToTribitPattern(D1, true);
std::vector<uint8_t> 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<uint8_t> 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;

View File

@ -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)

View File

@ -13,18 +13,18 @@ int main() {
std::vector<uint8_t> 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<int16_t> modulated_signal = modem.transmit();