Starting decoder rework

~ Changed indentation layout
~ Replaced some functions from utilities.h with more performant ones
(tested in gr-lora-benchmarks)
+ Added message if spreading factor is set outside of compatible range
+ Added this keyword for class members
+ Added NDEBUG macro to be able to completely remove debugging (for
performance improvement)
~ Extracted multiplications from loops to a precalculation instead
~ Reworked flow of most of the functions
* TODO: Change find_preamble algorithm for better detection
* TODO: Change detect_downchirp algorithm for better sync
pull/27/head
Wosser1sProductions 2017-02-23 21:12:40 +01:00
rodzic 447487380b
commit dbadd1aacb
4 zmienionych plików z 927 dodań i 895 usunięć

Plik diff jest za duży Load Diff

Wyświetl plik

@ -21,36 +21,40 @@
#ifndef INCLUDED_LORA_DECODER_IMPL_H #ifndef INCLUDED_LORA_DECODER_IMPL_H
#define INCLUDED_LORA_DECODER_IMPL_H #define INCLUDED_LORA_DECODER_IMPL_H
#include <lora/decoder.h> #include <liquid/liquid.h>
#include "lora/decoder.h"
#include <list> #include <list>
#include <string> #include <string>
#include <vector> #include <vector>
#include <deque>
#include <fstream> #include <fstream>
#define DECIMATOR_FILTER_SIZE 2*8*1+1 // 2*decim_factor*delay+1 #define DECIMATOR_FILTER_SIZE (2*8*1 + 1) // 2*decim_factor*delay+1
namespace gr { namespace gr {
namespace lora { namespace lora {
typedef enum decoder_state { enum class DecoderState {
DETECT, DETECT,
SYNC, SYNC,
PAUSE, PAUSE,
DECODE_HEADER, DECODE_HEADER,
DECODE_PAYLOAD, DECODE_PAYLOAD,
STOP STOP
} decoder_state; };
class decoder_impl : public decoder class decoder_impl : public decoder {
{
private: private:
decoder_state d_state; DecoderState d_state;
/// using std::complex = gr_complex
std::vector<gr_complex> d_downchirp; std::vector<gr_complex> d_downchirp;
std::vector<gr_complex> d_upchirp; std::vector<gr_complex> d_upchirp;
std::vector<float> d_downchirp_ifreq; std::vector<float> d_downchirp_ifreq;
std::vector<float> d_upchirp_ifreq; std::vector<float> d_upchirp_ifreq;
std::vector<gr_complex> d_fft; std::vector<gr_complex> d_fft;
std::vector<gr_complex> d_mult; std::vector<gr_complex> d_mult;
uint8_t d_sf; uint8_t d_sf;
uint32_t d_bw; uint32_t d_bw;
uint8_t d_cr; uint8_t d_cr;
@ -66,66 +70,74 @@ namespace gr {
uint32_t d_payload_symbols; uint32_t d_payload_symbols;
uint32_t d_payload_length; uint32_t d_payload_length;
uint32_t d_corr_fails; uint32_t d_corr_fails;
std::vector<unsigned int> d_words; std::vector<unsigned int> d_words;
std::vector<uint8_t> d_demodulated; std::vector<uint8_t> d_demodulated;
std::vector<uint8_t> d_words_deshuffled; std::vector<uint8_t> d_words_deshuffled;
std::vector<uint8_t> d_words_dewhitened; std::vector<uint8_t> d_words_dewhitened;
std::vector<uint8_t> d_data; std::vector<uint8_t> d_data;
std::ofstream d_debug_samples; std::ofstream d_debug_samples;
std::ofstream d_debug; std::ofstream d_debug;
fftplan d_q; fftplan d_q;
float d_decim_h[DECIMATOR_FILTER_SIZE]; float d_decim_h[DECIMATOR_FILTER_SIZE];
uint32_t d_corr_decim_factor; uint32_t d_corr_decim_factor;
int d_decim_factor; int d_decim_factor;
firdecim_crcf d_decim; firdecim_crcf d_decim = nullptr;
float d_cfo_estimation; float d_cfo_estimation;
int d_cfo_step; int d_cfo_step;
double d_dt; double d_dt;
bool calc_energy_threshold(gr_complex *samples, int window_size, float threshold); bool calc_energy_threshold(gr_complex *samples, int window_size, float threshold);
void build_ideal_chirps(void); void build_ideal_chirps(void);
void samples_to_file(const std::string path, const gr_complex* v, int length, int elem_size); void samples_to_file(const std::string path, const gr_complex *v, uint32_t length, uint32_t elem_size);
void samples_debug(const gr_complex* v, int length); void samples_debug(const gr_complex *v, uint32_t length);
float sliding_norm_cross_correlate(const float *samples_1, const float *samples_2, uint32_t window, uint32_t slide, int32_t *index); float sliding_norm_cross_correlate(const float *samples_1, const float *samples_2, uint32_t window, uint32_t slide, int32_t *index);
float norm_cross_correlate(const float *samples_1, const float *samples_2, uint32_t window); float norm_cross_correlate(const float *samples_1, const float *samples_2, uint32_t window);
float detect_downchirp(const gr_complex *samples, uint32_t window); float detect_downchirp(const gr_complex *samples, uint32_t window);
float detect_upchirp(const gr_complex *samples_1, uint32_t window, uint32_t slide, int32_t *index); float detect_upchirp(const gr_complex *samples_1, uint32_t window, uint32_t slide, int32_t *index);
float cross_correlate(const gr_complex *samples_1, const gr_complex *samples_2, int window); float cross_correlate(const gr_complex *samples_1, const gr_complex *samples_2, int window);
unsigned int get_shift_fft(gr_complex *samples); unsigned int get_shift_fft(gr_complex *samples);
void determine_cfo(const gr_complex *samples); void determine_cfo(const gr_complex *samples);
void correct_cfo(gr_complex* samples, int num_samples); void correct_cfo(gr_complex *samples, uint32_t num_samples);
int find_preamble_start(gr_complex *samples); int find_preamble_start(gr_complex *samples);
int find_preamble_start_fast(gr_complex *samples, uint32_t len); int find_preamble_start_fast(gr_complex *samples, uint32_t len);
unsigned int max_frequency_gradient_idx(gr_complex *samples); unsigned int max_frequency_gradient_idx(gr_complex *samples);
bool demodulate(gr_complex *samples, bool is_header); bool demodulate(gr_complex *samples, bool is_header);
void deinterleave(int ppm); void deinterleave(uint32_t ppm);
int decode(uint8_t *out_data, bool is_header); int decode(uint8_t *out_data, bool is_header);
void deshuffle(const uint8_t *shuffle_pattern, bool is_header); void deshuffle(const uint8_t *shuffle_pattern, bool is_header);
void dewhiten(const uint8_t *prng); void dewhiten(const uint8_t *prng);
void hamming_decode(uint8_t *out_data); void hamming_decode(uint8_t *out_data);
void nibble_reverse(uint8_t *out_data, int len); void nibble_reverse(uint8_t *out_data, int len);
float stddev(const float *values, int len, float mean); float stddev(const float *values, uint32_t len, float mean);
inline void instantaneous_phase(const gr_complex *in_samples, float *out_iphase, uint32_t window); inline void instantaneous_phase(const gr_complex *in_samples, float *out_iphase, uint32_t window);
void instantaneous_frequency(const gr_complex *in_samples, float *out_ifreq, uint32_t window); void instantaneous_frequency(const gr_complex *in_samples, float *out_ifreq, uint32_t window);
uint8_t lookup_cr(uint8_t bytevalue); uint8_t lookup_cr(uint8_t bytevalue);
void msg_raw_chirp_debug(const gr_complex *raw_samples, uint32_t num_samples); void msg_raw_chirp_debug(const gr_complex *raw_samples, uint32_t num_samples);
void msg_lora_frame(const uint8_t *frame_bytes, uint32_t frame_len); void msg_lora_frame(const uint8_t *frame_bytes, uint32_t frame_len);
public: public:
decoder_impl(float samp_rate, int sf); decoder_impl(float samp_rate, uint8_t sf);
~decoder_impl(); ~decoder_impl();
// Where all the action really happens /// Where all the action really happens
int work(int noutput_items, int work(int noutput_items,
gr_vector_const_void_star& input_items, gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items); gr_vector_void_star& output_items);
// GRC interfaces /// GRC interfaces
virtual void set_sf(uint8_t sf); virtual void set_sf(uint8_t sf);
virtual void set_samp_rate(float samp_rate); virtual void set_samp_rate(float samp_rate);
}; };
} // namespace lora } // namespace lora
} // namespace gr } // namespace gr

Wyświetl plik

@ -1,24 +1,20 @@
#ifndef UTILITIES_H #ifndef UTILITIES_H
#define UTILITIES_H #define UTILITIES_H
#include <cstdint>
namespace gr { namespace gr {
namespace lora { namespace lora {
template <typename T> template <typename T>
std::string to_bin(T v, int element_len_bits) { std::string to_bin(T v, uint32_t bitwidth) {
T mask = 0; unsigned long long maxpow = bitwidth ? (1ull << (bitwidth - 1)) : 0,
unsigned int maxpow = element_len_bits; mask;
std::string result = ""; std::string result = "";
for(int i = 0; i < maxpow; i++) { for (mask = 0x1; mask <= maxpow; mask <<= 1) {
mask = pow(2, i); result += (v & mask) ? "1" : "0";
//std::cout << (unsigned int)v << " AND " << mask << " is " << (v & mask) << std::endl;
if((v & mask) > 0) {
result += "1";
} else {
result += "0";
}
} }
return result; return result;
@ -27,61 +23,48 @@ namespace gr {
template <typename T> template <typename T>
inline void print_vector(std::ostream& out, std::vector<T>& v, std::string prefix, int element_len_bits) { inline void print_vector(std::ostream& out, std::vector<T>& v, std::string prefix, int element_len_bits) {
out << prefix << ": "; out << prefix << ": ";
for(int i = 0; i < v.size(); i++) {
out << to_bin(v[i], element_len_bits) << ", "; for (T x : v)
} out << to_bin(x, element_len_bits) << ", ";
out << std::endl << std::flush; out << std::endl << std::flush;
} }
template <typename T> template <typename T>
inline void print_vector_raw(std::ostream& out, std::vector<T>& v, int element_len_bits) { inline void print_vector_raw(std::ostream& out, std::vector<T>& v, int element_len_bits) {
for(int i = 0; i < v.size(); i++) {
out << to_bin(v[i], element_len_bits); for (T x : v)
} out << to_bin(x, element_len_bits);
out << std::flush; out << std::flush;
} }
bool check_parity(std::string word, bool even) { bool check_parity(std::string& word, bool even) {
int count = 0; size_t count = 0, i = 0;
for(int i = 0; i < 7; i++) { while(i < 7) {
if(word[i] == '1') if (word[i++] == '1')
count += 1; ++count;
} }
if(even) return (count & 0x1) == (even ? 0 : 1);
return ((count % 2) == 0);
else
return (((count+1) % 2) == 0);
} }
uint32_t select_bits(uint32_t data, uint8_t *indices, uint8_t n) { uint32_t select_bits(uint32_t data, uint8_t *indices, uint8_t n) {
uint32_t result = 0; uint32_t r = 0;
for(uint32_t j = 0; j < n; j++) { for(uint8_t i = 0; i < n; ++i)
uint32_t power = pow(2, indices[j]); r |= (data & (1 << indices[i])) ? (1 << i) : 0;
if((data & power) > 0) {
result += pow(2, j);
}
}
return result; return r;
} }
void fec_extract_data_only(uint8_t *in_data, uint32_t len, uint8_t *indices, uint8_t n, uint8_t *out_data) { void fec_extract_data_only(uint8_t *in_data, uint32_t len, uint8_t *indices, uint8_t n, uint8_t *out_data) {
uint8_t out_index = 0; for (uint32_t i = 0, out_index = 0; i < len; i += 2) {
uint8_t d1 = (select_bits(in_data[i], indices, n) & 0xff) << 4;
d1 |= (i + 1 < len) ? select_bits(in_data[i + 1], indices, n) & 0xff : 0;
for(uint32_t i = 0; i < len; i+=2) { out_data[out_index++] = d1;
uint8_t d1 = 0;
d1 = select_bits(in_data[i], indices, n) & 0xff;
uint8_t d2 = 0;
if(i+1 < len)
d2 = select_bits(in_data[i+1], indices, n) & 0xff;
out_data[out_index] = (d1 << 4) | d2;
out_index++;
} }
} }
@ -127,11 +110,7 @@ namespace gr {
// p4 01010101 // p4 01010101
// Syndrome matrix = columns of "cover bits" above // Syndrome matrix = columns of "cover bits" above
uint8_t H[16]; uint8_t H[16] = { 0 };
for(uint8_t i = 0; i < 16; i++) {
H[i] = 0;
}
uint8_t i0 = pack_nibble(1, 0, 0, 0); uint8_t i0 = pack_nibble(1, 0, 0, 0);
uint8_t i1 = pack_nibble(0, 1, 1, 1); uint8_t i1 = pack_nibble(0, 1, 1, 1);
@ -164,9 +143,8 @@ namespace gr {
uint8_t syndrome = pack_nibble((uint8_t)(p1 != p1c), (uint8_t)(p2 != p2c), (uint8_t)(p3 != p3c), (uint8_t)(p4 != p4c)); uint8_t syndrome = pack_nibble((uint8_t)(p1 != p1c), (uint8_t)(p2 != p2c), (uint8_t)(p3 != p3c), (uint8_t)(p4 != p4c));
if(syndrome != 0) { if (syndrome) {
uint8_t index = H[syndrome]; v ^= pow2[ H[syndrome] ];
v = v ^ pow2[index];
} }
uint8_t d1 = bit(v, 1); uint8_t d1 = bit(v, 1);
@ -179,17 +157,11 @@ namespace gr {
// Manual Hamming // Manual Hamming
void hamming_decode_soft(uint8_t *words, uint32_t len, uint8_t *out_data) { void hamming_decode_soft(uint8_t *words, uint32_t len, uint8_t *out_data) {
uint32_t out_index = 0; for (uint32_t i = 0, out_index = 0; i < len; i += 2) {
for(int i = 0; i < len; i+=2) { uint8_t d1 = hamming_decode_soft_byte(words[i]) << 4;
uint8_t d1 = 0; d1 |= (i + 1 < len) ? hamming_decode_soft_byte(words[i + 1]) : 0;
d1 = hamming_decode_soft_byte(words[i]);
uint8_t d2 = 0; out_data[out_index++] = d1;
if(i+1 < len)
d2 = hamming_decode_soft_byte(words[i+1]);
out_data[out_index] = (d1 << 4) | d2;
out_index++;
} }
} }