mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-05-24 11:12:27 -04:00
M17: M17Randomizer code cleanup
This commit is contained in:
parent
ca24d1bc57
commit
e29581a0b2
@ -8,6 +8,7 @@ set(modemm17_SOURCES
|
|||||||
LinkSetupFrame.cpp
|
LinkSetupFrame.cpp
|
||||||
M17Demodulator.cpp
|
M17Demodulator.cpp
|
||||||
M17Modulator.cpp
|
M17Modulator.cpp
|
||||||
|
M17Randomizer.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(modemm17_HEADERS
|
set(modemm17_HEADERS
|
||||||
@ -35,7 +36,6 @@ set(modemm17_HEADERS
|
|||||||
M17Synchronizer.h
|
M17Synchronizer.h
|
||||||
PhaseEstimator.h
|
PhaseEstimator.h
|
||||||
PolynomialInterleaver.h
|
PolynomialInterleaver.h
|
||||||
queue.h
|
|
||||||
SlidingDFT.h
|
SlidingDFT.h
|
||||||
SymbolEvm.h
|
SymbolEvm.h
|
||||||
Trellis.h
|
Trellis.h
|
||||||
|
@ -41,7 +41,7 @@ struct M17FrameDecoder
|
|||||||
{
|
{
|
||||||
static const size_t MAX_LICH_FRAGMENT = 5;
|
static const size_t MAX_LICH_FRAGMENT = 5;
|
||||||
|
|
||||||
M17Randomizer<368> derandomize_;
|
M17Randomizer derandomize_;
|
||||||
PolynomialInterleaver<45, 92, 368> interleaver_;
|
PolynomialInterleaver<45, 92, 368> interleaver_;
|
||||||
Trellis<4,2> trellis_{makeTrellis<4, 2>({031,027})};
|
Trellis<4,2> trellis_{makeTrellis<4, 2>({031,027})};
|
||||||
Viterbi<decltype(trellis_), 4> viterbi_{trellis_};
|
Viterbi<decltype(trellis_), 4> viterbi_{trellis_};
|
||||||
|
@ -118,7 +118,7 @@ public:
|
|||||||
{
|
{
|
||||||
lsf.fill(0);
|
lsf.fill(0);
|
||||||
|
|
||||||
M17Randomizer<368> randomizer;
|
M17Randomizer randomizer;
|
||||||
PolynomialInterleaver<45, 92, 368> interleaver;
|
PolynomialInterleaver<45, 92, 368> interleaver;
|
||||||
CRC16 crc(0x5935, 0xFFFF);
|
CRC16 crc(0x5935, 0xFFFF);
|
||||||
|
|
||||||
@ -289,7 +289,7 @@ public:
|
|||||||
const std::array<uint8_t, 25> packet
|
const std::array<uint8_t, 25> packet
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
M17Randomizer<368> randomizer;
|
M17Randomizer randomizer;
|
||||||
PolynomialInterleaver<45, 92, 368> interleaver;
|
PolynomialInterleaver<45, 92, 368> interleaver;
|
||||||
|
|
||||||
std::array<uint8_t, 26> packet_assembly;
|
std::array<uint8_t, 26> packet_assembly;
|
||||||
@ -446,7 +446,7 @@ public:
|
|||||||
|
|
||||||
static void interleave_and_randomize(std::array<int8_t, 368>& punctured)
|
static void interleave_and_randomize(std::array<int8_t, 368>& punctured)
|
||||||
{
|
{
|
||||||
M17Randomizer<368> randomizer;
|
M17Randomizer randomizer;
|
||||||
PolynomialInterleaver<45, 92, 368> interleaver;
|
PolynomialInterleaver<45, 92, 368> interleaver;
|
||||||
|
|
||||||
interleaver.interleave(punctured);
|
interleaver.interleave(punctured);
|
||||||
|
14
modemm17/M17Randomizer.cpp
Normal file
14
modemm17/M17Randomizer.cpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include "M17Randomizer.h"
|
||||||
|
|
||||||
|
namespace modemm17
|
||||||
|
{
|
||||||
|
|
||||||
|
const std::array<uint8_t, 46> M17Randomizer::DC = std::array<uint8_t, 46>{
|
||||||
|
0xd6, 0xb5, 0xe2, 0x30, 0x82, 0xFF, 0x84, 0x62,
|
||||||
|
0xba, 0x4e, 0x96, 0x90, 0xd8, 0x98, 0xdd, 0x5d,
|
||||||
|
0x0c, 0xc8, 0x52, 0x43, 0x91, 0x1d, 0xf8, 0x6e,
|
||||||
|
0x68, 0x2F, 0x35, 0xda, 0x14, 0xea, 0xcd, 0x76,
|
||||||
|
0x19, 0x8d, 0xd5, 0x80, 0xd1, 0x33, 0x87, 0x13,
|
||||||
|
0x57, 0x18, 0x2d, 0x29, 0x78, 0xc3};
|
||||||
|
|
||||||
|
}
|
@ -9,28 +9,14 @@
|
|||||||
namespace modemm17
|
namespace modemm17
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
// M17 randomization matrix.
|
|
||||||
static const std::array<uint8_t, 46> DC = std::array<uint8_t, 46>{
|
|
||||||
0xd6, 0xb5, 0xe2, 0x30, 0x82, 0xFF, 0x84, 0x62,
|
|
||||||
0xba, 0x4e, 0x96, 0x90, 0xd8, 0x98, 0xdd, 0x5d,
|
|
||||||
0x0c, 0xc8, 0x52, 0x43, 0x91, 0x1d, 0xf8, 0x6e,
|
|
||||||
0x68, 0x2F, 0x35, 0xda, 0x14, 0xea, 0xcd, 0x76,
|
|
||||||
0x19, 0x8d, 0xd5, 0x80, 0xd1, 0x33, 0x87, 0x13,
|
|
||||||
0x57, 0x18, 0x2d, 0x29, 0x78, 0xc3};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t N = 368>
|
|
||||||
struct M17Randomizer
|
struct M17Randomizer
|
||||||
{
|
{
|
||||||
std::array<int8_t, N> dc_;
|
std::array<int8_t, 368> dc_;
|
||||||
|
|
||||||
M17Randomizer()
|
M17Randomizer()
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (auto b : detail::DC)
|
for (auto b : DC)
|
||||||
{
|
{
|
||||||
for (size_t j = 0; j != 8; ++j)
|
for (size_t j = 0; j != 8; ++j)
|
||||||
{
|
{
|
||||||
@ -40,39 +26,24 @@ struct M17Randomizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Randomize and derandomize are the same operation.
|
// Randomize and derandomize are the same operation.
|
||||||
void operator()(std::array<int8_t, N>& frame)
|
void operator()(std::array<int8_t, 368>& frame)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i != N; ++i)
|
for (size_t i = 0; i != 368; ++i)
|
||||||
{
|
{
|
||||||
frame[i] *= dc_[i];
|
frame[i] *= dc_[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void randomize(std::array<int8_t, N>& frame)
|
void randomize(std::array<int8_t, 368>& frame)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i != N; ++i)
|
for (size_t i = 0; i != 368; ++i)
|
||||||
{
|
{
|
||||||
frame[i] ^= (dc_[i] == -1);
|
frame[i] ^= (dc_[i] == -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
private:
|
||||||
|
static const std::array<uint8_t, 46> DC;
|
||||||
template <size_t N = 46>
|
|
||||||
struct M17ByteRandomizer
|
|
||||||
{
|
|
||||||
// Randomize and derandomize are the same operation.
|
|
||||||
void operator()(std::array<uint8_t, N>& frame)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i != N; ++i)
|
|
||||||
{
|
|
||||||
for (size_t j = 8; j != 0; --j)
|
|
||||||
{
|
|
||||||
uint8_t mask = 1 << (j - 1);
|
|
||||||
frame[i] = (frame[i] & ~mask) | ((frame[i] & mask) ^ (detail::DC[i] & mask));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,24 +21,22 @@ template <size_t SampleRate, size_t Frequency, size_t Accuracy = 1000>
|
|||||||
class SlidingDFT
|
class SlidingDFT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using ComplexType = std::complex<float>;
|
|
||||||
|
|
||||||
SlidingDFT()
|
SlidingDFT()
|
||||||
{
|
{
|
||||||
samples_.fill(0);
|
samples_.fill(0);
|
||||||
float pi2 = M_PI * 2.0f;
|
float pi2 = M_PI * 2.0f;
|
||||||
float kth = float(Frequency) / float(SampleRate);
|
float kth = float(Frequency) / float(SampleRate);
|
||||||
coeff_ = std::exp(-ComplexType{0, 1} * pi2 * kth);
|
coeff_ = std::exp(-std::complex<float>{0, 1} * pi2 * kth);
|
||||||
}
|
}
|
||||||
|
|
||||||
ComplexType operator()(float sample)
|
std::complex<float> operator()(float sample)
|
||||||
{
|
{
|
||||||
auto index = index_;
|
auto index = index_;
|
||||||
index_ += 1;
|
index_ += 1;
|
||||||
if (index_ == (SampleRate / Accuracy)) index_ = 0;
|
if (index_ == (SampleRate / Accuracy)) index_ = 0;
|
||||||
|
|
||||||
float delta = sample - samples_[index];
|
float delta = sample - samples_[index];
|
||||||
ComplexType result = (result_ + delta) * coeff_;
|
std::complex<float> result = (result_ + delta) * coeff_;
|
||||||
result_ = result * float(0.999999999999999);
|
result_ = result * float(0.999999999999999);
|
||||||
samples_[index] = sample;
|
samples_[index] = sample;
|
||||||
prev_index_ = index;
|
prev_index_ = index;
|
||||||
@ -46,9 +44,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ComplexType coeff_;
|
std::complex<float> coeff_;
|
||||||
std::array<float, (SampleRate / Accuracy)> samples_;
|
std::array<float, (SampleRate / Accuracy)> samples_;
|
||||||
ComplexType result_{0,0};
|
std::complex<float> result_{0,0};
|
||||||
size_t index_ = 0;
|
size_t index_ = 0;
|
||||||
size_t prev_index_ = (SampleRate / Accuracy) - 1;
|
size_t prev_index_ = (SampleRate / Accuracy) - 1;
|
||||||
};
|
};
|
||||||
@ -69,8 +67,7 @@ template <size_t SampleRate, size_t N, size_t K>
|
|||||||
class NSlidingDFT
|
class NSlidingDFT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using ComplexType = std::complex<float>;
|
using result_type = std::array<std::complex<float>, K>;
|
||||||
using result_type = std::array<ComplexType, K>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct the DFT with an array of frequencies. These frequencies
|
* Construct the DFT with an array of frequencies. These frequencies
|
||||||
@ -107,17 +104,17 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::array<ComplexType, K> coeff_;
|
const std::array<std::complex<float>, K> coeff_;
|
||||||
std::array<float, N> samples_;
|
std::array<float, N> samples_;
|
||||||
std::array<ComplexType, K> result_{0,0};
|
std::array<std::complex<float>, K> result_{0,0};
|
||||||
size_t index_ = 0;
|
size_t index_ = 0;
|
||||||
size_t prev_index_ = N - 1;
|
size_t prev_index_ = N - 1;
|
||||||
|
|
||||||
static constexpr std::array<ComplexType, K>
|
static constexpr std::array<std::complex<float>, K>
|
||||||
make_coefficients(const std::array<size_t, K>& frequencies)
|
make_coefficients(const std::array<size_t, K>& frequencies)
|
||||||
{
|
{
|
||||||
ComplexType j = ComplexType{0, 1};
|
std::complex<float> j = std::complex<float>{0, 1};
|
||||||
std::array<ComplexType, K> result;
|
std::array<std::complex<float>, K> result;
|
||||||
float pi2 = M_PI * 2.0f;
|
float pi2 = M_PI * 2.0f;
|
||||||
for (size_t i = 0; i != K; ++i)
|
for (size_t i = 0; i != K; ++i)
|
||||||
{
|
{
|
||||||
|
251
modemm17/queue.h
251
modemm17/queue.h
@ -1,251 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <list>
|
|
||||||
#include <iterator>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <thread>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
namespace modemm17
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A thread-safe queue
|
|
||||||
*/
|
|
||||||
template <typename T, size_t SIZE>
|
|
||||||
class queue
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
using mutex_type = std::mutex;
|
|
||||||
using lock_type = std::unique_lock<mutex_type>;
|
|
||||||
using guard_type = std::lock_guard<mutex_type>;
|
|
||||||
|
|
||||||
enum class State {OPEN, CLOSING, CLOSED};
|
|
||||||
|
|
||||||
std::list<T> queue_;
|
|
||||||
size_t size_ = 0;
|
|
||||||
State state_ = State::OPEN;
|
|
||||||
mutable mutex_type mutex_;
|
|
||||||
std::condition_variable full_;
|
|
||||||
std::condition_variable empty_;
|
|
||||||
|
|
||||||
queue(queue&) = delete;
|
|
||||||
queue& operator=(const queue&) = delete;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
static constexpr auto forever = std::chrono::seconds::max();
|
|
||||||
|
|
||||||
/// The data type stored in the queue.
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
/// A reference to an element stored in the queue.
|
|
||||||
using reference = value_type&;
|
|
||||||
|
|
||||||
/// A const reference to an element stored in the queue.
|
|
||||||
using const_reference = value_type const&;
|
|
||||||
|
|
||||||
/// A pointer to an element stored in a Queue.
|
|
||||||
using pointer = value_type*;
|
|
||||||
|
|
||||||
/// A pointer to an element stored in a Queue.
|
|
||||||
using const_pointer = const value_type*;
|
|
||||||
|
|
||||||
queue()
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the next item in the queue.
|
|
||||||
*
|
|
||||||
* @param[out] val is an object into which the object will be moved
|
|
||||||
* or copied.
|
|
||||||
* @param[in] timeout is the duration to wait for an item to appear
|
|
||||||
* in the queue (default is forever, duration::max()).
|
|
||||||
*
|
|
||||||
* @return true if a value was returned, otherwise false.
|
|
||||||
*
|
|
||||||
* @note The return value me be false if either the timeout expires
|
|
||||||
* or the queue is closed.
|
|
||||||
*/
|
|
||||||
template<class Clock>
|
|
||||||
bool get_until(reference val, std::chrono::time_point<Clock> when)
|
|
||||||
{
|
|
||||||
lock_type lock(mutex_);
|
|
||||||
|
|
||||||
while (queue_.empty())
|
|
||||||
{
|
|
||||||
if (State::CLOSED == state_)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty_.wait_until(lock, when) == std::cv_status::timeout)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val = std::move(queue_.front());
|
|
||||||
queue_.pop_front();
|
|
||||||
size_ -= 1;
|
|
||||||
|
|
||||||
if (state_ == State::CLOSING && queue_.empty())
|
|
||||||
{
|
|
||||||
state_ == State::CLOSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
full_.notify_one();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the next item in the queue.
|
|
||||||
*
|
|
||||||
* @param[out] val is an object into which the object will be moved
|
|
||||||
* or copied.
|
|
||||||
* @param[in] timeout is the duration to wait for an item to appear
|
|
||||||
* in the queue (default is forever, duration::max()).
|
|
||||||
*
|
|
||||||
* @return true if a value was returned, otherwise false.
|
|
||||||
*
|
|
||||||
* @note The return value me be false if either the timeout expires
|
|
||||||
* or the queue is closed.
|
|
||||||
*/
|
|
||||||
template<class Rep = int64_t, class Period = std::ratio<1>>
|
|
||||||
bool get(reference val, std::chrono::duration<Rep, Period> timeout = std::chrono::duration<Rep, Period>::max())
|
|
||||||
{
|
|
||||||
lock_type lock(mutex_);
|
|
||||||
|
|
||||||
while (queue_.empty())
|
|
||||||
{
|
|
||||||
if (State::CLOSED == state_)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty_.wait_for(lock, timeout) == std::cv_status::timeout)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val = std::move(queue_.front());
|
|
||||||
queue_.pop_front();
|
|
||||||
size_ -= 1;
|
|
||||||
|
|
||||||
if (state_ == State::CLOSING && queue_.empty())
|
|
||||||
{
|
|
||||||
state_ == State::CLOSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
full_.notify_one();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put an item on the queue.
|
|
||||||
*
|
|
||||||
* @param[in] val is the element to be appended to the queue.
|
|
||||||
* @param[in] timeout is the duration to wait until queue there is room
|
|
||||||
* for more items on the queue (default is forever -- duration::max()).
|
|
||||||
*
|
|
||||||
* @return true if a value was put on the queue, otherwise false.
|
|
||||||
*
|
|
||||||
* @note The return value me be false if either the timeout expires
|
|
||||||
* or the queue is closed.
|
|
||||||
*/
|
|
||||||
template<typename U, class Rep = int64_t, class Period = std::ratio<1>>
|
|
||||||
bool put(U&& val, std::chrono::duration<Rep, Period> timeout = std::chrono::duration<Rep, Period>::max())
|
|
||||||
{
|
|
||||||
// Get the queue mutex.
|
|
||||||
lock_type lock(mutex_);
|
|
||||||
|
|
||||||
if (SIZE == size_)
|
|
||||||
{
|
|
||||||
if (timeout.count() == 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto expiration = std::chrono::system_clock::now() + timeout;
|
|
||||||
|
|
||||||
while (SIZE == size_)
|
|
||||||
{
|
|
||||||
if (State::OPEN != state_)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (full_.wait_until(lock, expiration) == std::cv_status::timeout)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (State::OPEN != state_)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
queue_.emplace_back(std::forward<U>(val));
|
|
||||||
size_ += 1;
|
|
||||||
|
|
||||||
empty_.notify_one();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
void close()
|
|
||||||
{
|
|
||||||
guard_type lock(mutex_);
|
|
||||||
|
|
||||||
state_ = (queue_.empty() ? State::CLOSED : State::CLOSING);
|
|
||||||
|
|
||||||
full_.notify_all();
|
|
||||||
empty_.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_open() const
|
|
||||||
{
|
|
||||||
return State::OPEN == state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_closed() const
|
|
||||||
{
|
|
||||||
return State::CLOSED == state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the number of items in the queue.
|
|
||||||
*/
|
|
||||||
size_t size() const
|
|
||||||
{
|
|
||||||
guard_type lock(mutex_);
|
|
||||||
return size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the number of items in the queue.
|
|
||||||
*/
|
|
||||||
bool empty() const
|
|
||||||
{
|
|
||||||
guard_type lock(mutex_);
|
|
||||||
return size_ == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the capacity of the queue.
|
|
||||||
*/
|
|
||||||
static constexpr size_t capacity()
|
|
||||||
{
|
|
||||||
return SIZE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // modemm17
|
|
Loading…
x
Reference in New Issue
Block a user