Added interference display to waterfall. Improved Heltec V4 false interference rejection.

This commit is contained in:
Mark Qvist 2025-11-22 14:19:23 +01:00
parent 9ea2a589cb
commit 7f868c6c28
4 changed files with 33 additions and 10 deletions

View file

@ -417,6 +417,8 @@
const int pin_tcxo_enable = -1;
#define HAS_BUSY true
#define DIO2_AS_RF_SWITCH true
#define LNA_GD_THRSHLD (-109)
#define LNA_GD_LIMIT (-89)
#define LORA_LNA_GAIN 17
#define LORA_LNA_GVT 12

View file

@ -151,7 +151,7 @@
uint8_t model = 0x00;
uint8_t hwrev = 0x00;
#define NOISE_FLOOR_SAMPLES 64
#define NOISE_FLOOR_SAMPLES 128
int noise_floor = -292;
int current_rssi = -292;
int last_rssi = -292;

View file

@ -152,6 +152,7 @@ bool device_firmware_ok();
#define WATERFALL_SIZE 46
int waterfall[WATERFALL_SIZE];
int waterfall_meta[WATERFALL_SIZE];
int waterfall_head = 0;
int p_ad_x = 0;
@ -722,6 +723,9 @@ void draw_signal_bars(int px, int py) {
#define WF_RSSI_MIN -135
#define WF_RSSI_SPAN (WF_RSSI_MAX-WF_RSSI_MIN)
#define WF_PIXEL_WIDTH 10
#define WF_M_RX 0x00
#define WF_M_TX 0x01
#define WF_M_NTFR 0x02
void draw_waterfall(int px, int py) {
int rssi_val = current_rssi;
if (rssi_val < WF_RSSI_MIN) rssi_val = WF_RSSI_MIN;
@ -729,11 +733,14 @@ void draw_waterfall(int px, int py) {
int rssi_normalised = ((rssi_val - WF_RSSI_MIN)*(1.0/WF_RSSI_SPAN))*WF_PIXEL_WIDTH;
if (display_tx) {
for (uint8_t i = 0; i < WF_TX_SIZE; i++) {
waterfall_meta[waterfall_head] = WF_M_TX;
waterfall[waterfall_head++] = -1;
if (waterfall_head >= WATERFALL_SIZE) waterfall_head = 0;
}
display_tx = false;
} else {
if (interference_detected) { waterfall_meta[waterfall_head] = WF_M_NTFR; }
else { waterfall_meta[waterfall_head] = WF_M_RX; }
waterfall[waterfall_head++] = rssi_normalised;
if (waterfall_head >= WATERFALL_SIZE) waterfall_head = 0;
}
@ -742,8 +749,13 @@ void draw_waterfall(int px, int py) {
for (int i = 0; i < WATERFALL_SIZE; i++){
int wi = (waterfall_head+i)%WATERFALL_SIZE;
int ws = waterfall[wi];
int wm = waterfall_meta[wi];
if (ws > 0) {
stat_area.drawLine(px, py+i, px+ws-1, py+i, SSD1306_WHITE);
if (wm == WF_M_RX) { stat_area.drawLine(px, py+i, px+ws-1, py+i, SSD1306_WHITE); }
else if (wm == WF_M_NTFR) {
uint8_t o = 0;
for (uint8_t ti = 0; ti < WF_PIXEL_WIDTH/2; ti++) { stat_area.drawPixel(px+ti*2+o, py+i, SSD1306_WHITE); }
}
} else if (ws == -1) {
uint8_t o = i%2;
for (uint8_t ti = 0; ti < WF_PIXEL_WIDTH/2; ti++) {

View file

@ -1358,20 +1358,26 @@ int noise_floor_buffer[NOISE_FLOOR_SAMPLES] = {0};
void update_noise_floor() {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (!dcd) {
#if BOARD_MODEL != BOARD_HELTEC32_V4
if (!noise_floor_sampled || current_rssi < noise_floor + CSMA_INFR_THRESHOLD_DB) {
#else
if ((!noise_floor_sampled || current_rssi < noise_floor + CSMA_INFR_THRESHOLD_DB) || (noise_floor_sampled && (noise_floor < LNA_GD_THRSHLD && current_rssi <= LNA_GD_LIMIT))) {
#endif
#if HAS_LORA_LNA
// Discard invalid samples due to gain variance
// during LoRa LNA re-calibration
if (current_rssi < noise_floor-LORA_LNA_GVT) { return; }
#endif
bool sum_noise_floor = false;
noise_floor_buffer[noise_floor_sample] = current_rssi;
noise_floor_sample = noise_floor_sample+1;
if (noise_floor_sample >= NOISE_FLOOR_SAMPLES) {
noise_floor_sample %= NOISE_FLOOR_SAMPLES;
noise_floor_sampled = true;
sum_noise_floor = true;
}
if (noise_floor_sampled) {
if (noise_floor_sampled && sum_noise_floor) {
noise_floor = 0;
for (int ni = 0; ni < NOISE_FLOOR_SAMPLES; ni++) { noise_floor += noise_floor_buffer[ni]; }
noise_floor /= NOISE_FLOOR_SAMPLES;
@ -1402,7 +1408,13 @@ void update_modem_status() {
portEXIT_CRITICAL();
#endif
interference_detected = !carrier_detected && (current_rssi > (noise_floor+CSMA_INFR_THRESHOLD_DB));
#if BOARD_MODEL == BOARD_HELTEC32_V4
if (noise_floor > LNA_GD_THRSHLD) { interference_detected = !carrier_detected && (current_rssi > (noise_floor+CSMA_INFR_THRESHOLD_DB)); }
else { interference_detected = !carrier_detected && (current_rssi > LNA_GD_LIMIT); }
#else
interference_detected = !carrier_detected && (current_rssi > (noise_floor+CSMA_INFR_THRESHOLD_DB));
#endif
if (interference_detected) { if (led_id_filter < LED_ID_TRIG) { led_id_filter += 1; } }
else { if (led_id_filter > 0) {led_id_filter -= 1; } }
@ -1410,14 +1422,11 @@ void update_modem_status() {
// LNA recalibration, antenna swap, moving into new RF
// environment or similar.
if (interference_detected && current_rssi < CSMA_RFENV_RECAL_LIMIT_DB) {
if (!interference_persists) {
interference_persists = true; interference_start = millis();
} else {
if (!interference_persists) { interference_persists = true; interference_start = millis(); }
else {
if (millis()-interference_start >= CSMA_RFENV_RECAL_MS) { noise_floor_sampled = false; interference_persists = false; }
}
} else {
interference_persists = false;
}
} else { interference_persists = false; }
if (carrier_detected) { dcd = true; } else { dcd = false; }