From c5ac3896fb0f6d669031c3ea1ae99e1f06e23628 Mon Sep 17 00:00:00 2001 From: Sassa NF Date: Sat, 21 Sep 2024 16:36:21 +0100 Subject: [PATCH] Factor out detection + display loop Refactor code that does not depend on y. Essentially, the following logic: Recall that some loops are folds, some are maps. Maps look at only elements with one index. The important property of maps is that map(f . g) = map(f) . map(g) - parts of the loop body can be split into separate loops. Another property of maps is that if map(f) does not depend on the output of map(g), then map(f) . map(g) = map(g) . map(f) - the loops can be reordered. --- lib/scan/scan.cpp | 67 +++++++++++++++- lib/scan/scan.h | 22 +++--- src/main.cpp | 148 +++++++++++++----------------------- src/radioScan/radioScan.cpp | 59 ++++++++++++++ src/radioScan/radioScan.h | 10 +++ 5 files changed, 197 insertions(+), 109 deletions(-) diff --git a/lib/scan/scan.cpp b/lib/scan/scan.cpp index bf8b416..bc58902 100644 --- a/lib/scan/scan.cpp +++ b/lib/scan/scan.cpp @@ -6,17 +6,17 @@ #include #include -float Scan::getRSSI() { return 0.1; } - -uint16_t Scan::rssiMethod(uint16_t *result) +uint16_t Scan::rssiMethod(size_t samples, uint16_t *result, size_t res_size) { + float scale((float)res_size / (HI_RSSI_THRESHOLD - LO_RSSI_THRESHOLD + 0.1)); + memset(result, 0, res_size * sizeof(uint16_t)); int result_index = 0; // uint16_t max_signal = 65535; // N of samples - for (int r = 0; r < SAMPLES_RSSI; r++) + for (int r = 0; r < samples; r++) { float rssi = getRSSI(); if (rssi < -65535) @@ -66,4 +66,63 @@ uint16_t Scan::rssiMethod(uint16_t *result) return max_signal; } +size_t Scan::detect(uint16_t *result, bool *filtered_result, size_t result_size, + int samples) +{ + size_t max_rssi_x = 999; + + for (int y = 0; y < result_size; y++) + { + + LOG("%i:%i,", y, result[y]); +#if !defined(FILTER_SPECTRUM_RESULTS) || FILTER_SPECTRUM_RESULTS == false + if (result[y] && result[y] != 0) + { + filtered_result[y] = 1; + } + else + { + filtered_result[y] = 0; + } +#endif + +// if samples low ~1 filter removes all values +#if FILTER_SPECTRUM_RESULTS + + filtered_result[y] = 0; + // Filter Elements without neighbors + // if RSSI method actual value is -xxx dB + if (result[y] > 0 && samples > 1) + { + // do not process 'first' and 'last' row to avoid out of index + // access. + if ((y > 0) && (y < (result_size - 2))) + { + if (((result[y + 1] != 0) && (result[y + 2] != 0)) || + (result[y - 1] != 0)) + { + filtered_result[y] = 1; + // Fill empty pixel + result[y + 1] = 1; + } + else + { + LOG("Filtered::%i,", y); + } + } + } // not filtering if samples == 1 because it will be filtered + else if (result[y] > 0 && samples == 1) + { + filtered_result[y] = 1; + } +#endif + if (filtered_result[y] && max_rssi_x > y) + { + max_rssi_x = y; + } + } + + return max_rssi_x; +} + #endif diff --git a/lib/scan/scan.h b/lib/scan/scan.h index 36f449c..bfbdcf8 100644 --- a/lib/scan/scan.h +++ b/lib/scan/scan.h @@ -30,17 +30,21 @@ constexpr float LO_RSSI_THRESHOLD = HI_RSSI_THRESHOLD - 66; struct Scan { - Scan(int sz) - : res_size(sz), scale((float)sz / (HI_RSSI_THRESHOLD - LO_RSSI_THRESHOLD + 0.1)) - { - } + virtual float getRSSI() = 0; - virtual float getRSSI(); + // rssiMethod gets the data similar to the scan method, + // but uses getRSSI directly. + uint16_t rssiMethod(size_t samples, uint16_t *result, size_t res_size); - uint16_t rssiMethod(uint16_t *result); - - int res_size; - float scale; + // detect method analyses result, and produces filtered_result, marking + // those values that represent a detection event. + // It returns index that represents strongest signal at which a detection event + // occurred. + static size_t detect(uint16_t *result, bool *filtered_result, size_t result_size, + int samples); }; +// Remove reading without neighbors +#define FILTER_SPECTRUM_RESULTS true + #endif diff --git a/src/main.cpp b/src/main.cpp index a7704e9..6f48c1d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -144,8 +144,6 @@ bool ANIMATED_RELOAD = false; #define UP_FILTER 5 // Trim low signals - nose level #define START_LOW 6 -// Remove reading without neighbors -#define FILTER_SPECTRUM_RESULTS true #define FILTER_SAMPLES_MIN constexpr bool DRAW_DETECTION_TICKS = true; int16_t max_x_rssi[STEPS] = {999}; @@ -888,9 +886,7 @@ void loop(void) float step = (range * ((float)x / (STEPS * SCAN_RBW_FACTOR))); freq = fr_begin + step; -#ifdef PRINT_DEBUG - Serial.println("setFrequency:" + String(freq)); -#endif + LOG("setFrequency:%f\n", freq); #ifdef USING_SX1280PA state = radio.setFrequency(freq); // 1280 doesn't have calibration @@ -911,9 +907,7 @@ void loop(void) continue; } -#ifdef PRINT_DEBUG - Serial.printf("Step:%d Freq: %f\n", x, freq); -#endif + LOG("Step:%d Freq: %f\n", x, freq); // SpectralScan Method #ifdef METHOD_SPECTRAL { @@ -971,59 +965,21 @@ void loop(void) display.setColor(WHITE); } #endif - detected = false; - detected_y[display_x] = false; - max_rssi_x = 999; + size_t detected_at = r.detect( + result, filtered_result, RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE, samples); - for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) + if (max_rssi_x > detected_at) { + // MAx bin Value not RSSI + max_rssi_x = detected_at; + } -#ifdef PRINT_DEBUG - Serial.print(String(y) + ":"); - Serial.print(String(result[y]) + ","); -#endif -#if !defined(FILTER_SPECTRUM_RESULTS) || FILTER_SPECTRUM_RESULTS == false - if (result[y] && result[y] != 0) - { - filtered_result[y] = 1; - } - else - { - filtered_result[y] = 0; - } -#endif + detected = detected_at < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; + detected_y[display_x] = false; -// if samples low ~1 filter removes all values #if FILTER_SPECTRUM_RESULTS - - filtered_result[y] = 0; - // Filter Elements without neighbors - // if RSSI method actual value is -xxx dB - if (result[y] > 0 && samples > 1) - { - // do not process 'first' and 'last' row to avoid out of index - // access. - if ((y > 0) && (y < (RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE - 2))) - { - if (((result[y + 1] != 0) && (result[y + 2] != 0)) || - (result[y - 1] != 0)) - { - filtered_result[y] = 1; - // Fill empty pixel - result[y + 1] = 1; - } - else - { -#ifdef PRINT_DEBUG - Serial.print("Filtered:" + String(x) + ":" + String(y) + ","); -#endif - } - } - } // not filtering if samples == 1 because it will be filtered - else if (result[y] > 0 && samples == 1) - { - filtered_result[y] = 1; - } + for (int y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) + { // calculating max window x RSSI after filters x_window = (int)(display_x / WINDOW_SIZE); int abs_result = abs(result[y]); @@ -1031,16 +987,15 @@ void loop(void) max_x_window[x_window] > abs_result) { max_x_window[x_window] = abs_result; -#ifdef PRINT_DEBUG - Serial.println("MAX x window: " + String(x_window) + " " + - String(abs_result)); -#endif + LOG("MAX x window: %i %i\n", x_window, abs_result); } + } #endif + + if (detected_at <= drone_detection_level) + { // check if we should alarm about a drone presence - if ((filtered_result[y] == 1) // we have some data and - && (y <= drone_detection_level) && - detected_y[display_x] == false) // detection threshold match + if (detected_y[display_x] == false) // detection threshold match { // Set LED to ON (filtered in UI component) UI_setLedFlag(true); @@ -1084,8 +1039,7 @@ void loop(void) } } #if (WATERFALL_ENABLED == true) - if ((filtered_result[y] == 1) && (y <= drone_detection_level) && - (single_page_scan) && (waterfall[display_x] != true) && new_pixel) + if ((single_page_scan) && (waterfall[display_x] != true) && new_pixel) { // If drone not found set dark pixel on the waterfall // TODO: make something like scrolling up if possible @@ -1095,44 +1049,46 @@ void loop(void) display.setColor(WHITE); } #endif - // next 2 If's ... adds !!!! 10ms of runtime ......tfk ??? + } + +#ifdef PRINT_DEBUG + for (int y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) + { if (filtered_result[y] == 1) { -#ifdef PRINT_DEBUG - Serial.print("Pixel:" + String(display_x) + "(" + String(x) + ")" + - ":" + String(y) + ","); -#endif - if (max_rssi_x > y) - { - // MAx bin Value not RSSI - max_rssi_x = y; - } - // Set MAIN signal level pixel - if (y < MAX_POWER_LEVELS - START_LOW) - { - display.setPixel(display_x, y + START_LOW); - } - if (!detected) - { - detected = true; - } + LOG("Pixel:%i(%i):%i,", display_x, x, y); } + } +#endif - // ------------------------------------------------------------- - // Draw "Detection Level line" every 2 pixel - // ------------------------------------------------------------- - if ((y == drone_detection_level) && (display_x % 2 == 0)) + for (int y = 0; y < min(RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE, + MAX_POWER_LEVELS - START_LOW); + y++) + { + if (filtered_result[y] == 1) + { + // Set MAIN signal level pixel + display.setPixelColor(display_x, y + START_LOW, WHITE); + } + } + + // ------------------------------------------------------------- + // Draw "Detection Level line" every 2 pixel + // ------------------------------------------------------------- + if (display_x % 2 == 0) + { + if (filtered_result[drone_detection_level] == 1) + { + display.setColor(INVERSE); + } + else { display.setColor(WHITE); - if (filtered_result[y] == 1) - { - display.setColor(INVERSE); - } - display.setPixel(display_x, y + START_LOW); - // display.setPixel(display_x, y + START_LOW - 1); // 2 px wide - - display.setColor(WHITE); } + display.setPixel(display_x, drone_detection_level + START_LOW); + // display.setPixel(display_x, y + START_LOW - 1); // 2 px wide + + display.setColor(WHITE); } #ifdef JOYSTICK_ENABLED diff --git a/src/radioScan/radioScan.cpp b/src/radioScan/radioScan.cpp index 73150fc..a5a2332 100644 --- a/src/radioScan/radioScan.cpp +++ b/src/radioScan/radioScan.cpp @@ -66,4 +66,63 @@ uint16_t Scan::rssiMethod(size_t samples, uint16_t *result, size_t res_size) return max_signal; } +size_t Scan::detect(uint16_t *result, bool *filtered_result, size_t result_size, + int samples) +{ + size_t max_rssi_x = 999; + + for (int y = 0; y < result_size; y++) + { + + LOG("%i:%i,", y, result[y]); +#if !defined(FILTER_SPECTRUM_RESULTS) || FILTER_SPECTRUM_RESULTS == false + if (result[y] && result[y] != 0) + { + filtered_result[y] = 1; + } + else + { + filtered_result[y] = 0; + } +#endif + +// if samples low ~1 filter removes all values +#if FILTER_SPECTRUM_RESULTS + + filtered_result[y] = 0; + // Filter Elements without neighbors + // if RSSI method actual value is -xxx dB + if (result[y] > 0 && samples > 1) + { + // do not process 'first' and 'last' row to avoid out of index + // access. + if ((y > 0) && (y < (result_size - 2))) + { + if (((result[y + 1] != 0) && (result[y + 2] != 0)) || + (result[y - 1] != 0)) + { + filtered_result[y] = 1; + // Fill empty pixel + result[y + 1] = 1; + } + else + { + LOG("Filtered::%i,", y); + } + } + } // not filtering if samples == 1 because it will be filtered + else if (result[y] > 0 && samples == 1) + { + filtered_result[y] = 1; + } +#endif + if (filtered_result[y] && max_rssi_x > y) + { + max_rssi_x = y; + } + } + + return max_rssi_x; +} + #endif diff --git a/src/radioScan/radioScan.h b/src/radioScan/radioScan.h index 1c8ca8e..bfbdcf8 100644 --- a/src/radioScan/radioScan.h +++ b/src/radioScan/radioScan.h @@ -35,6 +35,16 @@ struct Scan // rssiMethod gets the data similar to the scan method, // but uses getRSSI directly. uint16_t rssiMethod(size_t samples, uint16_t *result, size_t res_size); + + // detect method analyses result, and produces filtered_result, marking + // those values that represent a detection event. + // It returns index that represents strongest signal at which a detection event + // occurred. + static size_t detect(uint16_t *result, bool *filtered_result, size_t result_size, + int samples); }; +// Remove reading without neighbors +#define FILTER_SPECTRUM_RESULTS true + #endif