Corrected probe data formation, added 4800 bps case in interleaver and EOM generator
This commit is contained in:
parent
b9502ebe86
commit
9f2d79617e
@ -180,7 +180,10 @@ private:
|
|||||||
* @brief Sets the matrix dimensions based on baud rate and interleave setting.
|
* @brief Sets the matrix dimensions based on baud rate and interleave setting.
|
||||||
*/
|
*/
|
||||||
void setMatrixDimensions() {
|
void setMatrixDimensions() {
|
||||||
if (baud_rate == 2400) {
|
if (baud_rate == 4800) {
|
||||||
|
rows = 0;
|
||||||
|
columns = 0;
|
||||||
|
} else if (baud_rate == 2400) {
|
||||||
rows = 40;
|
rows = 40;
|
||||||
columns = (interleave_setting == 2) ? 576 : 72;
|
columns = (interleave_setting == 2) ? 576 : 72;
|
||||||
} else if (baud_rate == 1200) {
|
} else if (baud_rate == 1200) {
|
||||||
|
@ -51,7 +51,7 @@ public:
|
|||||||
interleaver(baud_rate, interleave_setting, is_frequency_hopping),
|
interleaver(baud_rate, interleave_setting, is_frequency_hopping),
|
||||||
input_data(std::move(_data)),
|
input_data(std::move(_data)),
|
||||||
mgd_decoder(baud_rate, is_frequency_hopping),
|
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.
|
* @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
|
// Step 3: Interleaving
|
||||||
processed_data = interleaver.interleaveStream(fec_encoded_data);
|
processed_data = interleaver.interleaveStream(fec_encoded_data);
|
||||||
}
|
}
|
||||||
|
// Step 4: MGD Decoding
|
||||||
std::vector<uint8_t> mgd_decoded_data = mgd_decoder.mgdDecode(processed_data);
|
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);
|
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);
|
std::vector<int16_t> modulated_signal = modulator.modulate(symbol_stream);
|
||||||
|
|
||||||
return modulated_signal;
|
return modulated_signal;
|
||||||
@ -116,9 +117,10 @@ private:
|
|||||||
size_t fec_flush_bits = 144; // FEC encoder flush bits
|
size_t fec_flush_bits = 144; // FEC encoder flush bits
|
||||||
size_t interleave_flush_bits = interleaver.getFlushBits();
|
size_t interleave_flush_bits = interleaver.getFlushBits();
|
||||||
size_t total_flush_bits = fec_flush_bits + ((interleave_setting == 0) ? 0 : interleave_flush_bits);
|
size_t total_flush_bits = fec_flush_bits + ((interleave_setting == 0) ? 0 : interleave_flush_bits);
|
||||||
|
if (interleave_flush_bits > 0) {
|
||||||
while ((eom_data.getMaxBitIndex() + total_flush_bits) % interleave_flush_bits)
|
while ((eom_data.getMaxBitIndex() + total_flush_bits) % interleave_flush_bits)
|
||||||
total_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.
|
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);
|
BitStream flush_bits(std::vector<uint8_t>(total_bytes, 0), total_flush_bits);
|
||||||
eom_data += flush_bits;
|
eom_data += flush_bits;
|
||||||
|
@ -21,16 +21,10 @@ std::vector<uint8_t> baud75_normal_3 = {0, 4, 4, 0};
|
|||||||
|
|
||||||
class SymbolFormation {
|
class SymbolFormation {
|
||||||
public:
|
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) {}
|
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);
|
|
||||||
|
|
||||||
// Determine the block sizes
|
// Determine the block sizes
|
||||||
size_t unknown_data_block_size = (baud_rate >= 2400) ? 32 : 20;
|
unknown_data_block_size = (baud_rate >= 2400) ? 32 : 20;
|
||||||
size_t interleaver_block_size;
|
known_data_block_size = (baud_rate >= 2400) ? 16 : 20;
|
||||||
|
|
||||||
if (baud_rate == 2400) {
|
if (baud_rate == 2400) {
|
||||||
interleaver_block_size = (interleave_setting == 2) ? (40 * 576) : (40 * 72);
|
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);
|
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 set_count = 0;
|
||||||
size_t symbol_count = 0;
|
size_t symbol_count = 0;
|
||||||
|
size_t current_frame = 0;
|
||||||
std::vector<uint8_t> data_stream;
|
std::vector<uint8_t> data_stream;
|
||||||
|
|
||||||
size_t current_index = 0;
|
size_t current_index = 0;
|
||||||
@ -71,9 +74,9 @@ class SymbolFormation {
|
|||||||
|
|
||||||
// Insert probe data if we are at an interleaver block boundary
|
// Insert probe data if we are at an interleaver block boundary
|
||||||
if (baud_rate > 75) {
|
if (baud_rate > 75) {
|
||||||
bool is_at_boundary = (symbol_count % interleaver_block_size) == 0;
|
std::vector<uint8_t> probe_data = generateProbeData(current_frame, total_frames);
|
||||||
std::vector<uint8_t> probe_data = generateProbeData(!is_at_boundary);
|
|
||||||
data_stream.insert(data_stream.end(), probe_data.begin(), probe_data.end());
|
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;
|
int interleave_setting;
|
||||||
bool is_voice;
|
bool is_voice;
|
||||||
bool is_frequency_hopping;
|
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();
|
Scrambler scrambler = Scrambler();
|
||||||
|
|
||||||
std::vector<uint8_t> mapChannelSymbolToTribitPattern(uint8_t symbol, bool repeat_twice = false) {
|
std::vector<uint8_t> mapChannelSymbolToTribitPattern(uint8_t symbol, bool repeat_twice = false) {
|
||||||
@ -212,25 +219,9 @@ class SymbolFormation {
|
|||||||
return preamble;
|
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;
|
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);
|
|
||||||
} 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);
|
|
||||||
} else {
|
|
||||||
interleaver_block_size = (interleave_setting == 2) ? (20 * 36) : (10 * 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
// Set the known symbol patterns for D1 and D2 based on Table XI
|
||||||
uint8_t D1, D2;
|
uint8_t D1, D2;
|
||||||
if (baud_rate == 4800) {
|
if (baud_rate == 4800) {
|
||||||
@ -259,12 +250,29 @@ class SymbolFormation {
|
|||||||
throw std::invalid_argument("Invalid baud rate for generateProbeData");
|
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> 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());
|
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());
|
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;
|
return probe_data;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
class PSKModulator {
|
class PSKModulator {
|
||||||
public:
|
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) {
|
: sample_rate(sample_rate), carrier_freq(1800), phase(0.0) {
|
||||||
initializeSymbolMap();
|
initializeSymbolMap();
|
||||||
symbol_rate = 2400; // Fixed symbol rate as per specification (2400 symbols per second)
|
symbol_rate = 2400; // Fixed symbol rate as per specification (2400 symbols per second)
|
||||||
|
10
main.cpp
10
main.cpp
@ -13,18 +13,18 @@ int main() {
|
|||||||
std::vector<uint8_t> sample_data(sample_string.begin(), sample_string.end());
|
std::vector<uint8_t> sample_data(sample_string.begin(), sample_string.end());
|
||||||
|
|
||||||
// Convert sample data to a BitStream object
|
// 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
|
// Configuration for modem
|
||||||
size_t baud_rate = 150;
|
size_t baud_rate = 2400;
|
||||||
bool is_voice = false; // False indicates data mode
|
bool is_voice = false; // False indicates data mode
|
||||||
bool is_frequency_hopping = false; // Fixed frequency operation
|
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
|
// 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
|
// Perform transmit operation to generate modulated signal
|
||||||
std::vector<int16_t> modulated_signal = modem.transmit();
|
std::vector<int16_t> modulated_signal = modem.transmit();
|
||||||
|
Loading…
Reference in New Issue
Block a user