225 lines
7.8 KiB
C++
225 lines
7.8 KiB
C++
#ifndef INTERLEAVER_H
|
|
#define INTERLEAVER_H
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
|
|
#include "bitstream.h"
|
|
|
|
/**
|
|
* @class Interleaver
|
|
* @brief A class to interleave input bitstreams based on the specified baud rate and interleave settings.
|
|
*
|
|
* The Interleaver processes input data in chunks, rearranging the bit order as required
|
|
* by the MIL-STD-188-110 standard for different baud rates and interleave settings.
|
|
*/
|
|
class Interleaver {
|
|
public:
|
|
/**
|
|
* @brief Constructs an Interleaver with specific baud rate, interleave settings, and operation mode.
|
|
* @param baud_rate The baud rate of the transmission.
|
|
* @param interleave_setting The interleave setting (0, short, or long).
|
|
* @param is_frequency_hopping Boolean flag indicating if frequency-hopping mode is enabled.
|
|
*/
|
|
Interleaver(size_t baud_rate, size_t interleave_setting, bool is_frequency_hopping)
|
|
: baud_rate(baud_rate), interleave_setting(interleave_setting), is_frequency_hopping(is_frequency_hopping) {
|
|
setMatrixDimensions();
|
|
matrix.resize(rows * columns, 0);
|
|
}
|
|
|
|
/**
|
|
* @brief Interleaves the entire input BitStream and returns the interleaved result.
|
|
* @param input_data The input BitStream to be interleaved.
|
|
* @return A new BitStream containing the interleaved data.
|
|
*/
|
|
std::vector<uint8_t> interleaveStream(const BitStream& input_data) {
|
|
BitStream data = input_data;
|
|
BitStream interleaved_data;
|
|
size_t chunk_size = rows * columns;
|
|
size_t input_index = 0;
|
|
|
|
while (input_index < data.getMaxBitIndex()) {
|
|
size_t end_index = std::min(input_index + chunk_size, data.getMaxBitIndex());
|
|
BitStream chunk = data.getSubStream(input_index, end_index);
|
|
if (chunk.getMaxBitIndex() > rows * columns) {
|
|
throw std::invalid_argument("Input data exceeds interleaver matrix size in loadChunk()");
|
|
}
|
|
BitStream interleaved_chunk = interleaveChunk(chunk);
|
|
interleaved_data += interleaved_chunk;
|
|
input_index = end_index;
|
|
}
|
|
|
|
// Apply puncturing for 2400 bps in frequency-hopping mode (Rate 2/3)
|
|
if (baud_rate == 2400 && is_frequency_hopping) {
|
|
return applyPuncturing(interleaved_data);
|
|
}
|
|
|
|
std::vector<uint8_t> final_interleaved_data = groupSymbols(interleaved_data);
|
|
return final_interleaved_data;
|
|
}
|
|
|
|
/**
|
|
* @brief Retrieves the number of bits required to fully flush the interleaver matrix.
|
|
* @return The number of bits needed for a complete flush.
|
|
*/
|
|
size_t getFlushBits() const {
|
|
return rows * columns;
|
|
}
|
|
|
|
private:
|
|
size_t baud_rate;
|
|
size_t interleave_setting;
|
|
bool is_frequency_hopping;
|
|
size_t rows;
|
|
size_t columns;
|
|
std::vector<uint8_t> matrix; ///< 1D vector representing the interleaver matrix.
|
|
|
|
static constexpr size_t ROW_INCREMENT_DEFAULT = 9;
|
|
static constexpr size_t COLUMN_DECREMENT_DEFAULT = 17;
|
|
|
|
/**
|
|
* @brief Groups the bits into symbols based on the baud rate (e.g., 2 bits per symbol at 1200 bps).
|
|
* @param input_data The input BitStream to be grouped into symbols.
|
|
* @return A vector of grouped symbols.
|
|
*/
|
|
std::vector<uint8_t> groupSymbols(BitStream& input_data) {
|
|
std::vector<uint8_t> grouped_data;
|
|
size_t max_index = input_data.getMaxBitIndex();
|
|
size_t bits_per_symbol = (baud_rate == 2400) ? 3 : (baud_rate == 1200 || (baud_rate == 75 && !is_frequency_hopping)) ? 2 : 1;
|
|
size_t current_index = 0;
|
|
|
|
while ((current_index + bits_per_symbol) < max_index) {
|
|
uint8_t symbol = 0;
|
|
|
|
for (int i = 0; i < bits_per_symbol; i++) {
|
|
symbol = (symbol << 1) | input_data.getBitVal(current_index + i);
|
|
}
|
|
|
|
grouped_data.push_back(symbol);
|
|
current_index += bits_per_symbol;
|
|
}
|
|
|
|
return grouped_data;
|
|
}
|
|
|
|
/**
|
|
* @brief Interleaves a chunk of the input BitStream and returns the result.
|
|
* @param input_data The input BitStream chunk.
|
|
* @return A BitStream representing the interleaved chunk.
|
|
*/
|
|
BitStream interleaveChunk(const BitStream& input_data) {
|
|
loadChunk(input_data);
|
|
return fetchChunk();
|
|
}
|
|
|
|
/**
|
|
* @brief Loads bits from the input BitStream into the interleaver matrix.
|
|
* @param data The input BitStream to load.
|
|
*/
|
|
void loadChunk(const BitStream& data) {
|
|
size_t row = 0;
|
|
size_t col = 0;
|
|
size_t index = 0;
|
|
|
|
size_t row_increment = (baud_rate == 75 && interleave_setting == 2) ? 7 : 9;
|
|
|
|
// Load bits into the matrix
|
|
std::fill(matrix.begin(), matrix.end(), 0); // Clear previous data
|
|
while (index < data.getMaxBitIndex() && col < columns) {
|
|
size_t matrix_idx = row * columns + col;
|
|
if (matrix_idx >= matrix.size()) {
|
|
throw std::out_of_range("Matrix index out of bounds in loadChunk()");
|
|
}
|
|
|
|
matrix[matrix_idx] = data.getBitVal(index++);
|
|
row = (row + row_increment) % rows;
|
|
|
|
if (row == 0) {
|
|
col++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Fetches bits from the interleaver matrix in the interleaved order.
|
|
* @return A BitStream containing the fetched interleaved data.
|
|
*/
|
|
BitStream fetchChunk() {
|
|
BitStream fetched_data;
|
|
size_t row = 0;
|
|
size_t col = 0;
|
|
|
|
size_t column_decrement = (baud_rate == 75 && interleave_setting == 2) ? 7 : 17;
|
|
|
|
// Fetch bits from the matrix
|
|
while (fetched_data.getMaxBitIndex() < rows * columns) {
|
|
size_t matrix_idx = row * columns + col;
|
|
if (matrix_idx >= matrix.size()) {
|
|
throw std::out_of_range("Matrix index out of bounds in fetchChunk()");
|
|
}
|
|
|
|
fetched_data.putBit(matrix[matrix_idx]);
|
|
row++;
|
|
|
|
if (row == rows) {
|
|
row = 0;
|
|
col = (col + 1) % columns;
|
|
} else {
|
|
col = (col + columns - column_decrement) % columns;
|
|
}
|
|
}
|
|
|
|
return fetched_data;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief Sets the matrix dimensions based on baud rate and interleave setting.
|
|
*/
|
|
void setMatrixDimensions() {
|
|
if (baud_rate == 2400) {
|
|
rows = 40;
|
|
columns = (interleave_setting == 2) ? 576 : 72;
|
|
} else if (baud_rate == 1200) {
|
|
rows = 40;
|
|
columns = (interleave_setting == 2) ? 288 : 36;
|
|
} else if (baud_rate == 600) {
|
|
rows = 40;
|
|
columns = (interleave_setting == 2) ? 144 : 18;
|
|
} else if (baud_rate == 300 || baud_rate == 150) {
|
|
rows = 40;
|
|
columns = (interleave_setting == 2) ? 144 : 18;
|
|
} else if (baud_rate == 75) {
|
|
if (is_frequency_hopping) {
|
|
rows = 40;
|
|
columns = 18;
|
|
} else {
|
|
rows = (interleave_setting == 2) ? 20 : 10;
|
|
columns = (interleave_setting == 2) ? 36 : 9;
|
|
}
|
|
} else {
|
|
throw std::invalid_argument("Invalid baud rate for setMatrixDimensions");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Applies puncturing to the interleaved data (used for 2400 bps in frequency-hopping mode).
|
|
* @param interleaved_data The interleaved data to be punctured.
|
|
* @return A BitStream containing punctured data.
|
|
*/
|
|
BitStream applyPuncturing(const BitStream& interleaved_data) {
|
|
BitStream punctured_data;
|
|
for (size_t i = 0; i < interleaved_data.getMaxBitIndex(); i++) {
|
|
if ((i % 4) != 1) { // Skip every fourth bit (the second value of T2)
|
|
punctured_data.putBit(interleaved_data.getBitVal(i));
|
|
}
|
|
}
|
|
return punctured_data;
|
|
}
|
|
};
|
|
|
|
#endif
|