Skip to content

Commit

Permalink
use soft decision decoder for iq data
Browse files Browse the repository at this point in the history
  • Loading branch information
marenz2569 committed Jan 8, 2025
1 parent ac29912 commit ab91156
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 22 deletions.
46 changes: 30 additions & 16 deletions include/l2/lower_mac.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,22 @@ class LowerMac {
std::optional<uint32_t> scrambling_code = std::nullopt);
~LowerMac() = default;

/// Get the correct viterbi decoder either for hard decision for bit or soft decision for soft bits.
/// \targ DataType with bool (bits) the hard decision decoder is returned, with int16_t we have soft bits and return
/// the soft decision decoder
template <typename DataType> [[nodiscard]] auto getViterbi() const -> const ViterbiCodec& {
if constexpr (std::is_same_v<DataType, bool>) {
return viter_bi_codec_1614_hard_decision_;
}
if constexpr (std::is_same_v<DataType, int16_t>) {
return viter_bi_codec_1614_soft_decision_;
}
assert(false && "Compiling descramble with template paramater not bool or int16_t");
}

/// handles the decoding of the synchronization bursts and once synchronized passes the data to the decoding of the
/// channels. keeps track of the current network time
/// \targ DataType with bool is selected we have bits, with int16_t we have symbols
/// \targ DataType with bool is selected we have bits, with int16_t we have soft bits
template <typename DataType>
[[nodiscard]] auto process(std::vector<DataType> frame, BurstType burst_type) -> return_type {
// Set to true if there was some decoding error in the lower MAC
Expand Down Expand Up @@ -61,8 +74,8 @@ class LowerMac {
};

auto sb_bits = LowerMacCoding::viter_bi_decode_1614(
viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(
LowerMacCoding::descramble(sb_input, 0x0003), 11)));
getViterbi<DataType>(), LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(
LowerMacCoding::descramble(sb_input, 0x0003), 11)));

if (LowerMacCoding::check_crc_16_ccitt<76>(sb_bits)) {
current_sync = BroadcastSynchronizationChannel(
Expand Down Expand Up @@ -140,8 +153,8 @@ class LowerMac {
}

auto bkn2_bits = LowerMacCoding::viter_bi_decode_1614(
viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(
LowerMacCoding::descramble(bkn2_input, bsc.scrambling_code), 101)));
getViterbi<DataType>(), LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(
LowerMacCoding::descramble(bkn2_input, bsc.scrambling_code), 101)));

slots = Slots(burst_type, SlotType::kOneSubslot,
Slot(LogicalChannelDataAndCrc{
Expand Down Expand Up @@ -174,7 +187,7 @@ class LowerMac {
auto bkn1_descrambled_bits = LowerMacCoding::softbits_to_bits(bkn1_descrambled);

auto bkn1_bits = LowerMacCoding::viter_bi_decode_1614(
viter_bi_codec_1614_,
getViterbi<DataType>(),
LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(bkn1_descrambled, 103)));

if (aach.downlink_usage == DownlinkUsage::Traffic) {
Expand Down Expand Up @@ -216,8 +229,8 @@ class LowerMac {
};

auto bkn1_bits = LowerMacCoding::viter_bi_decode_1614(
viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(
LowerMacCoding::descramble(bkn1_input, bsc.scrambling_code), 101)));
getViterbi<DataType>(), LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(
LowerMacCoding::descramble(bkn1_input, bsc.scrambling_code), 101)));

std::array<DataType, 216> bkn2_input{};
for (auto i = 0; i < 216; i++) {
Expand All @@ -227,7 +240,7 @@ class LowerMac {
auto bkn2_deinterleaved =
LowerMacCoding::deinterleave(LowerMacCoding::descramble(bkn2_input, bsc.scrambling_code), 101);
auto bkn2_deinterleaved_bits = LowerMacCoding::softbits_to_bits(bkn2_deinterleaved);
auto bkn2_bits = LowerMacCoding::viter_bi_decode_1614(viter_bi_codec_1614_,
auto bkn2_bits = LowerMacCoding::viter_bi_decode_1614(getViterbi<DataType>(),
LowerMacCoding::depuncture23(bkn2_deinterleaved));

// Half slot traffic channel defines type 3 bits (deinterleaved)
Expand Down Expand Up @@ -274,8 +287,8 @@ class LowerMac {
};

auto cb_bits = LowerMacCoding::viter_bi_decode_1614(
viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(
LowerMacCoding::descramble(cb_input, bsc.scrambling_code), 13)));
getViterbi<DataType>(), LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(
LowerMacCoding::descramble(cb_input, bsc.scrambling_code), 13)));

// SCH/HU
slots = Slots(burst_type, SlotType::kOneSubslot,
Expand All @@ -297,7 +310,7 @@ class LowerMac {
auto bkn1_descrambled_bits = LowerMacCoding::softbits_to_bits(bkn1_descrambled);

auto bkn1_bits = LowerMacCoding::viter_bi_decode_1614(
viter_bi_codec_1614_,
getViterbi<DataType>(),
LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(bkn1_descrambled, 103)));

slots = Slots(
Expand All @@ -321,8 +334,8 @@ class LowerMac {
}

auto bkn1_bits = LowerMacCoding::viter_bi_decode_1614(
viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(
LowerMacCoding::descramble(bkn1_input, bsc.scrambling_code), 101)));
getViterbi<DataType>(), LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(
LowerMacCoding::descramble(bkn1_input, bsc.scrambling_code), 101)));

std::array<DataType, 216> bkn2_input{};
for (auto i = 0; i < 216; i++) {
Expand All @@ -332,7 +345,7 @@ class LowerMac {
auto bkn2_deinterleaved =
LowerMacCoding::deinterleave(LowerMacCoding::descramble(bkn2_input, bsc.scrambling_code), 101);
auto bkn2_deinterleaved_bits = LowerMacCoding::softbits_to_bits(bkn2_deinterleaved);
auto bkn2_bits = LowerMacCoding::viter_bi_decode_1614(viter_bi_codec_1614_,
auto bkn2_bits = LowerMacCoding::viter_bi_decode_1614(getViterbi<DataType>(),
LowerMacCoding::depuncture23(bkn2_deinterleaved));

// STCH + TCH
Expand Down Expand Up @@ -361,7 +374,8 @@ class LowerMac {
return *slots;
}

const ViterbiCodec viter_bi_codec_1614_;
const ViterbiCodecHardDecision viter_bi_codec_1614_hard_decision_;
const ViterbiCodecSoftDecision viter_bi_codec_1614_soft_decision_;

std::unique_ptr<LowerMacMetrics> metrics_;

Expand Down
38 changes: 35 additions & 3 deletions include/utils/viter_bi_codec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,26 @@

class ViterbiCodec {
public:
ViterbiCodec() = default;
[[nodiscard]] auto Decode(const std::vector<int16_t>& bits) const -> std::vector<uint8_t>;
virtual ~ViterbiCodec() = default;

static constexpr size_t K = 5;
static constexpr size_t R = 4;

private:
[[nodiscard]] virtual auto Decode(const std::vector<int16_t>& bits) const -> std::vector<uint8_t> = 0;

protected:
ViterbiCodec() = default;

const std::vector<uint8_t> G = {19, 29, 23, 27};
};

class ViterbiCodecHardDecision : public ViterbiCodec {
public:
ViterbiCodecHardDecision() = default;

[[nodiscard]] auto Decode(const std::vector<int16_t>& bits) const -> std::vector<uint8_t> override;

private:
const int16_t soft_decision_high = +1;
const int16_t soft_decision_low = -1;
const uint16_t max_error = static_cast<uint16_t>(soft_decision_high - soft_decision_low) * static_cast<uint16_t>(R);
Expand All @@ -43,3 +54,24 @@ class ViterbiCodec {
const ViterbiBranchTable<K, R, int16_t> branch_table =
ViterbiBranchTable<K, R, int16_t>(G.data(), soft_decision_high, soft_decision_low);
};

class ViterbiCodecSoftDecision : public ViterbiCodec {
public:
ViterbiCodecSoftDecision() = default;
[[nodiscard]] auto Decode(const std::vector<int16_t>& bits) const -> std::vector<uint8_t> override;

private:
const int16_t soft_decision_high = +127;
const int16_t soft_decision_low = -127;
const uint16_t max_error = static_cast<uint16_t>(soft_decision_high - soft_decision_low) * static_cast<uint16_t>(R);
const uint16_t error_margin = max_error * static_cast<uint16_t>(5U);

const ViterbiDecoder_Config<uint16_t> config = {
.soft_decision_max_error = max_error,
.initial_start_error = std::numeric_limits<uint16_t>::min(),
.initial_non_start_error = static_cast<uint16_t>(std::numeric_limits<uint16_t>::min() + error_margin),
.renormalisation_threshold = static_cast<uint16_t>(std::numeric_limits<uint16_t>::max() - error_margin)};

const ViterbiBranchTable<K, R, int16_t> branch_table =
ViterbiBranchTable<K, R, int16_t>(G.data(), soft_decision_high, soft_decision_low);
};
4 changes: 2 additions & 2 deletions src/iq_stream_decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ auto IQStreamDecoder::symbols_to_softstream(iterator_type it) -> std::vector<int
// symbol 1:
// real > 0 -> 0 -> -1
// real <= 0 -> 1 -> 1
soft_bits[i * 2] = -1 * it->imag();
soft_bits[(i * 2) + 1] = -1 * it->real();
soft_bits[i * 2] = -127 * it->imag();
soft_bits[(i * 2) + 1] = -127 * it->real();
}
return soft_bits;
}
Expand Down
23 changes: 22 additions & 1 deletion src/utils/viter_bi_codec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,28 @@

#include "utils/viter_bi_codec.hpp"

auto ViterbiCodec::Decode(const std::vector<int16_t>& bits) const -> std::vector<uint8_t> {
auto ViterbiCodecHardDecision::Decode(const std::vector<int16_t>& bits) const -> std::vector<uint8_t> {
auto vitdec = ViterbiDecoder_Core<K, R, uint16_t, int16_t>(branch_table, config);
using Decoder = ViterbiDecoder_SSE_u16<K, R>;

const size_t total_bits = bits.size() / R;
const size_t total_tail_bits = K - 1u;
const size_t total_data_bits = total_bits - total_tail_bits;

std::vector<uint8_t> output_bytes(total_bits / 8);

vitdec.set_traceback_length(total_data_bits);

vitdec.reset();
Decoder::template update<uint64_t>(vitdec, bits.data(), bits.size());
vitdec.chainback(output_bytes.data(), total_data_bits, 0);
const uint64_t error = vitdec.get_error();
// std::cout << "error=" << error << std::endl;

return output_bytes;
}

auto ViterbiCodecSoftDecision::Decode(const std::vector<int16_t>& bits) const -> std::vector<uint8_t> {
auto vitdec = ViterbiDecoder_Core<K, R, uint16_t, int16_t>(branch_table, config);
using Decoder = ViterbiDecoder_SSE_u16<K, R>;

Expand Down

0 comments on commit ab91156

Please sign in to comment.