Skip to content

Commit e73ec08

Browse files
CapnBrySunjunKim
andauthored
SNR-based dynamic power system, refactor to new unit (ExpressLRS#1529)
* Use SNR for dynpower inc/dec instead of RSSI/LQ * Raise dynpower threshold, expected SNR bump per inc * Add per-rate minimum SNR * Increase power after a bit on missing TLM * TX's LQ tracks 25 packets now not 10 -- It uses the same amount of code and ram so why not? * Fix signedness/unused compiler warnings * Document dynamic_power_updated better * Update thresholds from Sunjun * Dynamic power refactored to its own unit * Use calculated linkstats interval, MovingAvg class * Reorder variables * Return of RSSI-based dynpower * Add SnrDn threshold, rename constants * Use signed int for powerHeadroom * Start dynamic power high if armed, instead of low * Fix going above max power after a boost event * powerHeadroom back to uint8 * Adjust SNR thresholds, add LQ_THRESH_DN to RSSI-based * Raise (lower?) 200Hz up/dn limit * I wrote the same bug twice! * Update the thresholds for 2.4g 150 and 50 Hz * SNR Multiplier * Revert "Update the thresholds for 2.4g 150 and 50 Hz" This reverts commit baccda3. * Revert "SNR Multiplier" This reverts commit 35500f7. * preserving the raw snr precision * Error fix * Descale SNR for linkstats, add SNR_SCALE macros * Add DYNPOWER_LQ_THRESH_UP * DEBUG_RCVR_LINKSTATS gets full precision SNR * Move linkstats code * Fix power overflow on +power (lq) * downlink_SNR / RSSI update on any telemetry packet * Shorten some DP var names * Fix Adv.Telem preventing +power(tlm) * If Adv.Telem is coming im fine, but no linkstats is, could prevent +power(tlm) from ever activating because the AT would keep resetting the timer. * Fix bug waiting for next telem after a missed telem to update * Raise UP thresholds +1, DN +0.5 to account for rounding Except Team900 200Hz/100HzFull, which keeps 3.0 instead of going up to 3.5 * Remove unused commented code * Try to prevent another ExpressLRS#1292/1293 Co-authored-by: Sunjun Kim <[email protected]>
1 parent f0a72e4 commit e73ec08

12 files changed

Lines changed: 327 additions & 165 deletions

File tree

src/include/common.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,22 @@ enum {
9999
RADIO_TYPE_SX128x_FLRC,
100100
};
101101

102+
// Value used for expresslrs_rf_pref_params_s.DynpowerUpThresholdSnr if SNR should not be used
103+
#define DYNPOWER_SNR_THRESH_NONE -127
104+
102105
typedef struct expresslrs_rf_pref_params_s
103106
{
104107
uint8_t index;
105108
expresslrs_RFrates_e enum_rate;
106-
int16_t RXsensitivity; // expected RF sensitivity based on
109+
int16_t RXsensitivity; // expected min RF sensitivity
107110
uint16_t TOA; // time on air in microseconds
108111
uint16_t DisconnectTimeoutMs; // Time without a packet before receiver goes to disconnected (ms)
109112
uint16_t RxLockTimeoutMs; // Max time to go from tentative -> connected state on receiver (ms)
110113
uint16_t SyncPktIntervalDisconnected; // how often to send the PACKET_TYPE_SYNC (ms) when there is no response from RX
111114
uint16_t SyncPktIntervalConnected; // how often to send the PACKET_TYPE_SYNC (ms) when there we have a connection
115+
int8_t DynpowerSnrThreshUp; // Request a raise in power if the reported (average) SNR is at or below this
116+
// or DYNPOWER_UPTHRESH_SNR_NONE to use RSSI
117+
int8_t DynpowerSnrThreshDn; // Like DynpowerSnrUpThreshold except to lower power
112118

113119
} expresslrs_rf_pref_params_s;
114120

@@ -158,6 +164,9 @@ extern uint8_t ExpressLRS_currTlmDenom;
158164
extern expresslrs_mod_settings_s *ExpressLRS_currAirRate_Modparams;
159165
extern expresslrs_rf_pref_params_s *ExpressLRS_currAirRate_RFperfParams;
160166

167+
#define SNR_SCALE(snr) ((int8_t)((float)snr * RADIO_SNR_SCALE))
168+
#define SNR_DESCALE(snrScaled) (snrScaled / RADIO_SNR_SCALE)
169+
161170
#endif // UNIT_TEST
162171

163172
uint32_t uidMacSeedGet(void);

src/include/dynpower.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#if defined(TARGET_TX)
2+
3+
#pragma once
4+
5+
#include <stdint.h>
6+
#include <config.h>
7+
#include <POWERMGNT.h>
8+
#include <CRSF.h>
9+
#include <logging.h>
10+
#include <MeanAccumulator.h>
11+
12+
#define DYNPOWER_UPDATE_NOUPDATE -128
13+
#define DYNPOWER_UPDATE_MISSED -127
14+
15+
// Call DynamicPower_Init in setup()
16+
void DynamicPower_Init();
17+
// Call DynamicPower_Update from loop()
18+
void DynamicPower_Update(uint32_t now);
19+
// Call DynamicPower_TelemetryUpdate from ISR with DYNPOWER_UPDATE_MISSED or ScaledSNR value
20+
void DynamicPower_TelemetryUpdate(int8_t snrScaled);
21+
22+
#endif
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#pragma once
2+
3+
template <typename StorageType, typename IncrementType, IncrementType NoValueReturn>
4+
class MeanAccumulator
5+
{
6+
public:
7+
void add(IncrementType val)
8+
{
9+
_accumulator += val;
10+
++_count;
11+
}
12+
13+
IncrementType mean()
14+
{
15+
if (_count)
16+
{
17+
IncrementType retVal = _accumulator / _count;
18+
reset();
19+
20+
return retVal;
21+
}
22+
return NoValueReturn;
23+
}
24+
25+
void reset()
26+
{
27+
_accumulator = 0;
28+
_count = 0;
29+
}
30+
31+
size_t getCount() const
32+
{
33+
return _count;
34+
}
35+
36+
private:
37+
StorageType _accumulator;
38+
StorageType _count;
39+
};

src/lib/SX127xDriver/SX127x.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,6 @@ void ICACHE_RAM_ATTR SX127xDriver::RXnbISR()
331331
// In Rx Single mode, the device will return to Standby mode as soon as the interrupt occurs
332332
currOpmode = SX127x_OPMODE_STANDBY;
333333
}
334-
// https://www.mouser.com/datasheet/2/761/sx1276-1278113.pdf
335-
// page 87 (note we already do /4 in GetLastPacketSNR())
336-
int8_t negOffset = (LastPacketSNR < 0) ? LastPacketSNR : 0;
337-
LastPacketRSSI += negOffset;
338334
RXdoneCallback(SX12XX_RX_OK);
339335
}
340336

@@ -361,7 +357,11 @@ void ICACHE_RAM_ATTR SX127xDriver::RXnb()
361357
void ICACHE_RAM_ATTR SX127xDriver::GetLastPacketStats()
362358
{
363359
LastPacketRSSI = GetLastPacketRSSI();
364-
LastPacketSNR = GetLastPacketSNR();
360+
LastPacketSNRRaw = GetLastPacketSNRRaw();
361+
// https://www.mouser.com/datasheet/2/761/sx1276-1278113.pdf
362+
// Section 3.5.5 (page 87)
363+
int8_t negOffset = (LastPacketSNRRaw < 0) ? (LastPacketSNRRaw / RADIO_SNR_SCALE) : 0;
364+
LastPacketRSSI += negOffset;
365365
}
366366

367367
void ICACHE_RAM_ATTR SX127xDriver::SetMode(SX127x_RadioOPmodes mode)
@@ -500,10 +500,9 @@ int8_t ICACHE_RAM_ATTR SX127xDriver::GetCurrRSSI()
500500
return (-157 + hal.getRegValue(SX127X_REG_RSSI_VALUE));
501501
}
502502

503-
int8_t ICACHE_RAM_ATTR SX127xDriver::GetLastPacketSNR()
503+
int8_t ICACHE_RAM_ATTR SX127xDriver::GetLastPacketSNRRaw()
504504
{
505-
int8_t rawSNR = (int8_t)hal.getRegValue(SX127X_REG_PKT_SNR_VALUE);
506-
return (rawSNR / 4);
505+
return (int8_t)hal.getRegValue(SX127X_REG_PKT_SNR_VALUE);;
507506
}
508507

509508
uint8_t ICACHE_RAM_ATTR SX127xDriver::GetIrqFlags()

src/lib/SX127xDriver/SX127x.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <cstdint>
99
#endif
1010

11+
#define RADIO_SNR_SCALE 4
12+
1113
class SX127xDriver: public SX12xxDriverCommon
1214
{
1315

@@ -63,7 +65,7 @@ class SX127xDriver: public SX12xxDriverCommon
6365

6466
uint8_t UnsignedGetLastPacketRSSI();
6567
int8_t GetLastPacketRSSI();
66-
int8_t GetLastPacketSNR();
68+
int8_t GetLastPacketSNRRaw();
6769
int8_t GetCurrRSSI();
6870
void GetLastPacketStats();
6971

src/lib/SX1280Driver/SX1280.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -506,15 +506,15 @@ void ICACHE_RAM_ATTR SX1280Driver::GetLastPacketStats()
506506
if (packet_mode == SX1280_PACKET_TYPE_FLRC) {
507507
// No SNR in FLRC mode
508508
LastPacketRSSI = -(int8_t)(status[1] / 2);
509-
LastPacketSNR = 0;
509+
LastPacketSNRRaw = 0;
510510
return;
511511
}
512512
// LoRa mode has both RSSI and SNR
513513
LastPacketRSSI = -(int8_t)(status[0] / 2);
514-
LastPacketSNR = (int8_t)status[1] / 4;
515-
// https://www.mouser.com/datasheet/2/761/DS_SX1280-1_V2.2-1511144.pdf
514+
LastPacketSNRRaw = (int8_t)status[1];
515+
// https://www.mouser.com/datasheet/2/761/DS_SX1280-1_V2.2-1511144.pdf p84
516516
// need to subtract SNR from RSSI when SNR <= 0;
517-
int8_t negOffset = (LastPacketSNR < 0) ? LastPacketSNR : 0;
517+
int8_t negOffset = (LastPacketSNRRaw < 0) ? (LastPacketSNRRaw / RADIO_SNR_SCALE) : 0;
518518
LastPacketRSSI += negOffset;
519519
}
520520

src/lib/SX1280Driver/SX1280.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "SX1280_hal.h"
66
#include "SX12xxDriverCommon.h"
77

8+
#define RADIO_SNR_SCALE 4 // Units for LastPacketSNRRaw
89

910
class SX1280Driver: public SX12xxDriverCommon
1011
{
@@ -32,7 +33,7 @@ class SX1280Driver: public SX12xxDriverCommon
3233

3334

3435
bool GetFrequencyErrorbool();
35-
bool FrequencyErrorAvailable() const { return modeSupportsFei && (LastPacketSNR > 0); }
36+
bool FrequencyErrorAvailable() const { return modeSupportsFei && (LastPacketSNRRaw > 0); }
3637

3738
void TXnb(uint8_t * data, uint8_t size);
3839
void RXnb();

src/lib/SX12xxDriverCommon/SX12xxDriverCommon.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class SX12xxDriverCommon
3636

3737
/////////////Packet Stats//////////
3838
int8_t LastPacketRSSI;
39-
int8_t LastPacketSNR;
39+
int8_t LastPacketSNRRaw; // in RADIO_SNR_SCALE units
4040

4141
protected:
4242
void RemoveCallbacks(void)

src/src/common.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ expresslrs_mod_settings_s ExpressLRS_AirRateConfig[RATE_MAX] = {
1919
{4, RADIO_TYPE_SX127x_LORA, RATE_LORA_25HZ, SX127x_BW_500_00_KHZ, SX127x_SF_9, SX127x_CR_4_7, TLM_RATIO_1_8, 2, 40000, 10, OTA4_PACKET_SIZE, 1}};
2020

2121
expresslrs_rf_pref_params_s ExpressLRS_AirRateRFperf[RATE_MAX] = {
22-
{0, RATE_LORA_200HZ, -112, 4380, 3000, 2500, 600, 5000},
23-
{1, RATE_LORA_100HZ_8CH, -112, 6690, 3500, 2500, 600, 5000},
24-
{2, RATE_LORA_100HZ, -117, 8770, 3500, 2500, 600, 5000},
25-
{3, RATE_LORA_50HZ, -120, 18560, 4000, 2500, 600, 5000},
26-
{4, RATE_LORA_25HZ, -123, 29950, 6000, 4000, 0, 5000}};
22+
{0, RATE_LORA_200HZ, -112, 4380, 3000, 2500, 600, 5000, SNR_SCALE( 1), SNR_SCALE(3.0)},
23+
{1, RATE_LORA_100HZ_8CH, -112, 6690, 3500, 2500, 600, 5000, SNR_SCALE( 1), SNR_SCALE(3.0)},
24+
{2, RATE_LORA_100HZ, -117, 8770, 3500, 2500, 600, 5000, SNR_SCALE( 1), SNR_SCALE(2.5)},
25+
{3, RATE_LORA_50HZ, -120, 18560, 4000, 2500, 600, 5000, SNR_SCALE(-1), SNR_SCALE(1.5)},
26+
{4, RATE_LORA_25HZ, -123, 29950, 6000, 4000, 0, 5000, SNR_SCALE(-3), SNR_SCALE(0.5)}};
2727
#endif
2828

2929
#if defined(RADIO_SX128X)
@@ -44,16 +44,16 @@ expresslrs_mod_settings_s ExpressLRS_AirRateConfig[RATE_MAX] = {
4444
{9, RADIO_TYPE_SX128x_LORA, RATE_LORA_50HZ, SX1280_LORA_BW_0800, SX1280_LORA_SF9, SX1280_LORA_CR_LI_4_6, TLM_RATIO_1_16, 2, 20000, 12, OTA4_PACKET_SIZE, 1}};
4545

4646
expresslrs_rf_pref_params_s ExpressLRS_AirRateRFperf[RATE_MAX] = {
47-
{0, RATE_FLRC_1000HZ, -104, 389, 2500, 2500, 3, 5000},
48-
{1, RATE_FLRC_500HZ, -104, 389, 2500, 2500, 3, 5000},
49-
{2, RATE_DVDA_500HZ, -104, 389, 2500, 2500, 3, 5000},
50-
{3, RATE_DVDA_250HZ, -104, 389, 2500, 2500, 3, 5000},
51-
{4, RATE_LORA_500HZ, -105, 1507, 2500, 2500, 3, 5000},
52-
{5, RATE_LORA_333HZ_8CH, -105, 2374, 2500, 2500, 4, 5000},
53-
{6, RATE_LORA_250HZ, -108, 3300, 3000, 2500, 6, 5000},
54-
{7, RATE_LORA_150HZ, -112, 5871, 3500, 2500, 10, 5000},
55-
{8, RATE_LORA_100HZ_8CH, -112, 7605, 3500, 2500, 11, 5000},
56-
{9, RATE_LORA_50HZ, -117, 18443, 4000, 2500, 0, 5000}};
47+
{0, RATE_FLRC_1000HZ, -104, 389, 2500, 2500, 3, 5000, DYNPOWER_SNR_THRESH_NONE, DYNPOWER_SNR_THRESH_NONE},
48+
{1, RATE_FLRC_500HZ, -104, 389, 2500, 2500, 3, 5000, DYNPOWER_SNR_THRESH_NONE, DYNPOWER_SNR_THRESH_NONE},
49+
{2, RATE_DVDA_500HZ, -104, 389, 2500, 2500, 3, 5000, DYNPOWER_SNR_THRESH_NONE, DYNPOWER_SNR_THRESH_NONE},
50+
{3, RATE_DVDA_250HZ, -104, 389, 2500, 2500, 3, 5000, DYNPOWER_SNR_THRESH_NONE, DYNPOWER_SNR_THRESH_NONE},
51+
{4, RATE_LORA_500HZ, -105, 1507, 2500, 2500, 3, 5000, SNR_SCALE( 5), SNR_SCALE(9.5)},
52+
{5, RATE_LORA_333HZ_8CH, -105, 2374, 2500, 2500, 4, 5000, SNR_SCALE( 5), SNR_SCALE(9.5)},
53+
{6, RATE_LORA_250HZ, -108, 3300, 3000, 2500, 6, 5000, SNR_SCALE( 3), SNR_SCALE(9.5)},
54+
{7, RATE_LORA_150HZ, -112, 5871, 3500, 2500, 10, 5000, SNR_SCALE( 0), SNR_SCALE(8.5)},
55+
{8, RATE_LORA_100HZ_8CH, -112, 7605, 3500, 2500, 11, 5000, SNR_SCALE( 0), SNR_SCALE(8.5)},
56+
{9, RATE_LORA_50HZ, -117, 18443, 4000, 2500, 0, 5000, SNR_SCALE(-1), SNR_SCALE(6.5)}};
5757
#endif
5858

5959
expresslrs_mod_settings_s *get_elrs_airRateConfig(uint8_t index)

0 commit comments

Comments
 (0)