Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Channel Estimation #8

Merged
merged 35 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
8235f53
implement argument parsing for IQ stream
marenz2569 Jul 2, 2023
a513161
move current decoder to bit_stream_decoder
marenz2569 Jul 2, 2023
9ef1196
implement reading IQ and hard decision symbol mapper
marenz2569 Jul 2, 2023
5e91c93
uplink sequence burst detection
marenz2569 Jul 3, 2023
fe70e99
implement first version of synchronization of bursts. very unperforma…
marenz2569 Jul 3, 2023
a99c463
add parsing stub for supplementary llc pdu
marenz2569 Jul 4, 2023
109e26c
fix upper mac parsing logic. add lower mac parsing for Normal Uplink …
marenz2569 Jul 4, 2023
ce6949a
use std::function to abstract and delay processing of upper mac in up…
marenz2569 Jul 4, 2023
c64bdfd
implement StreamingOrderedOutputThreadPoolExecutor
marenz2569 Jul 5, 2023
00a8bd6
remove duplicate code
marenz2569 Jul 5, 2023
63cc74e
add example for all different tetra RCPC punctering schemes
marenz2569 Jul 9, 2023
3853c6b
Use different viterbi decoder
marenz2569 Jul 9, 2023
4a7b1e9
add test for viterbi decoder
marenz2569 Jul 10, 2023
ad2eade
remove old code
marenz2569 Jul 10, 2023
c87e0d8
fix memory accumalation
marenz2569 Jul 11, 2023
0760983
update to newer version of viterbi decoder library. use sse4.1
marenz2569 Jul 11, 2023
a8ec51c
streaming thread pool executor wait_lok instead of lock and less threads
marenz2569 Aug 11, 2023
ebf0998
clang-format. add pthread names
marenz2569 Aug 12, 2023
cb239fa
update flake.lock to 23.05
marenz2569 Aug 12, 2023
38e9308
implement LLC basic link pdus with fcs
marenz2569 Aug 12, 2023
31946c5
implement a crude way to stop program on CTRL-C or EOF
marenz2569 Jan 23, 2024
feba058
optimize conv for detection
marenz2569 Jan 24, 2024
5c9bed1
improve performance by a bit
marenz2569 Jan 25, 2024
2057a1b
add more performance improvements
marenz2569 Jan 27, 2024
722a1fa
Refactor lower mac coding
marenz2569 Jan 27, 2024
53830b8
precompute descrambling table
marenz2569 Jan 28, 2024
643fd8b
fix bug in thread pool executor
marenz2569 Jan 28, 2024
83f80cc
move to raw pointers in performance critical regions
marenz2569 Jan 29, 2024
2d34a8e
l2/lower_mac: use fixed size buffer for descrambler result
marenz2569 Jan 29, 2024
ec9e2ef
l2/lower_mac: use fixed size buffer for reed muller 3014 result
marenz2569 Jan 29, 2024
10f9181
l2/lower_mac: use fixed size buffer for deinterleaver result
marenz2569 Jan 29, 2024
80a9b32
utils/bit_vector: do less copying and more unsafe pointer handling. s…
marenz2569 Jan 30, 2024
e85e832
update debug print
marenz2569 Feb 4, 2024
633aa81
update debug print
marenz2569 Feb 4, 2024
1389d55
fix descrambling precomputation
marenz2569 Feb 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "lib/ViterbiDecoderCpp"]
path = lib/ViterbiDecoderCpp
url = https://github.com/FiendChain/ViterbiDecoderCpp.git
21 changes: 19 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ add_executable(tetra
src/main.cpp
src/reporter.cpp
src/decoder.cpp
src/streaming_ordered_output_thread_pool_executor.cpp
src/bit_stream_decoder.cpp
src/iq_stream_decoder.cpp
src/l2/lower_mac.cpp
src/l2/lower_mac_coding.cpp
src/l2/upper_mac.cpp
Expand All @@ -21,7 +24,18 @@ add_executable(tetra
src/utils/bit_vector.cpp
src/utils/viter_bi_codec.cpp)

target_compile_options(tetra PUBLIC -std=c++17 -Wall -Wno-unused-variable)
add_executable(tetra-puncturing
src/examples/tetra_puncturing.cpp)

add_executable(tetra-viterbi
src/examples/viter_bi_codec.cpp
src/examples/tetra_viterbi.cpp)

target_compile_options(tetra PUBLIC -std=c++17 -Wall -Wno-unused-variable -msse4.1 -O3)
target_compile_options(tetra-puncturing PUBLIC -std=c++17 -Wall -Wno-unused-variable)
target_compile_options(tetra-viterbi PUBLIC -std=c++17 -Wall -Wno-unused-variable)

include(lib/ViterbiDecoderCpp/viterbi-config.cmake)

include_directories(src)

Expand All @@ -32,6 +46,9 @@ find_package(nlohmann_json REQUIRED)

include_directories(${CMAKE_SOURCE_DIR}/include)

target_link_libraries(tetra ZLIB::ZLIB fmt::fmt nlohmann_json::nlohmann_json)
target_link_libraries(tetra ZLIB::ZLIB fmt::fmt nlohmann_json::nlohmann_json viterbi)
target_link_libraries(tetra-viterbi viterbi)

install(TARGETS tetra DESTINATION bin)
install(TARGETS tetra-puncturing DESTINATION bin)
install(TARGETS tetra-viterbi DESTINATION bin)
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Usage:
with -i option)
-d arg <level> print debug information (default: 0)
-P, --packed pack rx data (1 byte = 8 bits)
--iq Receive IQ instead of bitstream
--uplink arg <scrambling code> enable uplink parsing with
predefined scrambilng code
```
32 changes: 25 additions & 7 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
inputs = {
nixpkgs.url = github:NixOS/nixpkgs/nixos-22.11;
nixpkgs.url = github:NixOS/nixpkgs/nixos-23.05;

utils.url = "github:numtide/flake-utils";
};
Expand Down
114 changes: 114 additions & 0 deletions include/bit_stream_decoder.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright (C) 2022 Transit Live Mapping Solutions
* All rights reserved.
*
* Authors:
* Marenz Schmidl
* Tassilo Tanneberger
*/

#pragma once

#include <memory>
#include <optional>
#include <string>
#include <vector>

#include <l2/lower_mac.hpp>

/**
* Tetra downlink decoder for PI/4-DQPSK modulation
*
* Following downlink burst types for Phase Modulation are supported: (See TSI
* EN 300 392-2 V3.8.1 (2016-08) Table 9.2)
*
* normal continuous downlink burst (NDB)
*
* synchronization continuous downlink burst (SB)
*
* Follawing downlink burst types for Phase Modulation are not supported:
* discontinuous downlink burst (NDB)
* synchronization discontinuous downlink burst (SB)
*
* Uplink burst types are not supported:
* control uplink burst (CB)
* normal uplink burst (NUB)
*/
class BitStreamDecoder {
public:
BitStreamDecoder(std::shared_ptr<LowerMac> lower_mac, bool is_uplink)
: lower_mac_(lower_mac)
, is_uplink_(is_uplink){};
~BitStreamDecoder() = default;

/**
* @brief Process a received symbol.
*
* This function is called by "physical layer" when a bit is ready
* to be processed.
*
* Note that "frame" is actually called "burst" in Tetra doc
*
* @return true if frame (burst) found, false otherwise
*
*/
void process_bit(uint8_t symbol) noexcept;

private:
std::shared_ptr<LowerMac> lower_mac_{};

bool is_synchronized_ = false;
bool is_uplink_{};
std::size_t sync_bit_counter_ = 0;

const std::size_t kFRAME_LEN = 510;

std::vector<uint8_t> frame_{};

// 9.4.4.3.2 Normal training sequence
const std::vector<uint8_t> kNORMAL_TRAINING_SEQ_1 = {1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1,
0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0}; // n1..n22
const std::vector<uint8_t> kNORMAL_TRAINING_SEQ_2 = {0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0,
0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0}; // p1..p22
const std::vector<uint8_t> kNORMAL_TRAINING_SEQ_3_BEGIN = {0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1}; // q11..q22
const std::vector<uint8_t> kNORMAL_TRAINING_SEQ_3_END = {1, 0, 1, 1, 0, 1, 1, 1, 0, 0}; // q1..q10

// 9.4.4.3.3 Extended training sequence
const std::vector<uint8_t> kEXTENDED_TRAINING_SEQ = {1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1,
0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1}; // x1..x30

// 9.4.4.3.4 Synchronisation training sequence
const std::vector<uint8_t> kSYNC_TRAINING_SEQ = {1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0,
1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1}; // y1..y38

/**
* @brief Reset the synchronizer
*
* Burst was matched, we can reset the synchronizer to allow 50 missing frames
* (expressed in burst units = 50 * 510 bits)
*
*/
void reset_synchronizer() noexcept;

/**
* @brief Process frame to decide which type of burst it is then service lower
* MAC
*
*/
void process_downlink_frame() noexcept;

/**
* @brief Return pattern/data comparison errors count at position in data
* vector
*
* @param data Vector to look in from pattern
* @param pattern Pattern to search
* @param position Position in vector to start search
*
* @return Score based on similarity with pattern (differences count between
* vector and pattern)
*
*/
static auto pattern_at_position_score(const std::vector<uint8_t>& data, const std::vector<uint8_t>& pattern,
std::size_t position) noexcept -> std::size_t;
};
83 changes: 12 additions & 71 deletions include/decoder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
* Tassilo Tanneberger
*/

#ifndef TETRA_DECODER_DECODER_HPP
#define TETRA_DECODER_DECODER_HPP
#pragma once

#include <memory>
#include <optional>
#include <string>
#include <vector>

#include <bit_stream_decoder.hpp>
#include <iq_stream_decoder.hpp>
#include <l2/lower_mac.hpp>
#include <reporter.hpp>

Expand All @@ -39,18 +40,19 @@
class Decoder {
public:
Decoder(unsigned int receive_port, unsigned int send_port, bool packed, std::optional<std::string> input_file,
std::optional<std::string> output_file, std::optional<unsigned int> uplink_scrambling_code);
std::optional<std::string> output_file, bool iq_or_bit_stream,
std::optional<unsigned int> uplink_scrambling_code);
~Decoder();

void main_loop();

private:
std::unique_ptr<LowerMac> lower_mac_{};
std::shared_ptr<LowerMac> lower_mac_{};
std::shared_ptr<Reporter> reporter_{};
std::shared_ptr<BitStreamDecoder> bit_stream_decoder_{};
std::unique_ptr<IQStreamDecoder> iq_stream_decoder_{};

bool packed_ = false;
bool is_synchronized_ = false;
std::size_t sync_bit_counter_ = 0;

// input and output file descriptor
int input_fd_ = 0;
Expand All @@ -61,70 +63,9 @@ class Decoder {
// uplink ?
std::optional<unsigned int> uplink_scrambling_code_;

const std::size_t kRX_BUFFER_SIZE = 4096;
const std::size_t kFRAME_LEN = 510;

std::vector<uint8_t> frame_{};

// 9.4.4.3.2 Normal training sequence
const std::vector<uint8_t> kNORMAL_TRAINING_SEQ_1 = {1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1,
0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0}; // n1..n22
const std::vector<uint8_t> kNORMAL_TRAINING_SEQ_2 = {0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0,
0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0}; // p1..p22
const std::vector<uint8_t> kNORMAL_TRAINING_SEQ_3_BEGIN = {0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1}; // q11..q22
const std::vector<uint8_t> kNORMAL_TRAINING_SEQ_3_END = {1, 0, 1, 1, 0, 1, 1, 1, 0, 0}; // q1..q10

// 9.4.4.3.3 Extended training sequence
const std::vector<uint8_t> kEXTENDED_TRAINING_SEQ = {1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1,
0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1}; // x1..x30

// 9.4.4.3.4 Synchronisation training sequence
const std::vector<uint8_t> kSYNC_TRAINING_SEQ = {1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0,
1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1}; // y1..y38
// IQ stream -> true
// bit stream -> false
bool iq_or_bit_stream_;

/**
* @brief Process a received symbol.
*
* This function is called by "physical layer" when a bit is ready
* to be processed.
*
* Note that "frame" is actually called "burst" in Tetra doc
*
* @return true if frame (burst) found, false otherwise
*
*/
void process_bit(uint8_t symbol) noexcept;

/**
* @brief Reset the synchronizer
*
* Burst was matched, we can reset the synchronizer to allow 50 missing frames
* (expressed in burst units = 50 * 510 bits)
*
*/
void reset_synchronizer() noexcept;

/**
* @brief Process frame to decide which type of burst it is then service lower
* MAC
*
*/
void process_downlink_frame() noexcept;

/**
* @brief Return pattern/data comparison errors count at position in data
* vector
*
* @param data Vector to look in from pattern
* @param pattern Pattern to search
* @param position Position in vector to start search
*
* @return Score based on similarity with pattern (differences count between
* vector and pattern)
*
*/
static auto pattern_at_position_score(const std::vector<uint8_t>& data, const std::vector<uint8_t>& pattern,
std::size_t position) noexcept -> std::size_t;
const std::size_t kRX_BUFFER_SIZE = 4096;
};

#endif // TETRA_DECODER_DECODER_HPP
39 changes: 39 additions & 0 deletions include/fixed_queue.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include <deque>
#include <iostream>
#include <queue>

template <typename T, int MaxLen, typename Container = std::deque<T>> class FixedQueue {
private:
Container queue{};

public:
using const_iterator = typename Container::const_iterator;
using const_reverse_iterator = typename Container::const_reverse_iterator;
using const_reference = typename Container::const_reference;

FixedQueue() {
for (auto i = 0; i < MaxLen; i++) {
T default_value{};
queue.push_back(default_value);
}
}

void push(const T& value) {
if (queue.size() == MaxLen) {
queue.pop_front();
}
queue.push_back(value);
}

void pop(const T& value) { std::logic_error("Function not implemented"); }

typename Container::const_iterator cbegin() { return queue.cbegin(); }

typename Container::const_reverse_iterator crbegin() { return queue.crbegin(); }

typename Container::const_iterator cend() { return queue.cend(); }

typename Container::const_reverse_iterator crend() { return queue.crend(); }

typename Container::const_reference operator[](typename Container::size_type pos) const { return queue[pos]; }
};
Loading
Loading