kopia lustrzana https://github.com/rpp0/gr-lora
Autocorr preamble detection
rodzic
7b2bbb5efe
commit
c45f156267
|
@ -1,13 +1,13 @@
|
|||
-------- Test Results on 2017-08-23 17:39:53 ---------
|
||||
-------- Test Results on 2017-08-23 17:51:40 ---------
|
||||
Test serie 0: [u'01 23 45 67 89 ab cd ef'] * 10
|
||||
Test 1 :: cr4-5 bw125 sf7 crc1 pwr1 :: passed 10 out of 10 (100.00%)
|
||||
Test 2 :: cr4-5 bw125 sf8 crc1 pwr1 :: passed 9 out of 10 ( 90.00%)
|
||||
Test 2 :: cr4-5 bw125 sf8 crc1 pwr1 :: passed 8 out of 10 ( 80.00%)
|
||||
Test 3 :: cr4-5 bw125 sf12 crc1 pwr1 :: passed 0 out of 10 ( 0.00%)
|
||||
Test 4 :: cr4-7 bw125 sf6 crc1 pwr1 :: passed 0 out of 10 ( 0.00%)
|
||||
Test 5 :: cr4-7 bw125 sf7 crc1 pwr1 :: passed 10 out of 10 (100.00%)
|
||||
Test 5 :: cr4-7 bw125 sf7 crc1 pwr1 :: passed 9 out of 10 ( 90.00%)
|
||||
Test 6 :: cr4-6 bw125 sf6 crc1 pwr1 :: passed 0 out of 10 ( 0.00%)
|
||||
Test 7 :: cr4-6 bw125 sf7 crc1 pwr1 :: passed 10 out of 10 (100.00%)
|
||||
=> Total passed: 39 out of 70 (55.71%)
|
||||
Test 7 :: cr4-6 bw125 sf7 crc1 pwr1 :: passed 8 out of 10 ( 80.00%)
|
||||
=> Total passed: 35 out of 70 (50.00%)
|
||||
|
||||
Test serie 1: [u'11 11 11'] * 1
|
||||
Test 8 :: cr4-5 bw125 sf7 crc1 pwr1 :: passed 1 out of 1 (100.00%)
|
||||
|
@ -23,21 +23,21 @@ Test serie 2: [u'11 11 11'] * 5
|
|||
Test 15 :: cr4-5 bw125 sf7 crc1 pwr1 :: passed 5 out of 5 (100.00%)
|
||||
Test 16 :: cr4-5 bw125 sf8 crc1 pwr1 :: passed 5 out of 5 (100.00%)
|
||||
Test 17 :: cr4-5 bw125 sf12 crc1 pwr1 :: passed 1 out of 5 ( 20.00%)
|
||||
Test 18 :: cr4-7 bw125 sf6 crc1 pwr1 :: passed 3 out of 5 ( 60.00%)
|
||||
Test 18 :: cr4-7 bw125 sf6 crc1 pwr1 :: passed 4 out of 5 ( 80.00%)
|
||||
Test 19 :: cr4-7 bw125 sf7 crc1 pwr1 :: passed 5 out of 5 (100.00%)
|
||||
Test 20 :: cr4-6 bw125 sf6 crc1 pwr1 :: passed 1 out of 5 ( 20.00%)
|
||||
Test 20 :: cr4-6 bw125 sf6 crc1 pwr1 :: passed 2 out of 5 ( 40.00%)
|
||||
Test 21 :: cr4-6 bw125 sf7 crc1 pwr1 :: passed 5 out of 5 (100.00%)
|
||||
=> Total passed: 25 out of 35 (71.43%)
|
||||
=> Total passed: 27 out of 35 (77.14%)
|
||||
|
||||
Test serie 3: [u'aa aa aa aa'] * 3
|
||||
Test 22 :: cr4-5 bw125 sf7 crc1 pwr1 :: passed 3 out of 3 (100.00%)
|
||||
Test 23 :: cr4-5 bw125 sf8 crc1 pwr1 :: passed 3 out of 3 (100.00%)
|
||||
Test 24 :: cr4-5 bw125 sf12 crc1 pwr1 :: passed 0 out of 3 ( 0.00%)
|
||||
Test 25 :: cr4-7 bw125 sf6 crc1 pwr1 :: passed 2 out of 3 ( 66.67%)
|
||||
Test 25 :: cr4-7 bw125 sf6 crc1 pwr1 :: passed 1 out of 3 ( 33.33%)
|
||||
Test 26 :: cr4-7 bw125 sf7 crc1 pwr1 :: passed 3 out of 3 (100.00%)
|
||||
Test 27 :: cr4-6 bw125 sf6 crc1 pwr1 :: passed 0 out of 3 ( 0.00%)
|
||||
Test 28 :: cr4-6 bw125 sf7 crc1 pwr1 :: passed 3 out of 3 (100.00%)
|
||||
=> Total passed: 14 out of 21 (66.67%)
|
||||
=> Total passed: 13 out of 21 (61.90%)
|
||||
|
||||
Test serie 4: [u'ff ff ff ff'] * 1
|
||||
Test 29 :: cr4-5 bw125 sf7 crc1 pwr1 :: passed 1 out of 1 (100.00%)
|
||||
|
@ -64,10 +64,10 @@ Test serie 6: [u'55 55 55 55'] * 3
|
|||
Test 44 :: cr4-5 bw125 sf8 crc1 pwr1 :: passed 3 out of 3 (100.00%)
|
||||
Test 45 :: cr4-5 bw125 sf12 crc1 pwr1 :: passed 0 out of 3 ( 0.00%)
|
||||
Test 46 :: cr4-7 bw125 sf6 crc1 pwr1 :: passed 0 out of 3 ( 0.00%)
|
||||
Test 47 :: cr4-7 bw125 sf7 crc1 pwr1 :: passed 3 out of 3 (100.00%)
|
||||
Test 47 :: cr4-7 bw125 sf7 crc1 pwr1 :: passed 2 out of 3 ( 66.67%)
|
||||
Test 48 :: cr4-6 bw125 sf6 crc1 pwr1 :: passed 0 out of 3 ( 0.00%)
|
||||
Test 49 :: cr4-6 bw125 sf7 crc1 pwr1 :: passed 3 out of 3 (100.00%)
|
||||
=> Total passed: 12 out of 21 (57.14%)
|
||||
=> Total passed: 11 out of 21 (52.38%)
|
||||
|
||||
Test serie 7: [u'55 55 55 55'] * 10
|
||||
Test 50 :: cr4-5 bw125 sf7 crc1 pwr1 :: passed 10 out of 10 (100.00%)
|
||||
|
@ -90,25 +90,25 @@ Test serie 8: [u'88 88 88 88'] * 1
|
|||
=> Total passed: 4 out of 7 (57.14%)
|
||||
|
||||
Test serie 9: [u'88 88 88 88'] * 5
|
||||
Test 64 :: cr4-5 bw125 sf7 crc1 pwr1 :: passed 5 out of 5 (100.00%)
|
||||
Test 65 :: cr4-5 bw125 sf8 crc1 pwr1 :: passed 5 out of 5 (100.00%)
|
||||
Test 64 :: cr4-5 bw125 sf7 crc1 pwr1 :: passed 4 out of 5 ( 80.00%)
|
||||
Test 65 :: cr4-5 bw125 sf8 crc1 pwr1 :: passed 4 out of 5 ( 80.00%)
|
||||
Test 66 :: cr4-5 bw125 sf12 crc1 pwr1 :: passed 0 out of 5 ( 0.00%)
|
||||
Test 67 :: cr4-7 bw125 sf6 crc1 pwr1 :: passed 0 out of 5 ( 0.00%)
|
||||
Test 67 :: cr4-7 bw125 sf6 crc1 pwr1 :: passed 2 out of 5 ( 40.00%)
|
||||
Test 68 :: cr4-7 bw125 sf7 crc1 pwr1 :: passed 5 out of 5 (100.00%)
|
||||
Test 69 :: cr4-6 bw125 sf6 crc1 pwr1 :: passed 0 out of 5 ( 0.00%)
|
||||
Test 69 :: cr4-6 bw125 sf6 crc1 pwr1 :: passed 1 out of 5 ( 20.00%)
|
||||
Test 70 :: cr4-6 bw125 sf7 crc1 pwr1 :: passed 5 out of 5 (100.00%)
|
||||
=> Total passed: 20 out of 35 (57.14%)
|
||||
=> Total passed: 21 out of 35 (60.00%)
|
||||
|
||||
Test serie 10: [u'88 88 88 88'] * 10
|
||||
Test 71 :: cr4-5 bw125 sf7 crc1 pwr1 :: passed 10 out of 10 (100.00%)
|
||||
Test 72 :: cr4-5 bw125 sf8 crc1 pwr1 :: passed 10 out of 10 (100.00%)
|
||||
Test 73 :: cr4-5 bw125 sf12 crc1 pwr1 :: passed 0 out of 10 ( 0.00%)
|
||||
Test 74 :: cr4-7 bw125 sf6 crc1 pwr1 :: passed 0 out of 10 ( 0.00%)
|
||||
Test 75 :: cr4-7 bw125 sf7 crc1 pwr1 :: passed 10 out of 10 (100.00%)
|
||||
Test 74 :: cr4-7 bw125 sf6 crc1 pwr1 :: passed 5 out of 10 ( 50.00%)
|
||||
Test 75 :: cr4-7 bw125 sf7 crc1 pwr1 :: passed 9 out of 10 ( 90.00%)
|
||||
Test 76 :: cr4-6 bw125 sf6 crc1 pwr1 :: passed 0 out of 10 ( 0.00%)
|
||||
Test 77 :: cr4-6 bw125 sf7 crc1 pwr1 :: passed 10 out of 10 (100.00%)
|
||||
=> Total passed: 40 out of 70 (57.14%)
|
||||
=> Total passed: 44 out of 70 (62.86%)
|
||||
|
||||
|
||||
====== Total passed: 239 out of 413 (57.87%) ======
|
||||
====== Total passed: 240 out of 413 (58.11%) ======
|
||||
|
||||
|
|
|
@ -362,6 +362,27 @@ namespace gr {
|
|||
d_fine_sync = -lag;
|
||||
}
|
||||
|
||||
float decoder_impl::detect_preamble_autocorr(const gr_complex *samples, const uint32_t window) {
|
||||
const gr_complex* chirp1 = samples;
|
||||
const gr_complex* chirp2 = samples + d_samples_per_symbol;
|
||||
float magsq_chirp1[window];
|
||||
float magsq_chirp2[window];
|
||||
float energy_chirp1 = 0;
|
||||
float energy_chirp2 = 0;
|
||||
float autocorr = 0;
|
||||
gr_complex dot_product;
|
||||
|
||||
volk_32fc_x2_conjugate_dot_prod_32fc(&dot_product, chirp1, chirp2, window);
|
||||
volk_32fc_magnitude_squared_32f(magsq_chirp1, chirp1, window);
|
||||
volk_32fc_magnitude_squared_32f(magsq_chirp2, chirp2, window);
|
||||
volk_32f_accumulator_s32f(&energy_chirp1, magsq_chirp1, window);
|
||||
volk_32f_accumulator_s32f(&energy_chirp2, magsq_chirp2, window);
|
||||
|
||||
autocorr = abs(dot_product / gr_complex(sqrt(energy_chirp1 * energy_chirp2), 0));
|
||||
|
||||
return autocorr;
|
||||
}
|
||||
|
||||
float decoder_impl::detect_downchirp(const gr_complex *samples, const uint32_t window) {
|
||||
float samples_ifreq[window];
|
||||
this->instantaneous_frequency(samples, samples_ifreq, window);
|
||||
|
@ -369,55 +390,24 @@ namespace gr {
|
|||
return this->cross_correlate_ifreq(samples_ifreq, this->d_downchirp_ifreq, window - 1u);
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Skip through the window and look for a falling edge
|
||||
* 2. Get the upper and lower bound of the upchrip edge, or the local maximum and minimum
|
||||
* 3. Look for the highest cross correlation index between these points and return
|
||||
*/
|
||||
float decoder_impl::sliding_norm_cross_correlate_upchirp(const float *samples_ifreq, const uint32_t window, int32_t *index) {
|
||||
bool found_change = false;
|
||||
uint32_t local_max_idx = 0u, local_min_idx;
|
||||
float decoder_impl::sliding_norm_cross_correlate_upchirp(const float *samples_ifreq, const uint32_t window, int32_t *index) {
|
||||
float max_correlation = 0;
|
||||
|
||||
const uint32_t coeff = (this->d_sf + this->d_sf + this->d_sf / 2u);
|
||||
const uint32_t len = this->d_samples_per_symbol - 1u;
|
||||
// Cross correlate
|
||||
for (uint32_t i = 0; i < window; i++) {
|
||||
const float max_corr = this->cross_correlate_ifreq_fast(samples_ifreq + i, &this->d_upchirp_ifreq[0], window - 1u);
|
||||
|
||||
float max_correlation = 0.0f;
|
||||
if (max_corr > max_correlation) {
|
||||
*index = i;
|
||||
max_correlation = max_corr;
|
||||
}
|
||||
}
|
||||
|
||||
// Approximate local maximum
|
||||
for (uint32_t i = 0u; i < window - coeff - 1u; i += coeff / 2u) {
|
||||
if (samples_ifreq[i] - samples_ifreq[i + coeff] > 0.2f) { // Goes down
|
||||
local_max_idx = i;
|
||||
found_change = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
|
||||
if (!found_change) {
|
||||
//printf("No falling edge?\n");
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// Find top and bottom of falling edge after first upchirp in window
|
||||
local_max_idx = std::max_element(samples_ifreq + gr::lora::clamp((int)(local_max_idx - 2u * coeff), 0, (int)window),
|
||||
samples_ifreq + gr::lora::clamp(local_max_idx + coeff, 0u, window)) - samples_ifreq;
|
||||
local_min_idx = std::min_element(samples_ifreq + gr::lora::clamp(local_max_idx + 1u, 0u, window),
|
||||
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 + 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;
|
||||
}
|
||||
return max_correlation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Slide the given chirp perfectly on top of the ideal upchirp (phase shift).
|
||||
|
@ -453,8 +443,8 @@ namespace gr {
|
|||
}
|
||||
|
||||
float decoder_impl::detect_upchirp(const gr_complex *samples, const uint32_t window, int32_t *index) {
|
||||
float samples_ifreq[window];
|
||||
this->instantaneous_frequency(samples, samples_ifreq, window);
|
||||
float samples_ifreq[window*2];
|
||||
this->instantaneous_frequency(samples, samples_ifreq, window*2);
|
||||
|
||||
return this->sliding_norm_cross_correlate_upchirp(samples_ifreq, window, index);
|
||||
}
|
||||
|
@ -826,39 +816,34 @@ namespace gr {
|
|||
|
||||
switch (this->d_state) {
|
||||
case gr::lora::DecoderState::DETECT: {
|
||||
const int i = this->find_preamble_start_fast(input);
|
||||
//int i = this->find_preamble_start(&input[0]);
|
||||
//int i = this->calc_energy_threshold(&input[0], 2u * this->d_samples_per_symbol, this->d_energy_threshold);
|
||||
float correlation = detect_preamble_autocorr(input, d_samples_per_symbol);
|
||||
|
||||
if (i != -1) {
|
||||
int32_t index_correction = 0;
|
||||
|
||||
const float c = this->detect_upchirp(&input[i],
|
||||
this->d_samples_per_symbol * 2u,
|
||||
&index_correction);
|
||||
|
||||
if (c > 0.9f) {
|
||||
#ifndef NDEBUG
|
||||
this->d_debug << "Cu: " << c << std::endl;
|
||||
#endif
|
||||
this->samples_to_file("/tmp/detectb", &input[i], this->d_samples_per_symbol, sizeof(gr_complex));
|
||||
this->samples_to_file("/tmp/detect", &input[i + index_correction], this->d_samples_per_symbol, sizeof(gr_complex));
|
||||
this->d_corr_fails = 0u;
|
||||
this->d_state = gr::lora::DecoderState::SYNC;
|
||||
this->consume_each(i + index_correction);
|
||||
break;
|
||||
}
|
||||
|
||||
// Consume just 1 symbol after preamble to have more chances to sync later
|
||||
this->consume_each(i + this->d_samples_per_symbol);
|
||||
} else {
|
||||
// Consume 2 symbols (usual) to skip noise faster before preamble has been found
|
||||
this->consume_each(2u * this->d_samples_per_symbol);
|
||||
if (correlation >= 0.95f) {
|
||||
this->samples_to_file("/tmp/detect", &input[0], this->d_samples_per_symbol, sizeof(gr_complex));
|
||||
this->d_corr_fails = 0u;
|
||||
this->d_state = gr::lora::DecoderState::SYNC;
|
||||
break;
|
||||
}
|
||||
|
||||
this->consume_each(this->d_samples_per_symbol);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gr::lora::DecoderState::SYNC: {
|
||||
int i = 0;
|
||||
float correlation = detect_upchirp(input, d_samples_per_symbol, &i);
|
||||
|
||||
#ifndef NDEBUG
|
||||
this->d_debug << "Cu: " << correlation << std::endl;
|
||||
#endif
|
||||
|
||||
this->consume_each(i);
|
||||
this->d_state = gr::lora::DecoderState::FIND_SFD;
|
||||
break;
|
||||
}
|
||||
|
||||
case gr::lora::DecoderState::FIND_SFD: {
|
||||
const float c = this->detect_downchirp(input, this->d_samples_per_symbol);
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace gr {
|
|||
enum class DecoderState {
|
||||
DETECT,
|
||||
SYNC,
|
||||
FIND_SFD,
|
||||
PAUSE,
|
||||
DECODE_HEADER,
|
||||
DECODE_PAYLOAD,
|
||||
|
@ -120,6 +121,7 @@ namespace gr {
|
|||
float cross_correlate_ifreq_fast(const float *samples_ifreq, const float *ideal_chirp, const uint32_t window);
|
||||
void fine_sync(const gr_complex* in_samples, uint32_t bin_idx);
|
||||
int32_t d_fine_sync;
|
||||
float detect_preamble_autocorr(const gr_complex *samples, uint32_t window);
|
||||
|
||||
/**
|
||||
* \brief Calculates the average energy from the given samples and returns whether its higher than the given threshold.
|
||||
|
|
Ładowanie…
Reference in New Issue