diff --git a/README.md b/README.md index 7ac2249..f04980e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,15 @@ # Lora SA(Spectrum Analyzer) +# Supportted boards: +- Heltec Lora V3 128 x 64 OLED +- Heltec Wireless Stick V3 64 x 32 (Not tested) +- Heltec Wireless Stick Lite V3 No Display (Not Tested) +- Heltec Vision Master E290 - e-Ink 296 x 128 (No OSD) +- Heltec Vision MAster T190 - color TFT 320X170 (No OSD) +- LilyGo Radio Lora T3S3 V.2 SX1262 +- LilyGo Radio Lora T3S3 V.2 SX1280 +- LilyGo Radio Lora T3_V1.6.1 SX1276 (Not Tested) + ## RF Spectrum Analyzer using Lora Radio LORA hardware @@ -213,3 +223,95 @@ or buy : ![image](https://github.com/user-attachments/assets/a1e00b51-5566-4ff5-98fe-67eaeb5bc81f) We are using pin 41 as a Buzzer trigger. Connect buzzer + leg with pin 41 and - leg with the ground (GND). You can change the buzzer pin in the code. + + +## Analog FPV OSD (ON SCREEN DISPLAY) +To Enable OSD, Uncomment these lines
+``` +// #define OSD_ENABLED true +``` +**OSD sidebar enabled/disable** +comment or uncomment this line +``` +#define OSD_SIDE_BAR true +``` + +Or you can set this and other variables as a build parameter: +``` +build_flags = + -DOSD_ENABLED +``` + +## DFRobot OSD Wiring +**Heltec V3 -> DFRobot OSD**
+GND -> GND
+3V3 -> 3V3
+26 -> SCK
+34 ->MOSI
+33 ->MISO
+47 -> D3
+ +More photos you can see there:
+https://github.com/Genaker/LoraSA/issues/11 + +![image](https://github.com/user-attachments/assets/3ba8230d-21de-449d-881b-bdc5f5b4907d) + +# Camera to DF robot Wiring +**Camera -> DFRobotOSD**
+Video out -> In
+GND -> GND
+3v3 -> 3V3 Heltec or some 3v on FPV
+ +# DFRobot to Drone or VTX(video transmitter) +**DF Robot -> VTX or**
+Video Out - Video IN
+ +``` +// SPI pins +#define OSD_CS 47 +#define OSD_MISO 33 +#define OSD_MOSI 34 +#define OSD_SCK 26 +``` + +## Joystick Wiring +https://www.aliexpress.us/item/2251832815289133.html +https://www.amazon.com/dp/B00P7QBGD2 + +**Loystic -> Heltec V3**
+SW -> 46
+VRX -> 19
+VRY -> X has not been implemented yet
++5v -> 5V
+GND -> GND
+ +## Buzzer/Beeper Wiring +TMB12A03 - in my case. Low voltage is better.
+**Buzzer -> Heltec V3**
+(+) -> 41
+GND (another) -> GND
+ +## Select Board to build +Select Visual Code environment: +![image](https://github.com/user-attachments/assets/3765615b-3a80-4270-bc74-8f6eae2b8458) + +Edit **paltformio.io** uncommenting/selecting your sources +``` +[platformio] +; for env:vision-master-e190 +; src_dir = tft_src +; for env:vision-master-e290 +; src_dir = eink_src +; for env:heltec_wifi_lora_32_V3 +; src_dir = src ;;Default +``` +for LilyGo use env:heltec_wifi_lora_32_V3 + +# WiFi and Bluetooth BT Scanning +Works only with OSD enabled
+Uncomment this lines +``` +// #define OSD_ENABLED true +// #define WIFI_SCANNING_ENABLED true +// #define BT_SCANNING_ENABLED true +``` diff --git a/include/DFRobot_OSD.h b/include/DFRobot_OSD.h index d446a86..063753c 100644 --- a/include/DFRobot_OSD.h +++ b/include/DFRobot_OSD.h @@ -13,8 +13,67 @@ #ifndef _DFRobot_OSD_H_ #define _DFRobot_OSD_H_ +#define MAX_POWER_LEVELS 33 + #include +/*Define Custom characters Example*/ +static const int buf0[36] = {0x02, 0x80, 0x02, 0x40, 0x7F, 0xE0, 0x42, 0x00, + 0x42, 0x00, 0x7A, 0x40, 0x4A, 0x40, 0x4A, 0x80, + 0x49, 0x20, 0x5A, 0xA0, 0x44, 0x60, 0x88, 0x20}; + +static constexpr uint16_t levels[10] = { + 0x105, // 0 + 0x10E, // 1 + 0x10D, // 2 + 0x10C, // 3 + 0x10B, // 4 + 0x10A, // 5 + 0x109, // 6 + 0x108, // 7 + 0x107, // 8 + 0x106, // 9 +}; + +static constexpr uint16_t power_level[MAX_POWER_LEVELS + 1] = { + 0x10E, // 0 + 0x10E, // 1 + 0x10D, // 2 + 0x10C, // 3 + 0x10B, // 4 + 0x10A, // 5 + 0x109, // 6 + 0x108, // 7 + 0x107, // 8 + 0x106, // 9 not using 106 to accent rise + // new line + 0x10E, // 10 + 0x10D, // 11 + 0x10C, // 12 + 0x10B, // 13 + 0x10A, // 14 + 0x109, // 15 + 0x108, // 16 + 0x107, // 17 + 0x106, // 18 not using 106 + // new line + 0x10E, // 19 + 0x10D, // 20 + 0x10C, // 21 + 0x10B, // 22 + 0x10A, // 23 + 0x109, // 24 + 0x108, // 25 + 0x107, // 26 + 0x106, // 27 + 0x105, // 28 --- + 0x105, // 29 + 0x105, // 30 + 0x105, // 31 + 0x105, // 32 + 0x105 // 33 +}; + // #define ENABLE_DBG //!< Open this macro and you can see the details of the program #ifdef ENABLE_DBG #define DBG(...) \ diff --git a/lib/scan/scan.cpp b/lib/scan/scan.cpp new file mode 100644 index 0000000..bf8b416 --- /dev/null +++ b/lib/scan/scan.cpp @@ -0,0 +1,69 @@ +#ifndef LORASA_CORE_CPP +#define LORASA_CORE_CPP + +#include "scan.h" +#include +#include +#include + +float Scan::getRSSI() { return 0.1; } + +uint16_t Scan::rssiMethod(uint16_t *result) +{ + 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++) + { + float rssi = getRSSI(); + if (rssi < -65535) + rssi = -65535; + + uint16_t abs_rssi = abs(rssi); + if (abs_rssi < max_signal) + { + max_signal = abs_rssi; + } + // ToDO: check if 4 is correct value for 33 power bins + // Now we have more space because we are ignoring low dB values + // we can / 3 default 4 + if (RSSI_OUTPUT_FORMULA == 1) + { + result_index = + /// still not clear formula but it works + uint8_t(abs(rssi) / 4); + } + else if (RSSI_OUTPUT_FORMULA == 2) + { + if (rssi > HI_RSSI_THRESHOLD) + { + rssi = HI_RSSI_THRESHOLD; + } + else if (rssi < LO_RSSI_THRESHOLD) + { + rssi = LO_RSSI_THRESHOLD; + } + + result_index = uint8_t((HI_RSSI_THRESHOLD - rssi) * scale); + } + + if (result_index >= res_size) + { + // Maximum index possible + result_index = res_size - 1; + } + + LOG("RSSI: %f IDX: %d\n", rssi, result_index); + if (result[result_index] == 0 || result[result_index] > abs_rssi) + { + result[result_index] = abs_rssi; + } + } + + return max_signal; +} + +#endif diff --git a/lib/scan/scan.h b/lib/scan/scan.h new file mode 100644 index 0000000..36f449c --- /dev/null +++ b/lib/scan/scan.h @@ -0,0 +1,46 @@ +#include +#include + +#ifndef LORASA_CORE_H + +#define LORASA_CORE_H + +#ifdef PRINT_DEBUG +#define LOG(args...) Serial.printf(args...) +#define LOG_IF(cond, args...) \ + if (cond) \ + LOG(args...) +#elif !defined(LOG) +#define LOG(args...) +#define LOG_IF(cond, args...) +#endif + +// Output Pixel Formula +// 1 = rssi / 4, 2 = (rssi / 2) - 22 or 20 +constexpr int RSSI_OUTPUT_FORMULA = 2; + +// based on the formula for RSSI_OUTPUT_FORMULA == 2 +// -2 * (22 + RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE) < rssi =< -44 +// practice may require a better pair of thresholds +constexpr float HI_RSSI_THRESHOLD = -44.0; +constexpr float LO_RSSI_THRESHOLD = HI_RSSI_THRESHOLD - 66; + +// number of samples for RSSI method +#define SAMPLES_RSSI 12 // 21 // + +struct Scan +{ + Scan(int sz) + : res_size(sz), scale((float)sz / (HI_RSSI_THRESHOLD - LO_RSSI_THRESHOLD + 0.1)) + { + } + + virtual float getRSSI(); + + uint16_t rssiMethod(uint16_t *result); + + int res_size; + float scale; +}; + +#endif diff --git a/ml_research/Diagram_ML.svg b/ml_research/Diagram_ML.svg new file mode 100644 index 0000000..f96baa4 --- /dev/null +++ b/ml_research/Diagram_ML.svg @@ -0,0 +1,4 @@ + + + +
Device produces a scan of N samples in Frequency F and loops over the entire Frequency band

Device cannot produce I/Q data
Device produces a sc...
Datasets contain I/Q data or Spectrograms (that can be built out of I/Q data)
Datasets contain I/Q...
SAME FORMAT











SAME FORMAT...
Generation of pseudo spectrogram with frequency bins and time length similar to train dataset
Generation of pseudo...
Spectrograms are cut so that the shown frequencies and time length is congruent with device data
Spectrograms are cut...
Train data
Convert to TF-Lite
(Model: MobileNetV3?)
Train data...
Prediction on device using TF-Lite library and saved model weights
Prediction on device...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/ml_research/datasets.md b/ml_research/datasets.md new file mode 100644 index 0000000..ebf796a --- /dev/null +++ b/ml_research/datasets.md @@ -0,0 +1,13 @@ +## Overview of ML Dataets + +| dataset name | data content | data format | frequencies / Sampling rate | other infos | source paper/website | source data | open questions | +|----------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------| +| Noisy Drone RF Signal Classification (Glüge et al.) | Drones: DJI, FutabaT14, FutabaT7, Graupner, Taranis, Turnigy | I/Q Data as well as generated Spectrograms available | The device can scan a range of 6Ghz. But the newest plot is very weird. +/- 7 Mhz, can this really be? "non-overlapping signal vectors of length of 1048576 samples, which corresponds to approx. 74.9ms at 14MHz" | mixed with either Labnoise (50%) or Gaussian noise (50%). The noise class was created by mixing Labnoise and Gaussian noise in all possible combinations. Several levels of SNR were used over the entire dataset. | https://www.scitepress.org/Link.aspx?doi=10.5220/0012176800003595 https://github.com/sgluege/Noisy-Drone-RF-Signal-Classification https://github.com/sgluege/Noisy-Drone-RF-Signal-Classification-v2/tree/main | https://www.kaggle.com/datasets/sgluege/noisy-drone-rf-signal-classification-v2/data https://www.kaggle.com/datasets/sgluege/noisy-drone-rf-signal-classification | Not sure about the frequencies. | +| DroneDataset (Swinney and Woods) | Drones: new DJI Mavic 2 Air S, DJI Mavic Pro, DJI Mavic Pro 2, DJI Inspire 2, DJI Mavic Mini, DJI Phantom 4 and the Parrot Disco. | Raw I/Q Data | TODO; Recordings were collected using a Nuand BladeRF SDR and using open source software GNURadio | There are 4 subsets of data included in this dataset, the UAS signals in the presence of Bluetooth interference, in the presence of Wi-Fi signals, in the presence of both and with no interference. 3 flight modes are captured - switched on, hovering and flying. | No paper seen | https://ieee-dataport.org/open-access/dronedetect-dataset-radio-frequency-dataset-unmanned-aerial-system-uas-signals-machine | Sampling rate? | +| DroneRF (Allahham et al.) | Drones: Bepop; AR; Phantom | "the dataset contains only time series data, and not the complex IQ signals" (From Glüge and not from the authors) - but what does this exactly mean? | capture the whole 2.4GHz bandwidth, we have used 2 RF receivers. Each RF receiver has a maximum instantaneous bandwidth of 40 MHz, so both receivers must be operating simultaneously to at least capture a technology spectrum such as WiFi (i.e. 80 MHz). Recorded using universal soft- ware radio peripheral (USRP) software-defined radio (SDR) transceivers. Signals that could be considered noise in the 2.4 GHz band (Bluetooth, Wi-Fi) were not recorded. | modes, including off, on and connected, hovering, flying, and video recording. | https://www.sciencedirect.com/science/article/pii/S2352340919306675?ref=pdf_download&fr=RR-2&rr=8bf5de727fa35d7f | https://data.mendeley.com/datasets/f4c2b4n755/1 | Apparently time versus db? Not very clear what is in the data | +| Radio-Frequency Control and Video Signal Recordings of Drones (Vuorenmaa et al.) | Drones: DJI Inspire 2 (2.44 and 5.8 GHz), DJI Matrice 100 (2.44 GHz), DJI Matrice 210 (2.44 and 5.8 GHz), DJI Mavic Mini (2.44 GHz), DJI Mavic Pro (2.44 GHz), DJI Phantom 4 (2.44 GHz), DJI Phantom 4 Pro Plus (2.44 and 5.8 GHz), Parrot Disco (2.44 GHz), Parrot Mambo (2.44 GHz), Yuneec Typhoon H (2.44 and 5.7 GHz) | I/Q Data (And Video data) | TODO: not clear yet | | https://zenodo.org/records/4264467 | | | +| Spectrogram Dataset (Wicht et al.) | Wi-Fi and Bluetooth signals (NOT DRONES) | Sepctrograms | | | https://www.mdpi.com/2306-5729/7/12/168 | | | + + +## Current Proposal for ML +![Diagram ML](./Diagram_ML.svg) diff --git a/platformio.ini b/platformio.ini index 4e79c64..5ff09ab 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,6 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] +default_envs = heltec_wifi_lora_32_V3 ; for env:vision-master-e190 ; src_dir = tft_src ; for env:vision-master-e290 diff --git a/src/main.cpp b/src/main.cpp index f83e37b..a7704e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,7 +25,7 @@ #include -// #define OSD_ENABLED true +#define OSD_ENABLED true // #define WIFI_SCANNING_ENABLED true // #define BT_SCANNING_ENABLED true @@ -71,58 +71,6 @@ uint64_t bt_start = 0; #include "DFRobot_OSD.h" #define OSD_SIDE_BAR true -static constexpr uint16_t levels[10] = { - 0x105, // 0 - 0x10E, // 1 - 0x10D, // 2 - 0x10C, // 3 - 0x10B, // 4 - 0x10A, // 5 - 0x109, // 6 - 0x108, // 7 - 0x107, // 8 - 0x106, // 9 -}; - -static constexpr uint16_t power_level[MAX_POWER_LEVELS + 1] = { - 0x10E, // 0 - 0x10E, // 1 - 0x10D, // 2 - 0x10C, // 3 - 0x10B, // 4 - 0x10A, // 5 - 0x109, // 6 - 0x108, // 7 - 0x107, // 8 - 0x106, // 9 not using 106 to accent rise - // new line - 0x10E, // 10 - 0x10D, // 11 - 0x10C, // 12 - 0x10B, // 13 - 0x10A, // 14 - 0x109, // 15 - 0x108, // 16 - 0x107, // 17 - 0x106, // 18 not using 106 - // new line - 0x10E, // 19 - 0x10D, // 20 - 0x10C, // 21 - 0x10B, // 22 - 0x10A, // 23 - 0x109, // 24 - 0x108, // 25 - 0x107, // 26 - 0x106, // 27 - 0x105, // 28 --- - 0x105, // 29 - 0x105, // 30 - 0x105, // 31 - 0x105, // 32 - 0x105 // 33 -}; - // SPI pins #define OSD_CS 47 #define OSD_MISO 33 @@ -147,11 +95,6 @@ int global_counter = 0; DFRobot_OSD osd(OSD_CS); #endif -/*Define Custom characters Example*/ -static const int buf0[36] = {0x02, 0x80, 0x02, 0x40, 0x7F, 0xE0, 0x42, 0x00, - 0x42, 0x00, 0x7A, 0x40, 0x4A, 0x40, 0x4A, 0x80, - 0x49, 0x20, 0x5A, 0xA0, 0x44, 0x60, 0x88, 0x20}; - #include "global_config.h" #include "ui.h" @@ -212,8 +155,6 @@ constexpr int WINDOW_SIZE = 15; // Number of samples for each frequency scan. Fewer samples = better temporal resolution. // if more than 100 it can freeze #define SAMPLES 35 //(scan time = 1294) -// number of samples for RSSI method -#define SAMPLES_RSSI 12 // 21 // #define RANGE (int)(FREQ_END - FREQ_BEGIN) @@ -232,6 +173,7 @@ uint64_t median_frequency = FREQ_BEGIN + FREQ_END - FREQ_BEGIN / 2; // Array to store the scan results uint16_t result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; +uint16_t result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; bool filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; @@ -831,6 +773,8 @@ int max_rssi_x = 999; RadioScan r; +RadioScan r; + void loop(void) { UI_displayDecorate(0, 0, false); // some default values @@ -919,6 +863,7 @@ void loop(void) // horizontal (x axis) Frequency loop osd_x = 1, osd_y = 2, col = 0, max_bin = 0; + int radio_error_count = 0; // x loop for (x = 0; x < STEPS * SCAN_RBW_FACTOR; x++) {