Change in osmo-bts[master]: power_control: migrate MS/BS control loops to the new params

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

laforge gerrit-no-reply at lists.osmocom.org
Mon Jan 11 13:56:46 UTC 2021


laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bts/+/21993 )

Change subject: power_control: migrate MS/BS control loops to the new params
......................................................................

power_control: migrate MS/BS control loops to the new params

In change [1] the new power control structures and default params
were introduced.  In change [2], the existing VTY commands for MS
power control in the BTS were deprecated and changed to use the
new structures as storage.  Finally, in change [3], handling of
the power control parameters on the A-bis/RSL was implemented.

This change is the final logical step in the mentioned chain: it
makes both MS/BS power control loops use the new parameters, and
removes the old structures.  The actual implementation of both
power control loops remains the same, however the expected output
of some unit tests for the Downlink loop needs to be changed:

  - TC_fixed_mode: disabling dynamic power control becomes a separate
    step of the test script since the field 'fixed' is removed;

  - TC_rxlev_target: RxLev thresholds are printed 'as-is'.

Not all of the new parameters are used by the power control loops
yet.  Further improvements to be done in the follow up commits.

[1] I6d41eb238aa6d4f5b77596c5477c2ecbe86de2a8
[2] Icbd9a7d31ce6723294130a31a179a002fccb4612
[3] I5a901eca5a78a0335a6954064e602e65cda85390

Change-Id: Ib18f84c40227841d95a36063a6789bf63054fc2e
Related: SYS#4918
---
M include/osmo-bts/bts.h
M include/osmo-bts/gsm_data.h
M src/common/bts.c
M src/common/power_control.c
M src/common/rsl.c
M src/common/vty.c
M src/osmo-bts-lc15/oml.c
M src/osmo-bts-oc2g/oml.c
M src/osmo-bts-sysmo/oml.c
M src/osmo-bts-sysmo/sysmobts_vty.c
M src/osmo-bts-trx/trx_vty.c
M tests/power/bs_power_loop_test.c
M tests/power/bs_power_loop_test.ok
M tests/power/ms_power_loop_test.c
14 files changed, 181 insertions(+), 153 deletions(-)

Approvals:
  Jenkins Builder: Verified
  pespin: Looks good to me, but someone else must approve
  laforge: Looks good to me, approved



diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h
index 0b224be..f6389ad 100644
--- a/include/osmo-bts/bts.h
+++ b/include/osmo-bts/bts.h
@@ -321,10 +321,6 @@
 		bool vty_override;	/* OML value overridden by VTY */
 	} radio_link_timeout;
 
-	/* Uplink/Downlink power control (legacy parameters) */
-	struct bts_power_ctrl_params ul_power_ctrl;
-	struct bts_power_ctrl_params dl_power_ctrl;
-
 	/* Default (fall-back) Dynamic Power Control parameters for all transceivers */
 	struct gsm_power_ctrl_params bs_dpc_params; /* BS Dynamic Power Control */
 	struct gsm_power_ctrl_params ms_dpc_params; /* MS Dynamic Power Control */
diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h
index b9e0e88..6efc717 100644
--- a/include/osmo-bts/gsm_data.h
+++ b/include/osmo-bts/gsm_data.h
@@ -222,7 +222,6 @@
 	 * (attenuation, in dB). */
 	uint8_t current;
 	uint8_t max;
-	bool fixed;
 
 	/* Scaled up (100 times) average UL/DL RxLev (in dBm) */
 	int avg100_rxlev_dbm;
diff --git a/src/common/bts.c b/src/common/bts.c
index de07957..06a5ccb 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -330,22 +330,6 @@
 	bts->rtp_port_range_next = bts->rtp_port_range_start;
 	bts->rtp_ip_dscp = -1;
 
-	/* Default UL/DL power control parameters (legacy) */
-	bts->ul_power_ctrl = bts->dl_power_ctrl = \
-	(struct bts_power_ctrl_params) {
-		.target_dbm = -75,
-		.hysteresis_db = 3,	/* -78 .. -72 dBm */
-		.raise_step_max_db = PWR_RAISE_MAX_DB,
-		.lower_step_max_db = PWR_LOWER_MAX_DB,
-		.pf_algo = BTS_PF_ALGO_EWMA,
-		.pf = {
-			.ewma = {
-				/* 50% smoothing */
-				.alpha = 50
-			}
-		}
-	};
-
 	/* Default (fall-back) MS/BS Power control parameters */
 	bts->bs_dpc_params = power_ctrl_params_def;
 	bts->ms_dpc_params = power_ctrl_params_def;
diff --git a/src/common/power_control.c b/src/common/power_control.c
index a616f18..e159740 100644
--- a/src/common/power_control.c
+++ b/src/common/power_control.c
@@ -70,11 +70,11 @@
  *   https://en.wikipedia.org/wiki/Low-pass_filter#Simple_infinite_impulse_response_filter
  *   https://tomroelandts.com/articles/low-pass-single-pole-iir-filter
  */
-static int8_t do_pf_ewma(const struct bts_power_ctrl_params *params,
+static int8_t do_pf_ewma(const struct gsm_power_ctrl_meas_params *mp,
 			 struct lchan_power_ctrl_state *state,
 			 const int8_t Pwr)
 {
-	const uint8_t A = params->pf.ewma.alpha;
+	const uint8_t A = mp->ewma.alpha;
 	int *Avg100 = &state->avg100_rxlev_dbm;
 
 	/* We don't have 'Avg[n - 1]' if this is the first run */
@@ -87,41 +87,51 @@
 	return *Avg100 / EWMA_SCALE_FACTOR;
 }
 
+/* Calculate target RxLev value from lower/upper thresholds */
+#define CALC_TARGET(mp) \
+	(mp.lower_thresh + mp.upper_thresh) / 2
+
 /* Calculate a 'delta' value (for the given MS/BS power control state and parameters)
  * to be applied to the current Tx power level to approach the target level. */
-static int calc_delta(const struct bts_power_ctrl_params *params,
+static int calc_delta(const struct gsm_power_ctrl_params *params,
 		      struct lchan_power_ctrl_state *state,
 		      const int rxlev_dbm)
 {
 	int rxlev_dbm_avg;
+	uint8_t rxlev_avg;
 	int delta;
 
-	/* Filter input value(s) to reduce unnecessary Tx power oscillations */
-	switch (params->pf_algo) {
-	case BTS_PF_ALGO_EWMA:
-		rxlev_dbm_avg = do_pf_ewma(params, state, rxlev_dbm);
+	/* Filter RxLev value to reduce unnecessary Tx power oscillations */
+	switch (params->rxlev_meas.algo) {
+	case GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA:
+		rxlev_dbm_avg = do_pf_ewma(&params->rxlev_meas, state, rxlev_dbm);
 		break;
-	case BTS_PF_ALGO_NONE:
+	/* TODO: implement other pre-processing methods */
+	case GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE:
 	default:
 		/* No filtering (pass through) */
 		rxlev_dbm_avg = rxlev_dbm;
 	}
 
+	/* 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)
+		return 0;
+
 	/* How many dBs measured power should be increased (+) or decreased (-)
 	 * to reach expected power. */
-	delta = params->target_dbm - rxlev_dbm_avg;
-
-	/* Tolerate small deviations from 'rx-target' */
-	if (abs(delta) <= params->hysteresis_db)
-		return 0;
+	delta = CALC_TARGET(params->rxlev_meas) - rxlev_avg;
 
 	/* 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
 	 * change. A higher value means a lower level (and vice versa) */
-	if (delta > params->raise_step_max_db)
-		delta = params->raise_step_max_db;
-	else if (delta < -params->lower_step_max_db)
-		delta = -params->lower_step_max_db;
+	if (delta > params->inc_step_size_db)
+		delta = params->inc_step_size_db;
+	else if (delta < -params->red_step_size_db)
+		delta = -params->red_step_size_db;
 
 	return delta;
 }
@@ -135,18 +145,17 @@
 		      const uint8_t ms_power_lvl,
 		      const int8_t ul_rssi_dbm)
 {
+	struct lchan_power_ctrl_state *state = &lchan->ms_power_ctrl;
+	const struct gsm_power_ctrl_params *params = state->dpc_params;
 	struct gsm_bts_trx *trx = lchan->ts->trx;
 	struct gsm_bts *bts = trx->bts;
 	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;
 
-	const struct bts_power_ctrl_params *params = &bts->ul_power_ctrl;
-	struct lchan_power_ctrl_state *state = &lchan->ms_power_ctrl;
-
 	if (!trx_ms_pwr_ctrl_is_osmo(trx))
 		return 0;
-	if (state->fixed)
+	if (params == NULL)
 		return 0;
 
 	ms_dbm = ms_pwr_dbm(band, ms_power_lvl);
@@ -184,11 +193,14 @@
 		return 0;
 	}
 
+	/* FIXME: this is only needed for logging, print thresholds instead */
+	int target_dbm = rxlev2dbm(CALC_TARGET(params->rxlev_meas));
+
 	if (state->current == new_power_lvl) {
 		LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping MS power at control level %d, %d dBm "
 			  "(rx-ms-pwr-lvl %" PRIu8 ", max-ms-pwr-lvl %" PRIu8 ", rx-current %d dBm, rx-target %d dBm)\n",
 			  new_power_lvl, new_dbm, ms_power_lvl, state->max,
-			  ul_rssi_dbm, params->target_dbm);
+			  ul_rssi_dbm, target_dbm);
 		return 0;
 	}
 
@@ -197,7 +209,7 @@
 		  "(rx-ms-pwr-lvl %" PRIu8 ", max-ms-pwr-lvl %" PRIu8 ", rx-current %d dBm, rx-target %d dBm)\n",
 		  (new_dbm > current_dbm) ? "Raising" : "Lowering",
 		  state->current, current_dbm, new_power_lvl, new_dbm,
-		  ms_power_lvl, state->max, ul_rssi_dbm, params->target_dbm);
+		  ms_power_lvl, state->max, ul_rssi_dbm, target_dbm);
 
 	/* store the resulting new MS power level in the lchan */
 	state->current = new_power_lvl;
@@ -213,18 +225,15 @@
 int lchan_bs_pwr_ctrl(struct gsm_lchan *lchan,
 		      const struct gsm48_hdr *gh)
 {
-	struct gsm_bts_trx *trx = lchan->ts->trx;
-	struct gsm_bts *bts = trx->bts;
+	struct lchan_power_ctrl_state *state = &lchan->bs_power_ctrl;
+	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, rxlev;
 	int delta, new;
 
-	const struct bts_power_ctrl_params *params = &bts->dl_power_ctrl;
-	struct lchan_power_ctrl_state *state = &lchan->bs_power_ctrl;
-
-	/* Check if BS Power Control is enabled */
-	if (state->fixed)
+	/* Check if dynamic BS Power Control is enabled */
+	if (params == NULL)
 		return 0;
 	/* Check if this is a Measurement Report */
 	if (gh->proto_discr != GSM48_PDISC_RR)
@@ -264,7 +273,7 @@
 	}
 
 	/* Bit Error Rate > 0 => reduce by 2 */
-	if (rxqual > 0) {
+	if (rxqual > 0) { /* FIXME: take RxQual threshold into account */
 		LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Reducing Downlink attenuation "
 			  "by half: %u -> %u dB due to RXQUAL %u > 0\n",
 			  state->current, state->current / 2, rxqual);
@@ -294,16 +303,19 @@
 	if (new < 0)
 		new = 0;
 
+	/* FIXME: this is only needed for logging, print thresholds instead */
+	int target_dbm = rxlev2dbm(CALC_TARGET(params->rxlev_meas));
+
 	if (state->current != new) {
 		LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Changing Downlink attenuation: "
 			  "%u -> %u dB (maximum %u dB, target %d dBm, delta %d dB)\n",
-			  state->current, new, state->max, params->target_dbm, delta);
+			  state->current, new, state->max, target_dbm, delta);
 		state->current = new;
 		return 1;
 	} else {
 		LOGPLCHAN(lchan, DLOOP, LOGL_INFO, "Keeping Downlink attenuation "
 			  "at %u dB (maximum %u dB, target %d dBm, delta %d dB)\n",
-			  state->current, state->max, params->target_dbm, delta);
+			  state->current, state->max, target_dbm, delta);
 		return 0;
 	}
 }
diff --git a/src/common/rsl.c b/src/common/rsl.c
index bca365e..b4df22c 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -1322,14 +1322,12 @@
 	lchan->ms_power_ctrl = (struct lchan_power_ctrl_state) {
 		.max = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, 0),
 		.current = lchan->ms_power_ctrl.max,
-		.fixed = true,
 	};
 
 	/* Initialize BS Power Control defaults */
 	lchan->bs_power_ctrl = (struct lchan_power_ctrl_state) {
 		.max = 2 * 15, /* maximum defined in 9.3.4 */
 		.current = 0,
-		.fixed = true,
 	};
 
 	rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
@@ -1414,7 +1412,6 @@
 		/* Spec explicitly states BTS should only perform
 		* autonomous MS power control loop in BTS if 'MS Power
 		* Parameters' IE is present! */
-		lchan->ms_power_ctrl.fixed = false;
 		lchan->ms_power_ctrl.dpc_params = params;
 	}
 
@@ -1433,7 +1430,6 @@
 
 		/* NOTE: it's safer to start from 0 */
 		lchan->bs_power_ctrl.current = 0;
-		lchan->bs_power_ctrl.fixed = false;
 		lchan->bs_power_ctrl.dpc_params = params;
 	}
 
@@ -1925,7 +1921,6 @@
 
 	/* Spec explicitly states BTS should only perform autonomous MS Power
 	 * control loop in BTS if 'MS Power Parameters' IE is present! */
-	lchan->ms_power_ctrl.fixed = !TLVP_PRESENT(&tp, RSL_IE_MS_POWER_PARAM);
 	lchan->ms_power_ctrl.dpc_params = NULL;
 
 	/* 9.3.31 (TLV) MS Power Parameters IE (vendor specific) */
@@ -1946,7 +1941,7 @@
 
 	/* Only set current to max if actual value of current
 	   in dBm > value in dBm from max, or if fixed. */
-	if (lchan->ms_power_ctrl.fixed) {
+	if (lchan->ms_power_ctrl.dpc_params == NULL) {
 		lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max;
 	} else {
 		max_pwr = ms_pwr_dbm(bts->band, lchan->ms_power_ctrl.max);
@@ -2005,12 +2000,10 @@
 		/* NOTE: it's safer to start from 0 */
 		lchan->bs_power_ctrl.current = 0;
 		lchan->bs_power_ctrl.max = new;
-		lchan->bs_power_ctrl.fixed = false;
 		lchan->bs_power_ctrl.dpc_params = params;
 	} else {
 		lchan->bs_power_ctrl.dpc_params = NULL;
 		lchan->bs_power_ctrl.current = new;
-		lchan->bs_power_ctrl.fixed = true;
 	}
 
 	if (lchan->bs_power_ctrl.current != old) {
diff --git a/src/common/vty.c b/src/common/vty.c
index 1c3b496..689ae58 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -1489,13 +1489,12 @@
 	const struct lchan_power_ctrl_state *st = &lchan->bs_power_ctrl;
 	const struct gsm_bts_trx *trx = lchan->ts->trx;
 
-	cfg_out(vty, "BS (Downlink) Power Control (%s):%s",
-		st->fixed ? "fixed" : "autonomous",
-		VTY_NEWLINE);
+	cfg_out(vty, "BS (Downlink) Power Control (%s mode):%s",
+		st->dpc_params ? "dynamic" : "static", VTY_NEWLINE);
 	indent += 2;
 
 	cfg_out(vty, "Channel reduction: %u dB", st->current);
-	if (!st->fixed)
+	if (st->dpc_params != NULL)
 		vty_out(vty, " (max %u dB)", st->max);
 	vty_out(vty, "%s", VTY_NEWLINE);
 
@@ -1520,8 +1519,7 @@
 	const struct gsm_bts_trx *trx = lchan->ts->trx;
 
 	cfg_out(vty, "MS (Uplink) Power Control (%s):%s",
-		st->fixed ? "fixed" : "autonomous",
-		VTY_NEWLINE);
+		st->dpc_params ? "dynamic" : "static", VTY_NEWLINE);
 	indent += 2;
 
 	int current_dbm = ms_pwr_dbm(trx->bts->band, st->current);
@@ -1529,7 +1527,7 @@
 
 	cfg_out(vty, "Current power level: %u, -%d dBm",
 		st->current, current_dbm);
-	if (!st->fixed)
+	if (st->dpc_params != NULL)
 		vty_out(vty, " (max %u, -%d dBm)", st->max, max_dbm);
 	vty_out(vty, "%s", VTY_NEWLINE);
 
diff --git a/src/osmo-bts-lc15/oml.c b/src/osmo-bts-lc15/oml.c
index 4c71790..44139cf 100644
--- a/src/osmo-bts-lc15/oml.c
+++ b/src/osmo-bts-lc15/oml.c
@@ -433,8 +433,15 @@
 	dev_par->u16Arfcn = trx->arfcn;
 	dev_par->u16BcchArfcn = trx->bts->c0->arfcn;
 	dev_par->u8NbTsc = trx->bts->bsic & 7;
-	dev_par->fRxPowerLevel = trx_ms_pwr_ctrl_is_osmo(trx)
-					? 0.0 : trx->bts->ul_power_ctrl.target_dbm;
+
+	if (!trx_ms_pwr_ctrl_is_osmo(trx)) {
+		/* Target is in the middle between lower and upper RxLev thresholds */
+		int lower_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.lower_thresh);
+		int upper_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.upper_thresh);
+		dev_par->fRxPowerLevel = (float) (lower_dbm + upper_dbm) / 2;
+	} else {
+		dev_par->fRxPowerLevel = 0.0;
+	}
 
 	dev_par->fTxPowerLevel = 0.0;
 	LOGP(DL1C, LOGL_NOTICE, "Init TRX (Band %d, ARFCN %u, TSC %u, RxPower % 2f dBm, "
diff --git a/src/osmo-bts-oc2g/oml.c b/src/osmo-bts-oc2g/oml.c
index b62e61c..ced6ad1 100644
--- a/src/osmo-bts-oc2g/oml.c
+++ b/src/osmo-bts-oc2g/oml.c
@@ -448,8 +448,15 @@
 	dev_par->u16Arfcn = trx->arfcn;
 	dev_par->u16BcchArfcn = trx->bts->c0->arfcn;
 	dev_par->u8NbTsc = trx->bts->bsic & 7;
-	dev_par->fRxPowerLevel = trx_ms_pwr_ctrl_is_osmo(trx)
-					? 0.0 : trx->bts->ul_power_ctrl.target_dbm;
+
+	if (!trx_ms_pwr_ctrl_is_osmo(trx)) {
+		/* Target is in the middle between lower and upper RxLev thresholds */
+		int lower_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.lower_thresh);
+		int upper_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.upper_thresh);
+		dev_par->fRxPowerLevel = (float) (lower_dbm + upper_dbm) / 2;
+	} else {
+		dev_par->fRxPowerLevel = 0.0;
+	}
 
 	dev_par->fTxPowerLevel = 0.0;
 	LOGP(DL1C, LOGL_NOTICE, "Init TRX (Band %d, ARFCN %u, TSC %u, RxPower % 2f dBm, "
diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c
index b79f731..8e38c60 100644
--- a/src/osmo-bts-sysmo/oml.c
+++ b/src/osmo-bts-sysmo/oml.c
@@ -428,8 +428,15 @@
 	dev_par->u16Arfcn = trx->arfcn;
 	dev_par->u16BcchArfcn = trx->bts->c0->arfcn;
 	dev_par->u8NbTsc = trx->bts->bsic & 7;
-	dev_par->fRxPowerLevel = trx_ms_pwr_ctrl_is_osmo(trx)
-					? 0.0 : trx->bts->ul_power_ctrl.target_dbm;
+
+	if (!trx_ms_pwr_ctrl_is_osmo(trx)) {
+		/* Target is in the middle between lower and upper RxLev thresholds */
+		int lower_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.lower_thresh);
+		int upper_dbm = rxlev2dbm(trx->ms_dpc_params->rxlev_meas.upper_thresh);
+		dev_par->fRxPowerLevel = (float) (lower_dbm + upper_dbm) / 2;
+	} else {
+		dev_par->fRxPowerLevel = 0.0;
+	}
 
 	dev_par->fTxPowerLevel = ((float) initial_mdBm) / 1000;
 	LOGP(DL1C, LOGL_NOTICE, "Init TRX (ARFCN %u, TSC %u, RxPower % 2f dBm, "
diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c
index 65edbf0..a8e7401 100644
--- a/src/osmo-bts-sysmo/sysmobts_vty.c
+++ b/src/osmo-bts-sysmo/sysmobts_vty.c
@@ -152,9 +152,20 @@
 	"Obsolete alias for bts uplink-power-target\n"
 	"Target uplink Rx level in dBm\n")
 {
+	struct gsm_power_ctrl_meas_params *mp;
 	struct gsm_bts_trx *trx = vty->index;
+	int rxlev_dbm = atoi(argv[0]);
 
-	trx->bts->ul_power_ctrl.target_dbm = atoi(argv[0]);
+	mp = &trx->bts->ms_dpc_params.rxlev_meas;
+	mp->lower_thresh = mp->upper_thresh = dbm2rxlev(rxlev_dbm);
+
+	vty_out(vty, "%% Command '%s' has been deprecated.%s"
+		"%% MS/BS Power control parameters should be configured in osmo-bsc: "
+		"use 'rxlev-thresh lower %u upper %u'.%s",
+		self->string, VTY_NEWLINE,
+		mp->lower_thresh,
+		mp->upper_thresh,
+		VTY_NEWLINE);
 
 	return CMD_SUCCESS;
 }
diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c
index 49403d4..8e701ea 100644
--- a/src/osmo-bts-trx/trx_vty.c
+++ b/src/osmo-bts-trx/trx_vty.c
@@ -199,7 +199,9 @@
 	vty_out(vty, "'%s' is deprecated, MS Power Control is now managed by BSC%s",
 		self->string, VTY_NEWLINE);
 
-	g_bts->ul_power_ctrl.target_dbm = atoi(argv[0]);
+	uint8_t rxlev = dbm2rxlev(atoi(argv[0]));
+	g_bts->ms_dpc_params.rxlev_meas.lower_thresh = rxlev;
+	g_bts->ms_dpc_params.rxlev_meas.upper_thresh = rxlev;
 
 	return CMD_SUCCESS;
 }
diff --git a/tests/power/bs_power_loop_test.c b/tests/power/bs_power_loop_test.c
index fd93183..ecd83e7 100644
--- a/tests/power/bs_power_loop_test.c
+++ b/tests/power/bs_power_loop_test.c
@@ -31,14 +31,9 @@
 
 #define PWR_TEST_RXLEV_TARGET	30
 
-#define PWR_TEST_CFG_RXLEV_TARGET \
-	.target_dbm = -110 + PWR_TEST_RXLEV_TARGET
-
-/* NOTE: raise/lower values are intentionally swapped here,
- * as it makes more sense in the context of BS Power Control. */
-#define PWR_TEST_CFG_RAISE_LOWER_MAX \
-	.raise_step_max_db = PWR_LOWER_MAX_DB, \
-	.lower_step_max_db = PWR_RAISE_MAX_DB
+#define PWR_TEST_CFG_RXLEV_THRESH(hyst) \
+	.lower_thresh = PWR_TEST_RXLEV_TARGET - hyst, \
+	.upper_thresh = PWR_TEST_RXLEV_TARGET + hyst
 
 #define DL_MEAS_FULL(rxqual, rxlev) \
 	.rxqual_full = rxqual, \
@@ -61,8 +56,9 @@
 	PWR_TEST_ST_IND_MEAS = 0,
 	PWR_TEST_ST_IND_DUMMY,
 	PWR_TEST_ST_SET_STATE,
-	PWR_TEST_ST_SET_PARAMS,
+	PWR_TEST_ST_SET_RXLEV_PARAMS,
 	PWR_TEST_ST_ENABLE_DTXD,
+	PWR_TEST_ST_DISABLE_DPC,
 };
 
 struct power_test_step {
@@ -72,8 +68,8 @@
 	union {
 		/* Power Control state */
 		struct lchan_power_ctrl_state state;
-		/* Power Control parameters */
-		struct bts_power_ctrl_params params;
+		/* Measurement pre-processing parameters */
+		struct gsm_power_ctrl_meas_params mp;
 		/* Indicated DL measurements */
 		struct {
 			uint8_t rxqual_full;
@@ -107,12 +103,6 @@
 	g_bts->band = GSM_BAND_900;
 	g_bts->c0 = g_trx;
 
-	g_bts->dl_power_ctrl = g_bts->ul_power_ctrl = \
-	(struct bts_power_ctrl_params) {
-		PWR_TEST_CFG_RXLEV_TARGET,
-		PWR_TEST_CFG_RAISE_LOWER_MAX,
-	};
-
 	printf("\nStarting test case '%s'\n", name);
 }
 
@@ -157,13 +147,18 @@
 		printf("#%02u %s() <- State (re)set (current %u dB, max %u dB)\n",
 		       n, __func__, step->state.current, step->state.max);
 		lchan->bs_power_ctrl = step->state;
+		lchan->bs_power_ctrl.dpc_params = &lchan->bs_dpc_params;
 		return 0; /* we're done */
-	case PWR_TEST_ST_SET_PARAMS:
-		printf("#%02u %s() <- Param (re)set (target %d dBm, hysteresis %u dB, "
-						    "filtering is %sabled)\n",
-		       n, __func__, step->params.target_dbm, step->params.hysteresis_db,
-		       step->params.pf_algo != BTS_PF_ALGO_NONE ? "en" : "dis");
-		g_bts->dl_power_ctrl = step->params;
+	case PWR_TEST_ST_DISABLE_DPC:
+		printf("#%02u %s() <- Dynamic power control is disabled\n", n, __func__);
+		lchan->bs_power_ctrl.dpc_params = NULL;
+		return 0; /* we're done */
+	case PWR_TEST_ST_SET_RXLEV_PARAMS:
+		printf("#%02u %s() <- (Re)set RxLev params (thresh %u .. %u, "
+							   "averaging is %sabled)\n",
+		       n, __func__, step->mp.lower_thresh, step->mp.upper_thresh,
+		       step->mp.algo != GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE ? "en" : "dis");
+		lchan->bs_dpc_params.rxlev_meas = step->mp;
 		return 0; /* we're done */
 	case PWR_TEST_ST_ENABLE_DTXD:
 		printf("#%02u %s() <- Enable DTXd\n", n, __func__);
@@ -202,6 +197,17 @@
 	init_test(name);
 
 	struct gsm_lchan *lchan = &g_trx->ts[0].lchan[0];
+
+	lchan->bs_dpc_params = (struct gsm_power_ctrl_params) {
+		/* NOTE: raise/lower values are intentionally swapped here,
+		 * as it makes more sense in the context of BS Power Control. */
+		.inc_step_size_db = PWR_LOWER_MAX_DB,
+		.red_step_size_db = PWR_RAISE_MAX_DB,
+
+		/* RxLev pre-processing parameters */
+		.rxlev_meas = { PWR_TEST_CFG_RXLEV_THRESH(0) },
+	};
+
 	for (n = 0; n < num_steps; n++)
 		rc |= exec_power_step(lchan, n, &steps[n]);
 
@@ -212,7 +218,8 @@
 static const struct power_test_step TC_fixed_mode[] = {
 	/* Initial state: 10 dB, up to 20 dB */
 	{ .type = PWR_TEST_ST_SET_STATE,
-	  .state = { .current = 10, .max = 2 * 10, .fixed = true } },
+	  .state = { .current = 10, .max = 2 * 10 } },
+	{ .type = PWR_TEST_ST_DISABLE_DPC },
 
 	/* MS indicates random RxQual/RxLev values, which must be ignored */
 	{ .meas = DL_MEAS_FULL_SUB(0, 63),	.exp_txred = 10 },
@@ -338,12 +345,8 @@
 	{ .meas = DL_MEAS_FULL_SUB(0, PWR_TEST_RXLEV_TARGET - 2),	.exp_txred = 12 },
 
 	/* Enable hysteresis */
-	{ .type = PWR_TEST_ST_SET_PARAMS,
-	  .params = {
-		PWR_TEST_CFG_RXLEV_TARGET,
-		PWR_TEST_CFG_RAISE_LOWER_MAX,
-		.hysteresis_db = 3,
-	  }
+	{ .type = PWR_TEST_ST_SET_RXLEV_PARAMS,
+	  .mp = { PWR_TEST_CFG_RXLEV_THRESH(3) }
 	},
 
 	/* Hysteresis is enabled, so small deviations do not trigger any changes */
@@ -359,13 +362,12 @@
 	{ .type = PWR_TEST_ST_SET_STATE,
 	  .state = { .current = 16, .max = 2 * 15 } },
 
-	/* Enable EWMA based power filtering */
-	{ .type = PWR_TEST_ST_SET_PARAMS,
-	  .params = {
-		PWR_TEST_CFG_RXLEV_TARGET,
-		PWR_TEST_CFG_RAISE_LOWER_MAX,
-		.pf_algo = BTS_PF_ALGO_EWMA,
-		.pf.ewma.alpha = 50,
+	/* Enable EWMA based pre-processing for RxLev */
+	{ .type = PWR_TEST_ST_SET_RXLEV_PARAMS,
+	  .mp = {
+		PWR_TEST_CFG_RXLEV_THRESH(0),
+		.algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA,
+		.ewma.alpha = 50,
 	  }
 	},
 
diff --git a/tests/power/bs_power_loop_test.ok b/tests/power/bs_power_loop_test.ok
index acaad82..814f7e2 100644
--- a/tests/power/bs_power_loop_test.ok
+++ b/tests/power/bs_power_loop_test.ok
@@ -2,21 +2,22 @@
 
 Starting test case 'TC_fixed_mode'
 #00 exec_power_step() <- State (re)set (current 10 dB, max 20 dB)
-#01 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(63), RXQUAL-FULL(0), RXLEV-SUB(63), RXQUAL-SUB(0)
-#01 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3f 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
-#01 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)
-#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(00), RXQUAL-FULL(7), RXLEV-SUB(00), RXQUAL-SUB(7)
-#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 00 00 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 
+#01 exec_power_step() <- Dynamic power control is disabled
+#02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(63), RXQUAL-FULL(0), RXLEV-SUB(63), RXQUAL-SUB(0)
+#02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 3f 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
 #02 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)
-#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
-#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
+#03 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(00), RXQUAL-FULL(7), RXLEV-SUB(00), RXQUAL-SUB(7)
+#03 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 00 00 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 
 #03 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)
-#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(1), RXLEV-SUB(30), RXQUAL-SUB(1)
-#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 12 00 00 00 00 00 00 00 00 00 00 00 00 00 
+#04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
+#04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
 #04 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)
-#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(50), RXQUAL-FULL(1), RXLEV-SUB(50), RXQUAL-SUB(1)
-#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 32 32 12 00 00 00 00 00 00 00 00 00 00 00 00 00 
+#05 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(1), RXLEV-SUB(30), RXQUAL-SUB(1)
+#05 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 12 00 00 00 00 00 00 00 00 00 00 00 00 00 
 #05 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)
+#06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(50), RXQUAL-FULL(1), RXLEV-SUB(50), RXQUAL-SUB(1)
+#06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 32 32 12 00 00 00 00 00 00 00 00 00 00 00 00 00 
+#06 lchan_bs_pwr_ctrl() -> BS power reduction: 10 -> 10 (expected 10)
 Test case verdict: SUCCESS
 
 Starting test case 'TC_rxlev_target'
@@ -175,7 +176,7 @@
 #04 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(28), RXQUAL-FULL(0), RXLEV-SUB(28), RXQUAL-SUB(0)
 #04 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1c 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
 #04 lchan_bs_pwr_ctrl() -> BS power reduction: 14 -> 12 (expected 12)
-#05 exec_power_step() <- Param (re)set (target -80 dBm, hysteresis 3 dB, filtering is disabled)
+#05 exec_power_step() <- (Re)set RxLev params (thresh 27 .. 33, averaging is disabled)
 #06 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(31), RXQUAL-FULL(0), RXLEV-SUB(31), RXQUAL-SUB(0)
 #06 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1f 1f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
 #06 lchan_bs_pwr_ctrl() -> BS power reduction: 12 -> 12 (expected 12)
@@ -192,7 +193,7 @@
 
 Starting test case 'TC_rxlev_pf_ewma'
 #00 exec_power_step() <- State (re)set (current 16 dB, max 30 dB)
-#01 exec_power_step() <- Param (re)set (target -80 dBm, hysteresis 0 dB, filtering is enabled)
+#01 exec_power_step() <- (Re)set RxLev params (thresh 30 .. 30, averaging is enabled)
 #02 enc_meas_rep() -> Measurement Results (valid): RXLEV-FULL(30), RXQUAL-FULL(0), RXLEV-SUB(30), RXQUAL-SUB(0)
 #02 lchan_bs_pwr_ctrl() <- UL SACCH: 06 15 1e 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
 #02 lchan_bs_pwr_ctrl() -> BS power reduction: 16 -> 16 (expected 16)
diff --git a/tests/power/ms_power_loop_test.c b/tests/power/ms_power_loop_test.c
index ea3c249..e93a2ef 100644
--- a/tests/power/ms_power_loop_test.c
+++ b/tests/power/ms_power_loop_test.c
@@ -28,6 +28,10 @@
 
 #include <stdio.h>
 
+#define PWR_TEST_RXLEV_TARGET_DBM	-75
+#define PWR_TEST_RXLEV_TARGET \
+	dbm2rxlev(PWR_TEST_RXLEV_TARGET_DBM)
+
 static struct gsm_bts *g_bts = NULL;
 static struct gsm_bts_trx *g_trx = NULL;
 
@@ -50,12 +54,15 @@
 	g_bts->band = GSM_BAND_1800;
 	g_bts->c0 = g_trx;
 
-	g_bts->ul_power_ctrl = g_bts->dl_power_ctrl = \
-	(struct bts_power_ctrl_params) {
-		.target_dbm = -75,
-		.raise_step_max_db = PWR_RAISE_MAX_DB,
-		.lower_step_max_db = PWR_LOWER_MAX_DB,
-	};
+	/* Init default MS power control parameters, enable dynamic power control */
+	struct gsm_power_ctrl_params *params = &g_trx->ts[0].lchan[0].ms_dpc_params;
+	g_trx->ts[0].lchan[0].ms_power_ctrl.dpc_params = params;
+	*params = power_ctrl_params_def;
+
+	/* Disable RxLev pre-processing and hysteresis by default */
+	struct gsm_power_ctrl_meas_params *mp = &params->rxlev_meas;
+	mp->lower_thresh = mp->upper_thresh = PWR_TEST_RXLEV_TARGET;
+	mp->algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_NONE;
 
 	printf("\nStarting test case '%s'\n", name);
 }
@@ -104,7 +111,7 @@
 	apply_power_test(lchan, -90, 1, 5);
 
 	/* Check good RSSI value keeps it at same power level: */
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm, 0, 5);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, 0, 5);
 
 	apply_power_test(lchan, -90, 1, 3);
 	apply_power_test(lchan, -90, 1, 2); /* .max is pwr lvl 2 */
@@ -122,7 +129,7 @@
 	apply_power_test(lchan, -90, 0, 29);
 
 	/* Check good RSSI value keeps it at same power level: */
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm, 0, 29);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, 0, 29);
 
 	/* Now go down, steps are double size in this direction: */
 	apply_power_test(lchan, -45, 1, 1);
@@ -130,23 +137,23 @@
 	apply_power_test(lchan, -45, 1, 9);
 
 	/* Go down only one level down and up: */
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm + 2, 1, 10);
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm - 2, 1, 9);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 2, 1, 10);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 2, 1, 9);
 
 	/* Check if BSC requesting a low max power is applied after loop calculation: */
 	lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 2);
 	OSMO_ASSERT(lchan->ms_power_ctrl.max == 14);
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm + 2, 1, 14);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 2, 1, 14);
 	/* Set back a more normal max: */
 	lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 30);
 	OSMO_ASSERT(lchan->ms_power_ctrl.max == 0);
 
-	/* Fix it and jump down */
-	lchan->ms_power_ctrl.fixed = true;
+	/* Disable dynamic power control and jump down */
+	lchan->ms_power_ctrl.dpc_params = NULL;
 	apply_power_test(lchan, -60, 0, 14);
 
-	/* And leave it again */
-	lchan->ms_power_ctrl.fixed = false;
+	/* Enable and leave it again */
+	lchan->ms_power_ctrl.dpc_params = &lchan->ms_dpc_params;
 	apply_power_test(lchan, -40, 1, 15);
 }
 
@@ -159,8 +166,9 @@
 	lchan = &g_trx->ts[0].lchan[0];
 	avg100 = &lchan->ms_power_ctrl.avg100_rxlev_dbm;
 
-	g_bts->ul_power_ctrl.pf_algo = BTS_PF_ALGO_EWMA;
-	g_bts->ul_power_ctrl.pf.ewma.alpha = 20; /* 80% smoothing */
+	struct gsm_power_ctrl_meas_params *mp = &lchan->ms_dpc_params.rxlev_meas;
+	mp->algo = GSM_PWR_CTRL_MEAS_AVG_ALGO_OSMO_EWMA;
+	mp->ewma.alpha = 20; /* 80% smoothing */
 
 	lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);
 	OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
@@ -194,7 +202,7 @@
 	apply_power_test(lchan, -70, 1, 9);
 	CHECK_UL_RSSI_AVG100(-78.40);
 
-	g_bts->ul_power_ctrl.pf.ewma.alpha = 70; /* 30% smoothing */
+	mp->ewma.alpha = 70; /* 30% smoothing */
 	lchan->ms_power_ctrl.current = 15;
 	lchan->ms_power_ctrl.avg100_rxlev_dbm = 0;
 
@@ -220,22 +228,23 @@
 	lchan = &g_trx->ts[0].lchan[0];
 
 	/* Tolerate power deviations in range -80 .. -70 */
-	g_bts->ul_power_ctrl.hysteresis_db = 5;
+	lchan->ms_dpc_params.rxlev_meas.lower_thresh = 30;
+	lchan->ms_dpc_params.rxlev_meas.upper_thresh = 40;
 
 	lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);
 	OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
 	lchan->ms_power_ctrl.max = ms_pwr_ctl_lvl(GSM_BAND_1800, 26);
 	OSMO_ASSERT(lchan->ms_power_ctrl.max == 2);
 
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm, 0, 15);
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm + 3, 0, 15);
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm - 3, 0, 15);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, 0, 15);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 3, 0, 15);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 3, 0, 15);
 
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm, 0, 15);
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm + 5, 0, 15);
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm - 5, 0, 15);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM, 0, 15);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM + 5, 0, 15);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 5, 0, 15);
 
-	apply_power_test(lchan, g_bts->ul_power_ctrl.target_dbm - 10, 1, 13);
+	apply_power_test(lchan, PWR_TEST_RXLEV_TARGET_DBM - 10, 1, 13);
 }
 
 int main(int argc, char **argv)

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/21993
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bts
Gerrit-Branch: master
Gerrit-Change-Id: Ib18f84c40227841d95a36063a6789bf63054fc2e
Gerrit-Change-Number: 21993
Gerrit-PatchSet: 2
Gerrit-Owner: fixeria <vyanitskiy at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: pespin <pespin at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210111/abee1983/attachment.htm>


More information about the gerrit-log mailing list