MS/BS Power Control Loop: Do RxLEV meas avg & delta calculations directly on RxLevels

Before this comits, averaging and delta calculation was done in RSSI,
but stored the averaging cached state in variables named "rxlev", which
was really confusing. Let's keeping averaging and delta calculations
based on RxLevels.

Some of the tests change results due to test passing RSSI -45, which is
an invalid Rxlev (only up to -47 is supported).
Others fail due to an unrelated bug showing up now. Basically the averaging algo
is doing rounding  the wrong way when downscaling the values. It will be
fixed in a follow-up commit.

Change-Id: I4cff8394f22b5d47789163051364ff594b2bcd74
This commit is contained in:
Pau Espin 2021-09-02 20:36:26 +02:00
parent e2f9abee58
commit aac12bfd67
4 changed files with 49 additions and 57 deletions

View File

@ -113,22 +113,18 @@ static int do_avg_algo(const struct gsm_power_ctrl_meas_params *mp,
* to be applied to the current Tx power level to approach the target level. */
static int calc_delta_rxlev(const struct gsm_power_ctrl_params *params,
struct lchan_power_ctrl_state *state,
const int rxlev_dbm_avg)
const uint8_t rxlev)
{
uint8_t rxlev_avg;
int delta;
/* FIXME: avoid this conversion, accept RxLev as-is */
rxlev_avg = dbm2rxlev(rxlev_dbm_avg);
/* Check if RxLev is within the threshold window */
if (rxlev_avg >= params->rxlev_meas.lower_thresh &&
rxlev_avg <= params->rxlev_meas.upper_thresh)
if (rxlev >= params->rxlev_meas.lower_thresh &&
rxlev <= params->rxlev_meas.upper_thresh)
return 0;
/* How many dBs measured power should be increased (+) or decreased (-)
* to reach expected power. */
delta = CALC_TARGET(params->rxlev_meas) - rxlev_avg;
delta = CALC_TARGET(params->rxlev_meas) - rxlev;
/* Don't ever change more than PWR_{LOWER,RAISE}_MAX_DBM during one loop
* iteration, i.e. reduce the speed at which the MS transmit power can
@ -183,7 +179,7 @@ int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,
enum gsm_band band = bts->band;
int8_t new_power_lvl; /* TS 05.05 power level */
int8_t ms_dbm, new_dbm, current_dbm, bsc_max_dbm;
int8_t ul_rssi_dbm_avg;
uint8_t rxlev_avg;
int16_t ul_lqual_cb_avg;
const struct gsm_power_ctrl_meas_params *ci_meas;
@ -221,14 +217,14 @@ int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,
/* If computed C/I is out of acceptable thresholds: */
ci_meas = lchan_get_ci_thresholds(lchan);
ul_lqual_cb_avg = do_avg_algo(ci_meas, &state->ci_meas_proc, ul_lqual_cb);
ul_rssi_dbm_avg = do_avg_algo(&params->rxlev_meas, &state->rxlev_meas_proc, ul_rssi_dbm);
rxlev_avg = do_avg_algo(&params->rxlev_meas, &state->rxlev_meas_proc, dbm2rxlev(ul_rssi_dbm));
if (ul_lqual_cb_avg < ci_meas->lower_thresh * 10) {
new_dbm = ms_dbm + params->inc_step_size_db;
} else if (ul_lqual_cb_avg > ci_meas->upper_thresh * 10) {
new_dbm = ms_dbm - params->red_step_size_db;
} else {
/* Calculate the new Tx power value (in dBm) */
new_dbm = ms_dbm + calc_delta_rxlev(params, state, ul_rssi_dbm_avg);
new_dbm = ms_dbm + calc_delta_rxlev(params, state, rxlev_avg);
}
/* Make sure new_dbm is never negative. ms_pwr_ctl_lvl() can later on
@ -252,7 +248,7 @@ int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,
LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping MS power at control level %d (%d dBm): "
"ms-pwr-lvl[curr %" PRIu8 ", max %" PRIu8 "], RSSI[curr %d, avg %d, thresh %d..%d] dBm,"
" C/I[curr %d, avg %d, thresh %d..%d] dB\n",
new_power_lvl, new_dbm, ms_power_lvl, state->max, ul_rssi_dbm, ul_rssi_dbm_avg,
new_power_lvl, new_dbm, ms_power_lvl, state->max, ul_rssi_dbm, rxlev2dbm(rxlev_avg),
rxlev2dbm(params->rxlev_meas.lower_thresh), rxlev2dbm(params->rxlev_meas.upper_thresh),
ul_lqual_cb/10, ul_lqual_cb_avg/10, ci_meas->lower_thresh, ci_meas->upper_thresh);
return 0;
@ -264,7 +260,7 @@ int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,
" C/I[curr %d, avg %d, thresh %d..%d] dB\n",
(new_dbm > current_dbm) ? "Raising" : "Lowering",
state->current, current_dbm, new_power_lvl, new_dbm, ms_power_lvl,
state->max, ul_rssi_dbm, ul_rssi_dbm_avg,
state->max, ul_rssi_dbm, rxlev2dbm(rxlev_avg),
rxlev2dbm(params->rxlev_meas.lower_thresh), rxlev2dbm(params->rxlev_meas.upper_thresh),
ul_lqual_cb/10, ul_lqual_cb_avg/10, ci_meas->lower_thresh, ci_meas->upper_thresh);
@ -286,8 +282,7 @@ int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,
const struct gsm_power_ctrl_params *params = state->dpc_params;
uint8_t rxqual_full, rxqual_sub;
uint8_t rxlev_full, rxlev_sub;
uint8_t rxqual, rxqual_avg, rxlev;
int8_t dl_rssi_dbm, dl_rssi_dbm_avg;
uint8_t rxqual, rxqual_avg, rxlev, rxlev_avg;
int new_att;
/* Check if dynamic BS Power Control is enabled */
@ -341,8 +336,7 @@ int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,
rxlev = rxlev_full;
}
dl_rssi_dbm = rxlev2dbm(rxlev);
dl_rssi_dbm_avg = do_avg_algo(&params->rxlev_meas, &state->rxlev_meas_proc, dl_rssi_dbm);
rxlev_avg = do_avg_algo(&params->rxlev_meas, &state->rxlev_meas_proc, rxlev);
rxqual_avg = do_avg_algo(&params->rxqual_meas, &state->rxqual_meas_proc, rxqual);
/* If RxQual > L_RXQUAL_XX_P, try to increase Tx power */
if (rxqual_avg > params->rxqual_meas.lower_thresh) {
@ -365,7 +359,7 @@ int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,
* RxLev + Delta = TxPwr - PathLoss - TxAtt + Delta
* RxLev + Delta = TxPwr - PathLoss - (TxAtt - Delta)
*/
new_att = state->current - calc_delta_rxlev(params, state, dl_rssi_dbm_avg);
new_att = state->current - calc_delta_rxlev(params, state, rxlev_avg);
}
/* Make sure new TxAtt is never negative: */
@ -380,7 +374,7 @@ int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,
LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping DL attenuation at %u dB: "
"max %u dB, RSSI[curr %d, avg %d, thresh %d..%d] dBm, "
"RxQual[curr %d, avg %d, thresh %d..%d]\n",
state->current, state->max, dl_rssi_dbm, dl_rssi_dbm_avg,
state->current, state->max, rxlev2dbm(rxlev), rxlev2dbm(rxlev_avg),
rxlev2dbm(params->rxlev_meas.lower_thresh), rxlev2dbm(params->rxlev_meas.upper_thresh),
rxqual, rxqual_avg, params->rxqual_meas.lower_thresh, params->rxqual_meas.upper_thresh);
return 0;
@ -390,7 +384,7 @@ int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,
"max %u dB, RSSI[curr %d, avg %d, thresh %d..%d] dBm, "
"RxQual[curr %d, avg %d, thresh %d..%d]\n",
(new_att > state->current) ? "Raising" : "Lowering",
state->current, new_att, state->max, dl_rssi_dbm, dl_rssi_dbm_avg,
state->current, new_att, state->max, rxlev2dbm(rxlev), rxlev2dbm(rxlev_avg),
rxlev2dbm(params->rxlev_meas.lower_thresh), rxlev2dbm(params->rxlev_meas.upper_thresh),
rxqual, rxqual_avg, params->rxqual_meas.lower_thresh, params->rxqual_meas.upper_thresh);
state->current = new_att;

View File

@ -185,32 +185,30 @@ static void test_pf_algo_ewma(void)
lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 26);
OSMO_ASSERT(lchan->ms_power_ctrl.max == 2);
#define CHECK_UL_RSSI_AVG100(exp) \
printf("\tAvg[t] is %2.2f dBm (expected %2.2f dBm)\n", \
#define CHECK_RXLEV_AVG100(exp) \
printf("\tAvg[t] is RxLev %2.2f (expected %2.2f)\n", \
((float) *avg100) / 100, exp);
/* UL RSSI remains constant => no UL power change */
apply_power_test(lchan, -75, good_lqual, 0, 15);
CHECK_UL_RSSI_AVG100(-75.00);
CHECK_RXLEV_AVG100((float)dbm2rxlev(-75)); /* RXLEV 35 */
/* Avg[t] = (0.2 * -90) + (0.8 * -75) = -78.0 dBm */
apply_power_test(lchan, -90, good_lqual, 1, 13);
CHECK_UL_RSSI_AVG100(-78.00);
/* Avg[t] = (0.2 * 20) + (0.8 * 35) = RXLEV 32, (-78 dBm) */
apply_power_test(lchan, -90, good_lqual, 1, 13); /* -90 dBm = RXLEV 20 */
CHECK_RXLEV_AVG100(32.00);
/* Avg[t] = (0.2 * -90) + (0.8 * -78) = -80.4 dBm */
apply_power_test(lchan, -90, good_lqual, 1, 11);
CHECK_UL_RSSI_AVG100(-80.40);
/* Avg[t] = (0.2 * 20) + (0.8 * 32) = RXLEV 29.6 (-80.4 dBm) */
apply_power_test(lchan, -90, good_lqual, 1, 11); /* -90 dBm = RXLEV 20 */
CHECK_RXLEV_AVG100(29.60);
/* Avg[t] = (0.2 * -70) + (0.8 * -80.4) = -78.32 dBm,
/* Avg[t] = (0.2 * 40) + (0.8 * 29.60) = RXLEV 31.68 (-78.32 dBm),
* but due to up-/down-scaling artefacts we get the following:
* Avg100[t] = Avg100[t - 1] + A * (Pwr - Avg[t] / 100)
* Avg100[t] = -8040 + 20 * (-70 - (-8040 / 100))
* Avg100[t] = -8040 + 20 * (-70 - (-8040 / 100))
* Avg100[t] = -8040 + 20 * (-70 + 80)
* Avg100[t] = -8040 + 200 = -7840
* Avg[t] = -7840 / 100 = -78.4 */
apply_power_test(lchan, -70, good_lqual, 1, 9);
CHECK_UL_RSSI_AVG100(-78.40);
* Avg100[t] = 2960 + 20 * (40 - (2960 / 100))
* Avg100[t] = 2960 + 20 * (40 - 29)
* Avg[t] = 3180 / 100 = 31.80 */
apply_power_test(lchan, -70, good_lqual, 1, 9); /* RXLEV 40 */
CHECK_RXLEV_AVG100(31.80);
mp->ewma.alpha = 70; /* 30% smoothing */
lchan->ms_power_ctrl.current = 15;
@ -218,17 +216,17 @@ static void test_pf_algo_ewma(void)
(struct gsm_power_ctrl_meas_proc_state) { 0 };
/* This is the first sample, the filter outputs it as-is */
apply_power_test(lchan, -50, good_lqual, 0, 15);
CHECK_UL_RSSI_AVG100(-50.00);
apply_power_test(lchan, -50, good_lqual, 0, 15); /* RXLEV 60 */
CHECK_RXLEV_AVG100((float)dbm2rxlev(-50));
/* Avg[t] = (0.7 * -50) + (0.3 * -50) = -50.0 dBm */
/* Avg[t] = (0.7 * 60) + (0.3 * 60) = RXLEV 60 (-50.0 dBm) */
apply_power_test(lchan, -50, good_lqual, 0, 15);
CHECK_UL_RSSI_AVG100(-50.0);
CHECK_RXLEV_AVG100((float)dbm2rxlev(-50));
/* Simulate SACCH block loss (-110 dBm):
* Avg[t] = (0.7 * -110) + (0.3 * -50) = -92.0 dBm */
apply_power_test(lchan, -110, good_lqual, 1, 13);
CHECK_UL_RSSI_AVG100(-92.0);
* Avg[t] = (0.7 * 0) + (0.3 * 60) = RXLEV 18.0 (-92.0 dBm) */
apply_power_test(lchan, -110, good_lqual, 1, 13); /* RXLEV 0 */
CHECK_RXLEV_AVG100(18.0);
}
static void test_power_hysteresis(void)

View File

@ -14,17 +14,17 @@
(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 30 (34 dBm) => 29 (36 dBm): ms-pwr-lvl[curr 30, max 29], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 29 (36 dBm): ms-pwr-lvl[curr 29, max 29], RSSI[curr -90, avg -90, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 29 (36 dBm): ms-pwr-lvl[curr 29, max 29], RSSI[curr -75, avg -75, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 29 (36 dBm) => 30 (34 dBm): ms-pwr-lvl[curr 29, max 29], RSSI[curr -45, avg -45, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 30 (34 dBm) => 31 (32 dBm): ms-pwr-lvl[curr 30, max 29], RSSI[curr -45, avg -45, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 31 (32 dBm) => 0 (30 dBm): ms-pwr-lvl[curr 31, max 29], RSSI[curr -45, avg -45, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 29 (36 dBm) => 30 (34 dBm): ms-pwr-lvl[curr 29, max 29], RSSI[curr -45, avg -47, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 30 (34 dBm) => 31 (32 dBm): ms-pwr-lvl[curr 30, max 29], RSSI[curr -45, avg -47, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 31 (32 dBm) => 0 (30 dBm): ms-pwr-lvl[curr 31, max 29], RSSI[curr -45, avg -47, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 0 (30 dBm) => 1 (28 dBm): ms-pwr-lvl[curr 0, max 29], RSSI[curr -73, avg -73, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 1 (28 dBm) => 0 (30 dBm): ms-pwr-lvl[curr 1, max 29], RSSI[curr -77, avg -77, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 0 (30 dBm) => 14 (2 dBm): ms-pwr-lvl[curr 0, max 14], RSSI[curr -73, avg -73, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 14 (2 dBm) => 15 (0 dBm): ms-pwr-lvl[curr 14, max 0], RSSI[curr -40, avg -40, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Lowering MS power control level 14 (2 dBm) => 15 (0 dBm): ms-pwr-lvl[curr 14, max 0], RSSI[curr -40, avg -47, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -75, avg -75, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 15 (0 dBm) => 13 (3 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -90, avg -78, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 13 (4 dBm) => 11 (8 dBm): ms-pwr-lvl[curr 13, max 2], RSSI[curr -90, avg -80, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 11 (8 dBm) => 9 (11 dBm): ms-pwr-lvl[curr 11, max 2], RSSI[curr -70, avg -78, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 13 (4 dBm) => 11 (8 dBm): ms-pwr-lvl[curr 13, max 2], RSSI[curr -90, avg -81, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 11 (8 dBm) => 9 (12 dBm): ms-pwr-lvl[curr 11, max 2], RSSI[curr -70, avg -79, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -50, avg -50, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Keeping MS power at control level 15 (0 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -50, avg -50, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB
(bts=0,trx=0,ts=0,ss=0) Raising MS power control level 15 (0 dBm) => 13 (4 dBm): ms-pwr-lvl[curr 15, max 2], RSSI[curr -110, avg -92, thresh -75..-75] dBm, C/I[curr 14, avg 14, thresh 12..16] dB

View File

@ -53,25 +53,25 @@ lchan_ms_pwr_ctrl(RxLvl=-40 dBm) returns 1 (expected 1)
Starting test case 'test_pf_algo_ewma'
lchan_ms_pwr_ctrl(RxLvl=-75 dBm) returns 0 (expected 0)
MS current power 15 -> 15 (expected 15)
Avg[t] is -75.00 dBm (expected -75.00 dBm)
Avg[t] is RxLev 35.00 (expected 35.00)
lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
MS current power 15 -> 13 (expected 13)
Avg[t] is -78.00 dBm (expected -78.00 dBm)
Avg[t] is RxLev 32.00 (expected 32.00)
lchan_ms_pwr_ctrl(RxLvl=-90 dBm) returns 1 (expected 1)
MS current power 13 -> 11 (expected 11)
Avg[t] is -80.40 dBm (expected -80.40 dBm)
Avg[t] is RxLev 29.60 (expected 29.60)
lchan_ms_pwr_ctrl(RxLvl=-70 dBm) returns 1 (expected 1)
MS current power 11 -> 9 (expected 9)
Avg[t] is -78.40 dBm (expected -78.40 dBm)
Avg[t] is RxLev 31.80 (expected 31.80)
lchan_ms_pwr_ctrl(RxLvl=-50 dBm) returns 0 (expected 0)
MS current power 15 -> 15 (expected 15)
Avg[t] is -50.00 dBm (expected -50.00 dBm)
Avg[t] is RxLev 60.00 (expected 60.00)
lchan_ms_pwr_ctrl(RxLvl=-50 dBm) returns 0 (expected 0)
MS current power 15 -> 15 (expected 15)
Avg[t] is -50.00 dBm (expected -50.00 dBm)
Avg[t] is RxLev 60.00 (expected 60.00)
lchan_ms_pwr_ctrl(RxLvl=-110 dBm) returns 1 (expected 1)
MS current power 15 -> 13 (expected 13)
Avg[t] is -92.00 dBm (expected -92.00 dBm)
Avg[t] is RxLev 18.00 (expected 18.00)
Starting test case 'test_power_hysteresis'
lchan_ms_pwr_ctrl(RxLvl=-75 dBm) returns 0 (expected 0)