kopia lustrzana https://github.com/rpp0/gr-lora
Merge branch 'dev' of https://github.com/Wosser1sProductions/gr-lora into Wosser1sProductions-dev
commit
2043e8e0bd
|
@ -13,7 +13,7 @@ import lora
|
|||
LoRaReceiver = collections.namedtuple('LoRaReceiver', ['name', 'available'])
|
||||
|
||||
class LoRaReceiveAll:
|
||||
def __init__(self, receiver, spreadingFactor = 7, samp_rate = 1e6, capture_freq = 868.0e6, target_freq = 868.1e6, threshold = 0.01):
|
||||
def __init__(self, receiver, spreadingFactor = 7, samp_rate = 1e6, capture_freq = 868.0e6, target_freq = 868.1e6, center_offset = 0, threshold = 0.01):
|
||||
##################################################
|
||||
# Variables #
|
||||
##################################################
|
||||
|
@ -30,17 +30,23 @@ class LoRaReceiveAll:
|
|||
# self.codingRate = codingRate # 4/5 4/6 4/7
|
||||
self.threshold = threshold
|
||||
|
||||
# For FFT, determine Center Frequency Offset first, then set here.
|
||||
# For RN2483, usually -14.1e3
|
||||
self.center_offset = center_offset
|
||||
|
||||
##################################################
|
||||
# Blocks #
|
||||
##################################################
|
||||
self.tb = gr.top_block ()
|
||||
|
||||
self.source = receiver
|
||||
self.lora_lora_receiver_0 = lora.lora_receiver(self.samp_rate, self.capture_freq, self.offset, self.sf, self.samp_rate, self.threshold)
|
||||
self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, self.samp_rate, True)
|
||||
self.source = receiver
|
||||
self.lora_lora_receiver_0 = lora.lora_receiver(self.samp_rate, self.capture_freq, self.offset, self.sf, self.samp_rate, self.threshold)
|
||||
self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, self.samp_rate, True)
|
||||
self.freq_xlating_fir_filter_0 = filter.freq_xlating_fir_filter_ccc(1, (firdes.low_pass(1, self.samp_rate, 200000, 50000)), self.center_offset, self.samp_rate)
|
||||
|
||||
self.tb.connect( (self.source, 0), (self.blocks_throttle_0, 0))
|
||||
self.tb.connect( (self.blocks_throttle_0, 0), (self.lora_lora_receiver_0, 0))
|
||||
self.tb.connect( (self.source, 0), (self.blocks_throttle_0, 0))
|
||||
self.tb.connect( (self.blocks_throttle_0, 0), (self.freq_xlating_fir_filter_0, 0))
|
||||
self.tb.connect( (self.freq_xlating_fir_filter_0, 0), (self.lora_lora_receiver_0, 0))
|
||||
|
||||
def start(self):
|
||||
# self.tb.Start(True)
|
||||
|
@ -60,9 +66,10 @@ if __name__ == '__main__':
|
|||
if sf in range(6, 13):
|
||||
break
|
||||
|
||||
target_freq = 868.1e6
|
||||
samp_rate = 1e6
|
||||
capture_freq = 868.0e6
|
||||
target_freq = 868.1e6
|
||||
samp_rate = 1e6
|
||||
capture_freq = 868.0e6
|
||||
center_offset = 0
|
||||
|
||||
print("Available sources:")
|
||||
for i, r in enumerate(receivers):
|
||||
|
@ -121,5 +128,5 @@ if __name__ == '__main__':
|
|||
print("Warning: No receiver set!")
|
||||
exit()
|
||||
|
||||
sdr = LoRaReceiveAll(receiver, sf, samp_rate, capture_freq, target_freq)
|
||||
sdr = LoRaReceiveAll(receiver, sf, samp_rate, capture_freq, target_freq, center_offset)
|
||||
sdr.start()
|
||||
|
|
|
@ -166,8 +166,10 @@ class ExamplifyLive:
|
|||
if __name__ == '__main__':
|
||||
random.seed(None)
|
||||
|
||||
gains = [32, 38, 38] # [10, 20, 20], for usrp: [32, 38, 38]
|
||||
|
||||
# Default: [10, 20, 20]
|
||||
# For an usrp it might me necessary to increase the gain and lower the detection threshold.
|
||||
# e.g. [32, 38, 38] and t = 0.001, but be careful.
|
||||
gains = [10, 20, 20]
|
||||
|
||||
############################################################################
|
||||
# SF / CR test with TimesPerSetting packets of len(2,16) on each setting
|
||||
|
|
|
@ -43,110 +43,3 @@ for name in files:
|
|||
|
||||
print("File: {0:s}\n\tLength: {1:d}\n\tAverage: {2:2.10f} ms\n\tStd: {3:2.10f}"
|
||||
.format(name, len(data), avg, std))
|
||||
|
||||
|
||||
#################
|
||||
#### Results ####
|
||||
#################
|
||||
# File: lora-time_SF7_grad_idx_DECODE_HEADER
|
||||
# Length: 9856
|
||||
# Average: 0.1259104846 ms
|
||||
# Std: 0.0083598489
|
||||
# File: lora-time_SF7_grad_idx_DECODE_PAYLOAD
|
||||
# Length: 14854
|
||||
# Average: 0.1240467029 ms
|
||||
# Std: 0.0058878571
|
||||
# File: lora-time_SF7_grad_idx_DETECT
|
||||
# Length: 132937
|
||||
# Average: 0.0111668757 ms
|
||||
# Std: 0.0863605383
|
||||
# File: lora-time_SF7_grad_idx_PAUSE
|
||||
# Length: 1232
|
||||
# Average: 0.0010141461 ms
|
||||
# Std: 0.0011882927
|
||||
# File: lora-time_SF7_grad_idx_SYNC
|
||||
# Length: 12334
|
||||
# Average: 0.1369446399 ms
|
||||
# Std: 0.0072021918
|
||||
# File: lora-time_SF7_grad_idx_only
|
||||
# Length: 11118
|
||||
# Average: 0.1189276336 ms
|
||||
# Std: 0.0055137726
|
||||
|
||||
|
||||
# File: lora-time_SF12_grad_idx_DECODE_HEADER
|
||||
# Length: 9912
|
||||
# Average: 3.7912548676 ms
|
||||
# Std: 0.2630857073
|
||||
# File: lora-time_SF12_grad_idx_DECODE_PAYLOAD
|
||||
# Length: 12320
|
||||
# Average: 3.8091647075 ms
|
||||
# Std: 0.2747977905
|
||||
# File: lora-time_SF12_grad_idx_DETECT
|
||||
# Length: 3723
|
||||
# Average: 16.7026039911 ms
|
||||
# Std: 21.1052133394
|
||||
# File: lora-time_SF12_grad_idx_PAUSE
|
||||
# Length: 1239
|
||||
# Average: 0.0012905004 ms
|
||||
# Std: 0.0002020981
|
||||
# File: lora-time_SF12_grad_idx_SYNC
|
||||
# Length: 10725
|
||||
# Average: 4.2126484056 ms
|
||||
# Std: 0.2068078822
|
||||
# File: lora-time_SF12_grad_idx_only
|
||||
# Length: 10002
|
||||
# Average: 3.7576346853 ms
|
||||
# Std: 0.2498984209
|
||||
|
||||
|
||||
# File: lora-time_SF7_fft_idx_DECODE_HEADER
|
||||
# Length: 9856
|
||||
# Average: 0.0783100350 ms
|
||||
# Std: 0.0131321480
|
||||
# File: lora-time_SF7_fft_idx_DECODE_PAYLOAD
|
||||
# Length: 20440
|
||||
# Average: 0.0760118956 ms
|
||||
# Std: 0.0125111634
|
||||
# File: lora-time_SF7_fft_idx_DETECT
|
||||
# Length: 130172
|
||||
# Average: 0.0112985811 ms
|
||||
# Std: 0.0876915475
|
||||
# File: lora-time_SF7_fft_idx_PAUSE
|
||||
# Length: 1232
|
||||
# Average: 0.0010230820 ms
|
||||
# Std: 0.0011295359
|
||||
# File: lora-time_SF7_fft_idx_SYNC
|
||||
# Length: 12320
|
||||
# Average: 0.1378892978 ms
|
||||
# Std: 0.0080917100
|
||||
# File: lora-time_SF7_fft_idx_only
|
||||
# Length: 13512
|
||||
# Average: 0.0706166163 ms
|
||||
# Std: 0.0098948093
|
||||
|
||||
|
||||
# File: lora-time_SF12_fft_idx_DECODE_HEADER
|
||||
# Length: 9912
|
||||
# Average: 2.2331703327 ms
|
||||
# Std: 0.2301535307
|
||||
# File: lora-time_SF12_fft_idx_DECODE_PAYLOAD
|
||||
# Length: 12390
|
||||
# Average: 2.2217885565 ms
|
||||
# Std: 0.2009724076
|
||||
# File: lora-time_SF12_fft_idx_DETECT
|
||||
# Length: 3744
|
||||
# Average: 16.3153207676 ms
|
||||
# Std: 20.9261960413
|
||||
# File: lora-time_SF12_fft_idx_PAUSE
|
||||
# Length: 1239
|
||||
# Average: 0.0012535383 ms
|
||||
# Std: 0.0001955853
|
||||
# File: lora-time_SF12_fft_idx_SYNC
|
||||
# Length: 10613
|
||||
# Average: 4.2222761290 ms
|
||||
# Std: 0.2295213521
|
||||
# File: lora-time_SF12_fft_idx_only
|
||||
# Length: 10032
|
||||
# Average: 2.2098768243 ms
|
||||
# Std: 0.2333799337
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2017 Pieter Robyns, William Thenaers.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef DBUGR_HPP
|
||||
#define DBUGR_HPP
|
||||
|
||||
|
@ -7,7 +27,7 @@
|
|||
|
||||
#include "utilities.h"
|
||||
|
||||
#define CLAMP_VAL 0.7f //1000000.0f //0.7f
|
||||
#define CLAMP_VAL 0.7e6f //1000000.0f //0.7f
|
||||
|
||||
#undef NDEBUG /// Debug printing
|
||||
//#define NDEBUG /// No debug printing
|
||||
|
@ -45,26 +65,19 @@
|
|||
std::ofstream DBGR_out_file; \
|
||||
DBGR_out_file.open("/tmp/DBGR.txt", std::ios::out); \
|
||||
\
|
||||
\
|
||||
/*printf("DBGR_Ideal\n");*/ \
|
||||
for (DBGR_j = 0; DBGR_j < int32_t(WINDOW); DBGR_j++) { \
|
||||
sprintf(DBGR_buf, "%f\n", IDEAL_SIG_FP[DBGR_j]); \
|
||||
DBGR_out_file.write(DBGR_buf, strlen(DBGR_buf)); \
|
||||
} DBGR_out_file.write(DBGR_delim, strlen(DBGR_delim)); \
|
||||
\
|
||||
/*printf("%s", DBGR_delim);*/ \
|
||||
\
|
||||
/*printf("DBGR_Before\n");*/ \
|
||||
for (DBGR_j = 0; DBGR_j < int32_t(WINDOW); DBGR_j++) { \
|
||||
sprintf(DBGR_buf, "%f\n", gr::lora::clamp(SAMPLE_SIG_FP[DBGR_j], -CLAMP_VAL, CLAMP_VAL)); \
|
||||
sprintf(DBGR_buf, "%f\n", gr::lora::clamp(SAMPLE_SIG_FP[DBGR_j], -CLAMP_VAL, CLAMP_VAL)); \
|
||||
DBGR_out_file.write(DBGR_buf, strlen(DBGR_buf)); \
|
||||
} DBGR_out_file.write(DBGR_delim, strlen(DBGR_delim)); \
|
||||
\
|
||||
/*printf("%s", DBGR_delim);*/ \
|
||||
\
|
||||
printf("DBGR_After %d of %d in %d\n", MIN, MAX, WINDOW); \
|
||||
for (DBGR_j = OFFSET; DBGR_j < int32_t(OFFSET > 0 ? WINDOW : MAX); DBGR_j++) { \
|
||||
sprintf(DBGR_buf, "%f\n", gr::lora::clamp(*(SAMPLE_SIG_FP + DBGR_j), -CLAMP_VAL, CLAMP_VAL)); \
|
||||
sprintf(DBGR_buf, "%f\n", gr::lora::clamp(*(SAMPLE_SIG_FP + DBGR_j), -CLAMP_VAL, CLAMP_VAL)); \
|
||||
DBGR_out_file.write(DBGR_buf, strlen(DBGR_buf)); \
|
||||
} DBGR_out_file.write(DBGR_delim, strlen(DBGR_delim)); \
|
||||
\
|
||||
|
@ -79,7 +92,6 @@
|
|||
printf("%s", DBGR_delim); \
|
||||
}*/ \
|
||||
\
|
||||
/*printf("DBGR_End\n");*/ \
|
||||
DBGR_out_file.close(); \
|
||||
if(PAUSE) DBGR_PAUSE(MSG); \
|
||||
} while(0)
|
||||
|
@ -119,39 +131,39 @@
|
|||
} while(0) \
|
||||
|
||||
|
||||
#define DBGR_START_TIME_MEASUREMENT(OUT, MSG) \
|
||||
DBGR_intermediate_time = OUT; \
|
||||
if (DBGR_intermediate_time) printf("[CHRONO] : Start in % 15s", std::string(MSG).c_str()); \
|
||||
if (DBGR_time_to_file) { \
|
||||
DBGR_filename = "/tmp/" + DBGR_fileprefix + "_" + std::string(MSG); \
|
||||
} \
|
||||
DBGR_totalled_time = false; \
|
||||
#define DBGR_START_TIME_MEASUREMENT(OUT, MSG) \
|
||||
DBGR_intermediate_time = OUT; \
|
||||
if (DBGR_intermediate_time) printf("[CHRONO] : Start in % 15s", std::string(MSG).c_str()); \
|
||||
if (DBGR_time_to_file) { \
|
||||
DBGR_filename = "/tmp/" + DBGR_fileprefix + "_" + std::string(MSG); \
|
||||
} \
|
||||
DBGR_totalled_time = false; \
|
||||
auto DBGR_start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
#define DBGR_START_TIME_MEASUREMENT_SAME_SCOPE(OUT, MSG) \
|
||||
DBGR_intermediate_time = OUT; \
|
||||
if (DBGR_intermediate_time) printf("[CHRONO] : Start with % 15s", MSG); \
|
||||
DBGR_totalled_time = false; \
|
||||
#define DBGR_START_TIME_MEASUREMENT_SAME_SCOPE(OUT, MSG) \
|
||||
DBGR_intermediate_time = OUT; \
|
||||
if (DBGR_intermediate_time) printf("[CHRONO] : Start with % 15s", MSG); \
|
||||
DBGR_totalled_time = false; \
|
||||
DBGR_start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
#define DBGR_INTERMEDIATE_TIME_MEASUREMENT() \
|
||||
if (!DBGR_totalled_time) { \
|
||||
#define DBGR_INTERMEDIATE_TIME_MEASUREMENT() \
|
||||
if (!DBGR_totalled_time) { \
|
||||
int64_t DBGR_duration = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - DBGR_start_time).count(); \
|
||||
DBGR_global_time += DBGR_duration; \
|
||||
const float DBGR_ms_duration[] = { DBGR_duration / 1e6f }; \
|
||||
if (DBGR_intermediate_time) printf(" and took %fms\n", DBGR_ms_duration[0]); \
|
||||
if (DBGR_time_to_file) { \
|
||||
DBGR_QUICK_TO_FILE(DBGR_filename, true, DBGR_ms_duration, 1, "%f"); \
|
||||
} \
|
||||
DBGR_global_time += DBGR_duration; \
|
||||
const float DBGR_ms_duration[] = { DBGR_duration / 1e6f }; \
|
||||
if (DBGR_intermediate_time) printf(" and took %fms\n", DBGR_ms_duration[0]); \
|
||||
if (DBGR_time_to_file) { \
|
||||
DBGR_QUICK_TO_FILE(DBGR_filename, true, DBGR_ms_duration, 1, "%f"); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DBGR_STOP_TIME_MEASUREMENT(OUT) \
|
||||
if (OUT) printf("[CHRONO] : Packet took %fms to process.\n", DBGR_global_time / 1e6); \
|
||||
DBGR_global_time = 0ll; \
|
||||
#define DBGR_STOP_TIME_MEASUREMENT(OUT) \
|
||||
if (OUT) printf("[CHRONO] : Packet took %fms to process.\n", DBGR_global_time / 1e6); \
|
||||
DBGR_global_time = 0ll; \
|
||||
DBGR_totalled_time = true;
|
||||
|
||||
#define DBGR_TIME_MEASUREMENT_TO_FILE(PRE) \
|
||||
DBGR_time_to_file = true; \
|
||||
#define DBGR_TIME_MEASUREMENT_TO_FILE(PRE) \
|
||||
DBGR_time_to_file = true; \
|
||||
if (DBGR_fileprefix.length() == 0) DBGR_fileprefix = "lora-time_" + std::string(PRE);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include "utilities.h"
|
||||
|
||||
//#define NO_TMP_WRITES 1 /// Debug output file write
|
||||
#define CFO_CORRECT 1 /// Correct shift fft estimation
|
||||
//#define CFO_CORRECT 1 /// Correct shift fft estimation
|
||||
|
||||
//#undef NDEBUG /// Debug printing
|
||||
//#define NDEBUG /// No debug printing
|
||||
|
@ -116,18 +116,24 @@ namespace gr {
|
|||
this->build_ideal_chirps();
|
||||
|
||||
this->set_output_multiple(2 * this->d_samples_per_symbol);
|
||||
this->d_fft.resize(this->d_number_of_bins);
|
||||
this->d_mult.resize(this->d_number_of_bins);
|
||||
this->d_q = fft_create_plan(this->d_number_of_bins, &this->d_mult[0], &this->d_fft[0], LIQUID_FFT_FORWARD, 0);
|
||||
this->d_fft.resize(this->d_samples_per_symbol);
|
||||
this->d_mult_hf.resize(this->d_samples_per_symbol);
|
||||
this->d_tmp.resize(this->d_number_of_bins);
|
||||
this->d_q = fft_create_plan(this->d_samples_per_symbol, &this->d_mult_hf[0], &this->d_fft[0], LIQUID_FFT_FORWARD, 0);
|
||||
this->d_qr = fft_create_plan(this->d_number_of_bins, &this->d_tmp[0], &this->d_mult_hf[0], LIQUID_FFT_BACKWARD, 0);
|
||||
|
||||
|
||||
// Decimation filter
|
||||
float g[DECIMATOR_FILTER_SIZE];
|
||||
liquid_firdes_rrcos(8, 1, 0.5f, 0.3f, g); // Filter for interpolating
|
||||
const int delay = 2;
|
||||
const int decim_filter_size = (2 * this->d_decim_factor * delay + 1);
|
||||
float g[decim_filter_size];
|
||||
float d_decim_h[decim_filter_size]; ///< The reversed decimation filter for LiquidDSP.
|
||||
liquid_firdes_rrcos(this->d_decim_factor, delay, 0.5f, 0.3f, g); // Filter for interpolating
|
||||
|
||||
for (uint32_t i = 0u; i < DECIMATOR_FILTER_SIZE; i++) // Reverse it to get decimation filter
|
||||
this->d_decim_h[i] = g[DECIMATOR_FILTER_SIZE - i - 1];
|
||||
for (uint32_t i = 0u; i < decim_filter_size; i++) // Reverse it to get decimation filter
|
||||
d_decim_h[i] = g[decim_filter_size - i - 1u];
|
||||
|
||||
this->d_decim = firdecim_crcf_create(this->d_decim_factor, this->d_decim_h, DECIMATOR_FILTER_SIZE);
|
||||
this->d_decim = firdecim_crcf_create(this->d_decim_factor, d_decim_h, decim_filter_size);
|
||||
|
||||
// Register gnuradio ports
|
||||
this->message_port_register_out(pmt::mp("frames"));
|
||||
|
@ -151,6 +157,7 @@ namespace gr {
|
|||
#endif
|
||||
|
||||
fft_destroy_plan(this->d_q);
|
||||
fft_destroy_plan(this->d_qr);
|
||||
firdecim_crcf_destroy(this->d_decim);
|
||||
}
|
||||
|
||||
|
@ -182,6 +189,19 @@ namespace gr {
|
|||
samples_to_file("/tmp/upchirp", &this->d_upchirp[0], this->d_upchirp.size(), sizeof(gr_complex));
|
||||
}
|
||||
|
||||
void decoder_impl::values_to_file(const std::string path, const unsigned char *v, const uint32_t length, const uint32_t ppm) {
|
||||
std::ofstream out_file;
|
||||
out_file.open(path.c_str(), std::ios::out | std::ios::app);
|
||||
|
||||
for (uint32_t i = 0u; i < length; i++) {
|
||||
std::string tmp = gr::lora::to_bin(v[i], ppm);
|
||||
out_file.write(tmp.c_str(), tmp.length());
|
||||
}
|
||||
out_file.write("\n", 1);
|
||||
|
||||
out_file.close();
|
||||
}
|
||||
|
||||
void decoder_impl::samples_to_file(const std::string path, const gr_complex *v, const uint32_t length, const uint32_t elem_size) {
|
||||
#ifndef NO_TMP_WRITES
|
||||
std::ofstream out_file;
|
||||
|
@ -292,28 +312,28 @@ namespace gr {
|
|||
* Calculate normalized cross correlation of real values.
|
||||
* See https://en.wikipedia.org/wiki/Cross-correlation#Normalized_cross-correlation.
|
||||
*/
|
||||
float decoder_impl::cross_correlate_ifreq(const float *samples_ifreq, const std::vector<float>& ideal_chirp, const uint32_t from_idx, const uint32_t to_idx) {
|
||||
float decoder_impl::cross_correlate_ifreq(const float *samples_ifreq, const std::vector<float>& ideal_chirp, const uint32_t to_idx) {
|
||||
float result = 0.0f;
|
||||
|
||||
const float average = std::accumulate(samples_ifreq + from_idx, samples_ifreq + to_idx, 0.0f) / (float)(to_idx - from_idx);
|
||||
const float chirp_avg = std::accumulate(&ideal_chirp[from_idx] , &ideal_chirp[to_idx] , 0.0f) / (float)(to_idx - from_idx);
|
||||
const float sd = this->stddev(samples_ifreq + from_idx , (to_idx - from_idx) , average)
|
||||
* this->stddev(&ideal_chirp[from_idx] , (to_idx - from_idx) , chirp_avg);
|
||||
const float average = std::accumulate(samples_ifreq , samples_ifreq + to_idx, 0.0f) / (float)(to_idx);
|
||||
const float chirp_avg = std::accumulate(&ideal_chirp[0], &ideal_chirp[to_idx] , 0.0f) / (float)(to_idx);
|
||||
const float sd = this->stddev(samples_ifreq , to_idx, average)
|
||||
* this->stddev(&ideal_chirp[0] , to_idx, chirp_avg);
|
||||
|
||||
for (uint32_t i = from_idx; i < to_idx; i++) {
|
||||
for (uint32_t i = 0u; i < to_idx; i++) {
|
||||
result += (samples_ifreq[i] - average) * (ideal_chirp[i] - chirp_avg) / sd;
|
||||
}
|
||||
|
||||
result /= (float)(to_idx - from_idx - 1u);
|
||||
result /= (float)(to_idx - 1u);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float decoder_impl::detect_downchirp(const gr_complex *samples, const uint32_t window) {
|
||||
float samples_ifreq[window];
|
||||
|
||||
this->instantaneous_frequency(samples, samples_ifreq, window);
|
||||
return this->cross_correlate_ifreq(samples_ifreq, this->d_downchirp_ifreq, 0u, window - 1u);
|
||||
|
||||
return this->cross_correlate_ifreq(samples_ifreq, this->d_downchirp_ifreq, window - 1u);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -340,6 +360,7 @@ namespace gr {
|
|||
}
|
||||
|
||||
if (!found_change) {
|
||||
//printf("No falling edge?\n");
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
@ -350,14 +371,18 @@ namespace gr {
|
|||
samples_ifreq + gr::lora::clamp(local_max_idx + 3u * coeff, 0u, window)) - samples_ifreq;
|
||||
|
||||
// Cross correlate between start and end of falling edge instead of entire window
|
||||
for (uint32_t i = local_max_idx; i < local_min_idx; i++) {
|
||||
const float max_corr = this->cross_correlate_ifreq(samples_ifreq + i, this->d_upchirp_ifreq, 0u, /*std::min(len, window - i - 1u)*/ len);
|
||||
for (uint32_t i = local_max_idx; i < local_min_idx && (i + len) < window; i++) {
|
||||
const float max_corr = this->cross_correlate_ifreq(samples_ifreq + i, this->d_upchirp_ifreq, len);
|
||||
|
||||
if (max_corr > max_correlation) {
|
||||
*index = i;
|
||||
max_correlation = max_corr;
|
||||
}
|
||||
}
|
||||
|
||||
// Signal from local_max_idx vs shifted with *index
|
||||
//DBGR_WRITE_SIGNAL(this->d_upchirp_ifreq, (samples_ifreq + local_max_idx), len, (*index - local_max_idx), 0u, window, false, true, Printed graphs in sliding_norm_cross_correlate_upchirp);
|
||||
|
||||
return max_correlation;
|
||||
}
|
||||
|
||||
|
@ -402,14 +427,14 @@ namespace gr {
|
|||
}
|
||||
|
||||
/**
|
||||
* Currently unused.
|
||||
* Currently unstable due to center frequency offset.
|
||||
*/
|
||||
uint32_t decoder_impl::get_shift_fft(const gr_complex *samples) {
|
||||
float fft_mag[this->d_number_of_bins];
|
||||
gr_complex mult_hf[this->d_samples_per_symbol];
|
||||
|
||||
gr_complex sample[this->d_samples_per_symbol];
|
||||
memcpy(sample, samples, this->d_samples_per_symbol);
|
||||
|
||||
memcpy(sample, samples, this->d_samples_per_symbol * sizeof(gr_complex));
|
||||
|
||||
#ifdef CFO_CORRECT
|
||||
this->determine_cfo(&samples[0]);
|
||||
#ifndef NDEBUG
|
||||
|
@ -423,50 +448,102 @@ namespace gr {
|
|||
|
||||
// Multiply with ideal downchirp
|
||||
for (uint32_t i = 0u; i < this->d_samples_per_symbol; i++) {
|
||||
mult_hf[i] = std::conj(sample[i] * this->d_downchirp[i]);
|
||||
this->d_mult_hf[i] = std::conj(sample[i] * this->d_downchirp[i]);
|
||||
}
|
||||
|
||||
samples_to_file("/tmp/mult", &mult_hf[0], this->d_samples_per_symbol, sizeof(gr_complex));
|
||||
samples_to_file("/tmp/mult", &this->d_mult_hf[0], this->d_samples_per_symbol, sizeof(gr_complex));
|
||||
|
||||
// Perform decimation
|
||||
for (uint32_t i = 0u; i < this->d_number_of_bins; i++) {
|
||||
firdecim_crcf_execute(this->d_decim, &mult_hf[this->d_decim_factor * i], &this->d_mult[i]);
|
||||
}
|
||||
//for (uint32_t i = 0u; i < this->d_number_of_bins; i++) {
|
||||
// firdecim_crcf_execute(this->d_decim, &mult_hf[this->d_decim_factor * i], &this->d_mult[i]);
|
||||
//}
|
||||
|
||||
samples_to_file("/tmp/resampled", &this->d_mult[0], this->d_number_of_bins, sizeof(gr_complex));
|
||||
//samples_to_file("/tmp/resampled", &this->d_mult[0], this->d_number_of_bins, sizeof(gr_complex));
|
||||
|
||||
// Perform FFT
|
||||
fft_execute(this->d_q);
|
||||
|
||||
// Decimate. Note: assumes fft size is multiple of decimation factor and number of bins is even
|
||||
const uint32_t N = this->d_number_of_bins;
|
||||
memcpy(&this->d_tmp[0], &this->d_fft[0], (N + 1u) / 2u * sizeof(gr_complex));
|
||||
memcpy(&this->d_tmp[ (N + 1u) / 2u ], &this->d_fft[this->d_samples_per_symbol - (N / 2u)], N / 2u * sizeof(gr_complex));
|
||||
this->d_tmp[N / 2u] += this->d_fft[N / 2u];
|
||||
// Note that you have to kill the grc before checking the plots!
|
||||
|
||||
// Get magnitude
|
||||
for (uint32_t i = 0u; i < this->d_number_of_bins; i++) {
|
||||
fft_mag[i] = std::abs(this->d_fft[i]);
|
||||
fft_mag[i] = std::abs(this->d_tmp[i]);
|
||||
}
|
||||
|
||||
samples_to_file("/tmp/fft", &this->d_fft[0], this->d_number_of_bins, sizeof(gr_complex));
|
||||
samples_to_file("/tmp/fft", &this->d_tmp[0], this->d_number_of_bins, sizeof(gr_complex));
|
||||
|
||||
fft_execute(this->d_qr); // debug
|
||||
samples_to_file("/tmp/resampled", &this->d_mult_hf[0], this->d_number_of_bins, sizeof(gr_complex));
|
||||
|
||||
// Return argmax here
|
||||
return (std::max_element(fft_mag, fft_mag + this->d_number_of_bins) - fft_mag);
|
||||
}
|
||||
|
||||
uint32_t decoder_impl::max_frequency_gradient_idx(const gr_complex *samples) {
|
||||
uint32_t decoder_impl::max_frequency_gradient_idx(const gr_complex *samples, const bool is_header) {
|
||||
float samples_ifreq[this->d_samples_per_symbol];
|
||||
|
||||
samples_to_file("/tmp/data", &samples[0], this->d_samples_per_symbol, sizeof(gr_complex));
|
||||
|
||||
this->instantaneous_frequency(samples, samples_ifreq, this->d_samples_per_symbol);
|
||||
|
||||
for (uint32_t i = 0u; i < this->d_number_of_bins - 1u; i++) {
|
||||
/*** Visualize bins in plot ******************************************/
|
||||
//#define PLOT_BINS // Uncomment for use
|
||||
|
||||
#ifdef PLOT_BINS
|
||||
uint32_t gradbins = this->d_number_of_bins;
|
||||
uint32_t graddecim = this->d_decim_factor;
|
||||
if (is_header) {
|
||||
gradbins /= 4u;
|
||||
graddecim *= 4u;
|
||||
}
|
||||
|
||||
printf("Bins: %d, len: %d\n", gradbins, graddecim);
|
||||
float samples_bins[this->d_samples_per_symbol];
|
||||
for (uint32_t i = 0u; i < this->d_samples_per_symbol; i++) {
|
||||
samples_bins[i] = i % (graddecim * 2u) == 0u ? 0.5f : i % graddecim == 0u ? -0.5f : 0.0f;
|
||||
}
|
||||
|
||||
DBGR_WRITE_SIGNAL(samples_bins, samples_ifreq, this->d_samples_per_symbol, 0, 0, this->d_samples_per_symbol, false, false, Printed bins in freq_grad_idx);
|
||||
|
||||
#endif
|
||||
/*********************************************************************/
|
||||
|
||||
for (uint32_t i = 1u; i < this->d_number_of_bins - 2u; i++) {
|
||||
if (samples_ifreq[this->d_decim_factor * i] - samples_ifreq[this->d_decim_factor * (i + 1u)] > 0.2f) {
|
||||
return i + 1u;
|
||||
#ifdef PLOT_BINS
|
||||
printf("[Freq_Grad] Down on idx: %4d in bin %4d (in [%4d, %4d])\n",
|
||||
this->d_decim_factor * i,
|
||||
is_header ? (i + !is_header) / 4u : (i + !is_header),
|
||||
graddecim * (is_header ? i / 4u : i),
|
||||
graddecim * ((is_header ? i / 4u : i) + 1u));
|
||||
DBGR_PAUSE();
|
||||
#endif
|
||||
return i + !is_header;
|
||||
}
|
||||
}
|
||||
|
||||
const float zero_bin = samples_ifreq[0u] - samples_ifreq[this->d_decim_factor];
|
||||
const float high_bin = samples_ifreq[(this->d_number_of_bins - 2u) * this->d_decim_factor] - samples_ifreq[(this->d_number_of_bins - 1u) * this->d_decim_factor];
|
||||
const float zero_bin = samples_ifreq[0u] - samples_ifreq[this->d_decim_factor * 2u];
|
||||
const float high_bin = samples_ifreq[(this->d_number_of_bins - 2u) * this->d_decim_factor] - samples_ifreq[this->d_number_of_bins * this->d_decim_factor - 1u];
|
||||
|
||||
return zero_bin > high_bin
|
||||
? 0u : this->d_number_of_bins;
|
||||
#ifdef PLOT_BINS
|
||||
if (zero_bin > 0.2f || zero_bin > high_bin)
|
||||
printf("[Freq_Grad] Down on idx: %4d in bin %4d (at %4d)\n", 0, 0, 1);
|
||||
else
|
||||
printf("[Freq_Grad] Down on idx: %4d in bin %4d (at %4d)\n",
|
||||
this->d_decim_factor * (this->d_number_of_bins - 1u),
|
||||
this->d_number_of_bins,
|
||||
this->d_decim_factor * this->d_number_of_bins);
|
||||
DBGR_PAUSE();
|
||||
#endif
|
||||
|
||||
// Prefer first bin over last. (First bin == 0 or 1?)
|
||||
return zero_bin > 0.2f || zero_bin > high_bin
|
||||
? 1u : this->d_number_of_bins;
|
||||
}
|
||||
|
||||
bool decoder_impl::demodulate(const gr_complex *samples, const bool is_header) {
|
||||
|
@ -474,7 +551,7 @@ namespace gr {
|
|||
|
||||
// DBGR_START_TIME_MEASUREMENT(false, "only");
|
||||
|
||||
uint32_t bin_idx = this->max_frequency_gradient_idx(samples);
|
||||
uint32_t bin_idx = this->max_frequency_gradient_idx(samples, is_header);
|
||||
//uint32_t bin_idx = this->get_shift_fft(samples);
|
||||
|
||||
// DBGR_INTERMEDIATE_TIME_MEASUREMENT();
|
||||
|
@ -509,7 +586,7 @@ namespace gr {
|
|||
*/
|
||||
void decoder_impl::deinterleave(const uint32_t ppm) {
|
||||
const uint32_t bits_per_word = this->d_words.size();
|
||||
const uint32_t offset_start = ppm - 1u;
|
||||
const uint32_t offset_start = ppm - 1u;
|
||||
|
||||
std::vector<uint8_t> words_deinterleaved(ppm, 0u);
|
||||
|
||||
|
@ -541,6 +618,10 @@ namespace gr {
|
|||
static const uint8_t shuffle_pattern[] = {7, 6, 3, 4, 2, 1, 0, 5};
|
||||
|
||||
this->deshuffle(shuffle_pattern, is_header);
|
||||
|
||||
if (!is_header)
|
||||
this->values_to_file("/tmp/after_deshuffle", &this->d_words_deshuffled[0], this->d_words_deshuffled.size(), 8);
|
||||
|
||||
this->dewhiten(is_header ? gr::lora::prng_header : this->d_whitening_sequence);
|
||||
this->hamming_decode(out_data);
|
||||
|
||||
|
@ -567,16 +648,13 @@ namespace gr {
|
|||
void decoder_impl::deshuffle(const uint8_t *shuffle_pattern, const bool is_header) {
|
||||
const uint32_t to_decode = is_header ? 5u : this->d_demodulated.size();
|
||||
const uint32_t len = sizeof(shuffle_pattern) / sizeof(uint8_t);
|
||||
uint8_t original, result;
|
||||
uint8_t result;
|
||||
|
||||
for (uint32_t i = 0u; i < to_decode; i++) {
|
||||
original = this->d_demodulated[i];
|
||||
result = 0u;
|
||||
result = 0u;
|
||||
|
||||
for (uint32_t j = 0u; j < len; j++) {
|
||||
if (original & (1u << shuffle_pattern[j])) {
|
||||
result |= 1u << j;
|
||||
}
|
||||
result |= !!(this->d_demodulated[i] & (1u << shuffle_pattern[j])) << j;
|
||||
}
|
||||
|
||||
this->d_words_deshuffled.push_back(result);
|
||||
|
@ -603,7 +681,6 @@ namespace gr {
|
|||
// if (prng != gr::lora::prng_header)
|
||||
// DBGR_QUICK_TO_FILE("/tmp/whitening_out", true, this->d_words_deshuffled, len, "0x%02X,");
|
||||
|
||||
|
||||
for (uint32_t i = 0u; i < len; i++) {
|
||||
uint8_t xor_b = this->d_words_deshuffled[i] ^ prng[i];
|
||||
|
||||
|
@ -800,7 +877,7 @@ namespace gr {
|
|||
this->d_debug << "Cd: " << c << std::endl;
|
||||
#endif
|
||||
|
||||
if (c > 0.98f) {
|
||||
if (c > 0.99f) {
|
||||
#ifndef NDEBUG
|
||||
this->d_debug << "SYNC: " << c << std::endl;
|
||||
#endif
|
||||
|
@ -889,6 +966,21 @@ namespace gr {
|
|||
|
||||
DBGR_STOP_TIME_MEASUREMENT(true);
|
||||
// DBGR_PAUSE();
|
||||
|
||||
//---- Whitening rejecter ----
|
||||
// bool all_zero = true;
|
||||
// for (uint32_t i = 0u; i < this->d_payload_length; i++) {
|
||||
// if (decoded[i]) {
|
||||
// all_zero = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Remove last line in whitening output file if decoded values were not all zero
|
||||
// if (!all_zero) {
|
||||
// system("sed -i '$ d' /tmp/whitening_out");
|
||||
// }
|
||||
//----------------------------
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,8 @@ namespace gr {
|
|||
std::vector<float> d_upchirp_ifreq; ///< The instantaneous frequency of the ideal upchirp.
|
||||
|
||||
std::vector<gr_complex> d_fft; ///< Vector containing the FFT resuls.
|
||||
std::vector<gr_complex> d_mult; ///< Vector containing the FFT decimation.
|
||||
std::vector<gr_complex> d_mult_hf; ///< Vector containing the FFT decimation.
|
||||
std::vector<gr_complex> d_tmp; ///< Vector containing the FFT decimation.
|
||||
|
||||
uint8_t d_sf; ///< The Spreading Factor.
|
||||
uint32_t d_bw; ///< The receiver bandwidth (fixed to `125kHz`).
|
||||
|
@ -102,8 +103,8 @@ namespace gr {
|
|||
std::ofstream d_debug; ///< Outputstream for the debug log.
|
||||
|
||||
fftplan d_q; ///< The LiquidDSP::FFT_Plan.
|
||||
fftplan d_qr; ///< The LiquidDSP::FFT_Plan in reverse.
|
||||
|
||||
float d_decim_h[DECIMATOR_FILTER_SIZE]; ///< The reversed decimation filter for LiquidDSP.
|
||||
uint32_t d_corr_decim_factor; ///< The decimation factor used in finding the preamble start.
|
||||
uint32_t d_decim_factor; ///< The amount of samples (data points) in each bin.
|
||||
firdecim_crcf d_decim = nullptr; ///< The LiquidDSP FIR decimation filter used to decimate the FFT imput.
|
||||
|
@ -141,6 +142,20 @@ namespace gr {
|
|||
*/
|
||||
void samples_to_file(const std::string path, const gr_complex *v, const uint32_t length, const uint32_t elem_size);
|
||||
|
||||
/**
|
||||
* \brief Debug method to dump the given values array to a file in textual format.
|
||||
*
|
||||
* \param path
|
||||
* The path to the file to dump to.
|
||||
* \param v
|
||||
* The values array to dump.
|
||||
* \param length
|
||||
* Length of said array.
|
||||
* \param ppm
|
||||
* PPM value of the data.
|
||||
*/
|
||||
void values_to_file(const std::string path, const unsigned char *v, const uint32_t length, const uint32_t ppm);
|
||||
|
||||
/**
|
||||
* \brief Write the given complex array to the debug outputstream.
|
||||
*
|
||||
|
@ -207,12 +222,10 @@ namespace gr {
|
|||
* The instantaneous frequency of the symbol to correlate with.
|
||||
* \param ideal_chirp
|
||||
* The vector containing the ideal chirp to correlate with.
|
||||
* \param from_idx
|
||||
* Correlation start index.
|
||||
* \param to_idx
|
||||
* Correlation end index.
|
||||
*/
|
||||
float cross_correlate_ifreq(const float *samples_ifreq, const std::vector<float>& ideal_chirp, const uint32_t from_idx, const uint32_t to_idx);
|
||||
float cross_correlate_ifreq(const float *samples_ifreq, const std::vector<float>& ideal_chirp, const uint32_t to_idx);
|
||||
|
||||
/**
|
||||
* \brief Returns the index to shift the given symbol so that it overlaps the ideal upchirp.
|
||||
|
@ -271,8 +284,10 @@ namespace gr {
|
|||
*
|
||||
* \param samples
|
||||
* The complex symbol to analyse.
|
||||
* \param is_header
|
||||
* Whether the given symbol is part of a HDR.
|
||||
*/
|
||||
uint32_t max_frequency_gradient_idx(const gr_complex *samples);
|
||||
uint32_t max_frequency_gradient_idx(const gr_complex *samples, const bool is_header = false);
|
||||
|
||||
/**
|
||||
* \brief Demodulate the given symbol and return true if all expected symbols have been parsed.
|
||||
|
@ -399,7 +414,7 @@ namespace gr {
|
|||
* \param num_samples
|
||||
* Size of said complex array.
|
||||
*/
|
||||
void msg_raw_chirp_debug(const gr_complex *raw_samples, const uint32_t num_samples);
|
||||
void msg_raw_chirp_debug(const gr_complex *raw_samples, const uint32_t num_samples);
|
||||
|
||||
/**
|
||||
* \brief Unimplemented
|
||||
|
@ -407,7 +422,7 @@ namespace gr {
|
|||
* \param frame_bytes
|
||||
* \param frame_len
|
||||
*/
|
||||
void msg_lora_frame(const uint8_t *frame_bytes, const uint32_t frame_len);
|
||||
void msg_lora_frame(const uint8_t *frame_bytes, const uint32_t frame_len);
|
||||
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -166,6 +166,7 @@ namespace gr {
|
|||
|
||||
/**
|
||||
* \brief Check whether the parity of the given uint64_t is even.
|
||||
* <BR>See https://graphics.stanford.edu/~seander/bithacks.html for more.
|
||||
*
|
||||
* \param word
|
||||
* The uint64_t to check.
|
||||
|
@ -296,7 +297,6 @@ namespace gr {
|
|||
// i5 = pack_nibble(1, 0, 1, 1),
|
||||
// i6 = pack_nibble(0, 0, 1, 0),
|
||||
// i7 = pack_nibble(0, 0, 0, 1);
|
||||
|
||||
// H[i0] = 0;
|
||||
// H[i1] = 1;
|
||||
// H[i2] = 2;
|
||||
|
|
|
@ -4,7 +4,8 @@ import collections, datetime
|
|||
import os.path
|
||||
import xmltodict
|
||||
|
||||
from gnuradio import gr, gr_unittest, blocks
|
||||
from gnuradio import gr, gr_unittest, blocks, filter
|
||||
from gnuradio.filter import firdes
|
||||
|
||||
TestResultData = collections.namedtuple('TestResultData', ['id', 'fromfile', 'passing', 'total', 'rate'])
|
||||
TestSerieSettings = collections.namedtuple('TestSerieSettings', ['data', 'times'])
|
||||
|
@ -82,6 +83,10 @@ class qa_BasicTest_XML (gr_unittest.TestCase):
|
|||
#self.bitrate = self.sf * (1 / (2**self.sf / self.bw ))
|
||||
self.hasHDR = True
|
||||
|
||||
# For FFT, determine Center Frequency Offset first, then set here.
|
||||
# For RN2483, usually -14.1e3
|
||||
self.center_offset = 0
|
||||
|
||||
self.inputFile = "./"
|
||||
|
||||
# Socket connection for sink
|
||||
|
@ -215,9 +220,11 @@ class qa_BasicTest_XML (gr_unittest.TestCase):
|
|||
self.lora_lora_receiver_0 = lora.lora_receiver(self.samp_rate, self.capture_freq, self.offset, self.sf, self.samp_rate)
|
||||
self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, self.samp_rate, True)
|
||||
self.blocks_message_socket_sink_0 = lora.message_socket_sink()
|
||||
self.freq_xlating_fir_filter_0 = filter.freq_xlating_fir_filter_ccc(1, (firdes.low_pass(1, self.samp_rate, 500000, 100000, firdes.WIN_HAMMING, 6.67)), self.center_offset, self.samp_rate)
|
||||
|
||||
self.tb.connect( (self.file_source, 0), (self.blocks_throttle_0, 0))
|
||||
self.tb.connect( (self.blocks_throttle_0, 0), (self.lora_lora_receiver_0, 0))
|
||||
self.tb.connect( (self.blocks_throttle_0, 0), (self.freq_xlating_fir_filter_0, 0))
|
||||
self.tb.connect( (self.freq_xlating_fir_filter_0, 0), (self.lora_lora_receiver_0, 0))
|
||||
self.tb.msg_connect( (self.lora_lora_receiver_0, 'frames'), (self.blocks_message_socket_sink_0, 'in'))
|
||||
|
||||
self.tb.run ()
|
||||
|
|
Ładowanie…
Reference in New Issue