Some progress on different SFs and CRs

pull/21/head
Pieter Robyns 2016-09-16 17:07:28 +02:00
rodzic 90486a0ed0
commit 380be3e20d
9 zmienionych plików z 111 dodań i 83 usunięć

Wyświetl plik

@ -18,6 +18,5 @@
# Boston, MA 02110-1301, USA. # Boston, MA 02110-1301, USA.
install(FILES install(FILES
lora_decoder.xml
lora_receiver.xml DESTINATION share/gnuradio/grc/blocks lora_receiver.xml DESTINATION share/gnuradio/grc/blocks
) )

Wyświetl plik

@ -1,30 +0,0 @@
<?xml version="1.0"?>
<block>
<name>LoRa Decoder</name>
<key>lora_decoder</key>
<category>lora</category>
<import>import lora</import>
<make>lora.lora_decoder()</make>
<sink>
<name>in</name>
<type>float</type>
</sink>
<sink>
<name>in</name>
<type>complex</type>
</sink>
<source>
<name>out</name>
<type>float</type>
<optional>1</optional>
</source>
<source>
<name>out</name>
<type>float</type>
<optional>1</optional>
</source>
</block>

Wyświetl plik

@ -4,13 +4,13 @@
<key>lora_lora_receiver</key> <key>lora_lora_receiver</key>
<category>lora</category> <category>lora</category>
<import>import lora</import> <import>import lora</import>
<make>lora.lora_receiver($in_samp_rate, $freq, $offset, $finetune, $realtime)</make> <make>lora.lora_receiver($in_samp_rate, $freq, $offset, $sf, $realtime)</make>
<callback>set_finetune($finetune)</callback> <callback>set_sf($sf)</callback>
<callback>set_offset($offset)</callback> <callback>set_offset($offset)</callback>
<param> <param>
<name>Finetune</name> <name>Spreading factor</name>
<key>finetune</key> <key>sf</key>
<type>int</type> <type>int</type>
</param> </param>

Wyświetl plik

@ -703,9 +703,9 @@ namespace gr {
* class. lora::decoder::make is the public interface for * class. lora::decoder::make is the public interface for
* creating new instances. * creating new instances.
*/ */
static sptr make(int finetune); static sptr make(int sf);
virtual void set_finetune(int32_t finetune) = 0; virtual void set_sf(uint8_t sf) = 0;
}; };
} // namespace lora } // namespace lora

Wyświetl plik

@ -30,8 +30,6 @@
#include "tables.h" #include "tables.h"
#include "utilities.h" #include "utilities.h"
#define CORRELATION_SEARCH_RANGE 1024
#define DELAY_AFTER_SYNC 262
//#define NO_TMP_WRITES 1 //#define NO_TMP_WRITES 1
//#define CFO_CORRECT 1 //#define CFO_CORRECT 1
@ -39,34 +37,35 @@ namespace gr {
namespace lora { namespace lora {
decoder::sptr decoder::sptr
decoder::make(int finetune) { decoder::make(int sf) {
return gnuradio::get_initial_sptr return gnuradio::get_initial_sptr
(new decoder_impl(finetune)); (new decoder_impl(sf));
} }
/* /*
* The private constructor * The private constructor
*/ */
decoder_impl::decoder_impl(int finetune) : gr::sync_block("decoder", decoder_impl::decoder_impl(int sf) : gr::sync_block("decoder",
gr::io_signature::make(1, -1, sizeof(gr_complex)), gr::io_signature::make(1, -1, sizeof(gr_complex)),
gr::io_signature::make(0, 2, sizeof(float))) { gr::io_signature::make(0, 2, sizeof(float))) {
d_state = DETECT; d_state = DETECT;
d_debug_samples.open("/tmp/grlora_debug", std::ios::out | std::ios::binary); d_debug_samples.open("/tmp/grlora_debug", std::ios::out | std::ios::binary);
d_debug.open("/tmp/grlora_debug_txt", std::ios::out); d_debug.open("/tmp/grlora_debug_txt", std::ios::out);
d_sf = 7; // Only affects PHY send d_sf = sf; // Only affects PHY send
d_bw = 125000; d_bw = 125000;
d_cr = 4; d_cr = 4;
d_bits_per_second = (double)d_sf * 1.0f / (pow(2.0f, d_sf) / d_bw); d_bits_per_second = (double)d_sf * (4.0f/4.0f+d_cr) / (pow(2.0f, d_sf) / d_bw);
d_samples_per_second = 1000000; d_samples_per_second = 1000000;
d_symbols_per_second = (double)d_bw / pow(2.0f, d_sf); d_symbols_per_second = (double)d_bw / pow(2.0f, d_sf);
d_bits_per_symbol = (uint32_t)(d_bits_per_second / d_symbols_per_second); d_bits_per_symbol = (uint32_t)(d_bits_per_second / d_symbols_per_second);
d_samples_per_symbol = (uint32_t)(d_samples_per_second / d_symbols_per_second); d_samples_per_symbol = (uint32_t)(d_samples_per_second / d_symbols_per_second);
d_delay_after_sync = d_samples_per_symbol / 4; //262;
d_delay_after_sync += (uint32_t)d_delay_after_sync * 2.4f / 100.0f;
d_corr_decim_factor = 8; // samples_per_symbol / corr_decim_factor = correlation window. Also serves as preamble decimation factor
d_number_of_bins = (uint32_t)pow(2, d_sf); d_number_of_bins = (uint32_t)pow(2, d_sf);
d_number_of_bins_hdr = d_number_of_bins / 4; d_number_of_bins_hdr = d_number_of_bins / 4;
d_compression = 8;
d_payload_symbols = 0; d_payload_symbols = 0;
d_finetune = finetune;
d_cfo_estimation = 0.0f; d_cfo_estimation = 0.0f;
d_cfo_step = 0; d_cfo_step = 0;
d_dt = 1.0f / d_samples_per_second; d_dt = 1.0f / d_samples_per_second;
@ -287,18 +286,18 @@ namespace gr {
float samples_ifreq[window]; float samples_ifreq[window];
instantaneous_frequency(samples, samples_ifreq, window); instantaneous_frequency(samples, samples_ifreq, window);
return sliding_norm_cross_correlate(samples_ifreq, &d_upchirp_ifreq[0], window, 128, index); return sliding_norm_cross_correlate(samples_ifreq, &d_upchirp_ifreq[0], window, d_samples_per_symbol / d_corr_decim_factor, index);
} }
unsigned int decoder_impl::get_shift_fft(gr_complex* samples) { unsigned int decoder_impl::get_shift_fft(gr_complex* samples) {
float fft_mag[d_number_of_bins]; float fft_mag[d_number_of_bins];
gr_complex mult_hf[d_samples_per_symbol]; gr_complex mult_hf[d_samples_per_symbol];
/*#ifdef CFO_CORRECT #ifdef CFO_CORRECT
determine_cfo(&samples[0]); determine_cfo(&samples[0]);
std::cout << "CFO: " << d_cfo_estimation << std::endl; d_debug << "CFO: " << d_cfo_estimation << std::endl;
correct_cfo(&samples[0], d_samples_per_symbol); correct_cfo(&samples[0], d_samples_per_symbol);
#endif*/ #endif
samples_to_file("/tmp/data", &samples[0], d_samples_per_symbol, sizeof(gr_complex)); samples_to_file("/tmp/data", &samples[0], d_samples_per_symbol, sizeof(gr_complex));
@ -386,17 +385,15 @@ namespace gr {
// Decode (actually gray encode) the bin to get the symbol value // Decode (actually gray encode) the bin to get the symbol value
unsigned int word = gray_encode(bin_idx); unsigned int word = gray_encode(bin_idx);
d_debug << bin_idx << " " << to_bin(word, is_header ? 5 : 7) << " ! " << bin_idx_test << std::endl; d_debug << to_bin(word, is_header ? d_sf-2 : d_sf) << " " << bin_idx << std::endl;
d_words.push_back(word); d_words.push_back(word);
// Look for 4+cr symbols and stop // Look for 4+cr symbols and stop
if(d_words.size() == (4 + d_cr)) { if(d_words.size() == (4 + d_cr)) {
// Deinterleave // Deinterleave
if(is_header) { if(is_header) {
//print_vector(d_words, "M", d_sf - 2);
deinterleave(d_sf - 2); deinterleave(d_sf - 2);
} else { } else {
//print_vector(d_words, "M", d_sf);
deinterleave(d_sf); deinterleave(d_sf);
} }
@ -473,6 +470,8 @@ namespace gr {
if(!is_header) if(!is_header)
std::cout << result.str() << std::endl; std::cout << result.str() << std::endl;
else
std::cout << result.str();
return 0; return 0;
} }
@ -513,9 +512,22 @@ namespace gr {
} }
void decoder_impl::hamming_decode(uint8_t* out_data) { void decoder_impl::hamming_decode(uint8_t* out_data) {
unsigned int n = ceil(d_words_dewhitened.size() * 4.0 / 8.0); unsigned int n = ceil(d_words_dewhitened.size() * 4.0f / (4.0f + d_cr));
fec_scheme fs = LIQUID_FEC_HAMMING84; fec_scheme fs = LIQUID_FEC_HAMMING84;
if(d_cr == 4)
fs = LIQUID_FEC_HAMMING84;
else if(d_cr == 3)
fs = LIQUID_FEC_HAMMING74;
else if(d_cr == 2)
fs = LIQUID_FEC_HAMMING128;
else if(d_cr == 1) { // TODO: Temporary, since Liquid doesn't support 4/5 Hamming so we need to implement it ourselves / extend Liquid.
uint8_t indices[4] = {1, 2, 3, 5};
fec_extract_data_only(&d_words_dewhitened[0], d_words_dewhitened.size(), indices, 4, out_data);
d_words_dewhitened.clear();
return;
}
unsigned int k = fec_get_enc_msg_length(fs, n); unsigned int k = fec_get_enc_msg_length(fs, n);
fec hamming = fec_create(fs, NULL); fec hamming = fec_create(fs, NULL);
@ -548,10 +560,10 @@ namespace gr {
} }
float sum = 0.0f; float sum = 0.0f;
for(int i = 0; i < d_samples_per_symbol; i++) { for(int i = 0; i < d_samples_per_symbol-1; i++) {
sum += instantaneous_freq[i]; sum += instantaneous_freq[i];
} }
sum /= d_samples_per_symbol; sum /= d_samples_per_symbol-1;
d_cfo_estimation = sum; d_cfo_estimation = sum;
@ -575,26 +587,32 @@ namespace gr {
} }
int decoder_impl::find_preamble_start_fast(gr_complex* samples, uint32_t len) { int decoder_impl::find_preamble_start_fast(gr_complex* samples, uint32_t len) {
int decimation = d_decim_factor; // TODO: Replace with d_decimation int decimation = d_corr_decim_factor;
int decim_size = d_samples_per_symbol / decimation; int decim_size = d_samples_per_symbol / decimation;
float decim[decim_size]; float decim[decimation];
float gradient[decim_size]; float gradient[decimation];
uint32_t rising = 0;
uint32_t rising_required = 2;
gradient[0] = 0.0f;
for(int i = 0; i < decim_size; i++) { for(int i = 0; i < decimation; i++) {
float s[2] = { float s[2] = {
arg(samples[i*decimation]), arg(samples[i*decim_size]),
arg(samples[(i+1)*decimation]) arg(samples[(i+1)*decim_size])
}; };
liquid_unwrap_phase(s, 2); liquid_unwrap_phase(s, 2);
decim[i] = (s[1] - s[0]) / (2.0f * M_PI) * d_samples_per_second; decim[i] = (s[1] - s[0]) / (2.0f * M_PI) * d_samples_per_second;
} }
for(int i = 1; i < decim_size; i++) { for(int i = 1; i < decimation; i++) {
gradient[i] = decim[i] - decim[i-1]; gradient[i] = decim[i] - decim[i-1];
if(gradient[i] <= -20000) { if(gradient[i] > gradient[i-1])
return i*decimation; rising++;
if(rising >= rising_required && gradient[i] <= -20000) { // TODO: Make this a bit more logical, e.g. d_bw / decimation * 2 -> 2 steps down
return i*decim_size;
} }
//d_debug << "G:" << gradient[i] << std::endl; //d_debug << "G:" << gradient[i] << std::endl;
} }
@ -602,6 +620,31 @@ namespace gr {
return -1; return -1;
} }
uint8_t decoder_impl::lookup_cr(uint8_t bytevalue) {
switch (bytevalue & 0x0f) {
case 0x0a: {
return 4;
break;
}
case 0x0b: {
return 3;
break;
}
case 0x0c: {
return 2;
break;
}
case 0x08: {
return 1;
break;
}
default: {
return 4;
break;
}
}
}
int decoder_impl::work(int noutput_items, int decoder_impl::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) {
@ -635,9 +678,10 @@ namespace gr {
if(c > 0.8f) { if(c > 0.8f) {
d_debug << "SYNC: " << c << std::endl; d_debug << "SYNC: " << c << std::endl;
// Debug stuff // Debug stuff
samples_to_file("/tmp/sync", &input[0], CORRELATION_SEARCH_RANGE, sizeof(gr_complex)); samples_to_file("/tmp/sync", &input[0], d_samples_per_symbol, sizeof(gr_complex));
d_state = PAUSE; d_state = PAUSE;
d_cr = 4;
consume_each(d_samples_per_symbol); consume_each(d_samples_per_symbol);
} else { } else {
d_corr_fails++; d_corr_fails++;
@ -651,8 +695,8 @@ namespace gr {
case PAUSE: { case PAUSE: {
d_state = DECODE_HEADER; d_state = DECODE_HEADER;
samples_debug(input, d_samples_per_symbol + DELAY_AFTER_SYNC); samples_debug(input, d_samples_per_symbol + d_delay_after_sync);
consume_each(d_samples_per_symbol + DELAY_AFTER_SYNC); consume_each(d_samples_per_symbol + d_delay_after_sync);
break; break;
} }
case DECODE_HEADER: { case DECODE_HEADER: {
@ -663,7 +707,7 @@ namespace gr {
nibble_reverse(decoded, 1); // TODO: Why? nibble_reverse(decoded, 1); // TODO: Why?
d_payload_length = decoded[0]; d_payload_length = decoded[0];
d_cr = 4; // TODO: Get from header instead of hardcode d_cr = lookup_cr(decoded[2]);
int symbols_per_block = d_cr + 4; int symbols_per_block = d_cr + 4;
int bits_needed = ((d_payload_length * 8) + 16) * (symbols_per_block / 4); int bits_needed = ((d_payload_length * 8) + 16) * (symbols_per_block / 4);
@ -710,8 +754,9 @@ namespace gr {
return 0; return 0;
} }
void decoder_impl::set_finetune(int32_t finetune) { void decoder_impl::set_sf(uint8_t sf) {
d_finetune = finetune; if(sf >= 7 && sf <= 13)
d_sf = sf;
} }
} /* namespace lora */ } /* namespace lora */

Wyświetl plik

@ -51,11 +51,11 @@ namespace gr {
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;
int32_t d_finetune;
uint8_t d_sf; uint8_t d_sf;
uint32_t d_bw; uint32_t d_bw;
uint8_t d_cr; uint8_t d_cr;
double d_bits_per_second; double d_bits_per_second;
uint32_t d_delay_after_sync;
uint32_t d_samples_per_second; uint32_t d_samples_per_second;
double d_symbols_per_second; double d_symbols_per_second;
uint32_t d_bits_per_symbol; uint32_t d_bits_per_symbol;
@ -75,6 +75,7 @@ namespace gr {
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;
int d_decim_factor; int d_decim_factor;
firdecim_crcf d_decim; firdecim_crcf d_decim;
float d_cfo_estimation; float d_cfo_estimation;
@ -106,6 +107,7 @@ namespace gr {
float stddev(const float *values, int len, float mean); float stddev(const float *values, int 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);
public: public:
@ -118,7 +120,7 @@ namespace gr {
gr_vector_void_star &output_items); gr_vector_void_star &output_items);
// GRC interfaces // GRC interfaces
virtual void set_finetune(int32_t finetune); virtual void set_sf(uint8_t sf);
}; };
} // namespace lora } // namespace lora

Wyświetl plik

@ -4,7 +4,7 @@
namespace gr { namespace gr {
namespace lora { namespace lora {
const uint8_t prng_header[] = { const uint8_t prng_header[] = {
0x22, 0x11, 0x0, 0x0, 0x0 0x22, 0x11, 0x00, 0x00, 0x00
}; };
const uint8_t prng_payload[] = { const uint8_t prng_payload[] = {

Wyświetl plik

@ -47,7 +47,19 @@ namespace gr {
return (((count+1) % 2) == 0); return (((count+1) % 2) == 0);
} }
void fec_extract_data_only(uint8_t* in_data, uint32_t len, uint8_t* indices, uint8_t n, uint8_t* out_data) {
for(uint32_t i = 0; i < len; i++) {
uint8_t d = 0;
for(uint32_t j = 0; j < n; j++) {
uint8_t power = pow(2, indices[j]);
if((in_data[i] & power) > 0) {
d += power;
}
}
out_data[i] = d;
}
}
} }
} }

Wyświetl plik

@ -30,15 +30,15 @@ class lora_receiver(gr.hier_block2):
""" """
docstring for block lora_receiver docstring for block lora_receiver
""" """
def __init__(self, in_samp_rate, freq, offset, finetune, realtime): def __init__(self, in_samp_rate, freq, offset, sf, realtime):
gr.hier_block2.__init__(self, gr.hier_block2.__init__(self,
"lora_receiver", # Min, Max, gr.sizeof_<type> "lora_receiver", # Min, Max, gr.sizeof_<type>
gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
gr.io_signature(0, 0, 0)) # Output signature gr.io_signature(0, 0, 0)) # Output signature
# Parameters # Parameters
self.finetune = finetune
self.offset = offset self.offset = offset
self.sf = sf
self.in_samp_rate = in_samp_rate self.in_samp_rate = in_samp_rate
self.realtime = realtime self.realtime = realtime
bw = 125000 bw = 125000
@ -47,7 +47,7 @@ class lora_receiver(gr.hier_block2):
null1 = null_sink(gr.sizeof_float) null1 = null_sink(gr.sizeof_float)
null2 = null_sink(gr.sizeof_float) null2 = null_sink(gr.sizeof_float)
if realtime: if realtime:
self.c_decoder = lora.decoder(finetune) self.c_decoder = lora.decoder(sf)
out_samp_rate = 1000000 out_samp_rate = 1000000
else: else:
decoder = lora_decoder() decoder = lora_decoder()
@ -73,13 +73,13 @@ class lora_receiver(gr.hier_block2):
self.connect((decoder, 0), (null1, 0)) self.connect((decoder, 0), (null1, 0))
self.connect((decoder, 1), (null2, 0)) self.connect((decoder, 1), (null2, 0))
def get_finetune(self): def set_sf(self):
return self.finetune return self.sf
def set_finetune(self, finetune): def set_sf(self, sf):
self.finetune = finetune self.sf = sf
if self.realtime: if self.realtime:
self.c_decoder.set_finetune(self.finetune) self.c_decoder.set_sf(self.sf)
def get_offset(self): def get_offset(self):
return self.offset return self.offset