Change in osmo-trx[master]: LMSDevice: Compute TxGain on LimeSuite API based on expected Tx outpu...

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/.

pespin gerrit-no-reply at lists.osmocom.org
Fri Jun 19 16:14:58 UTC 2020


pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-trx/+/18918 )


Change subject: LMSDevice: Compute TxGain on LimeSuite API based on expected Tx output power
......................................................................

LMSDevice: Compute TxGain on LimeSuite API based on expected Tx output power

Right now, according to a few measurements taken on LimeMicro devices, we
expect the Tx Gain at UHD level to relate 1:1 with the slope in Tx output
power given a specific band.

If more fine-grained results are wanted or some device doesn't follow a
1:1 slope relationship, functions TxGain2TxPower and TxPower2TxGain need
to be adapted/improved.

This patch is basically doing the same thing as was done previously for
UHDDevice in 992c9bd1cea410e2dd42ce7566299104b5648aff.

Related: OS#4583
Change-Id: If154fe4d4cd118aa30ea43c22ee7119117b77da6
---
M Transceiver52M/device/lms/LMSDevice.cpp
M Transceiver52M/device/lms/LMSDevice.h
2 files changed, 144 insertions(+), 51 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-trx refs/changes/18/18918/1

diff --git a/Transceiver52M/device/lms/LMSDevice.cpp b/Transceiver52M/device/lms/LMSDevice.cpp
index 355c8e4..8bb5316 100644
--- a/Transceiver52M/device/lms/LMSDevice.cpp
+++ b/Transceiver52M/device/lms/LMSDevice.cpp
@@ -65,8 +65,6 @@
 	 * LimeNET-Micro does not like selecting internal clock
 	 */
 	bool clock_src_int_usable;
-	/* Device specific maximum tx levels selected by phasenoise measurements, in dB */
-	double max_tx_gain;
 	/* Sample rate coef (without having TX/RX samples per symbol into account) */
 	double rate;
 	/* Sample rate coef (without having TX/RX samples per symbol into account), if multi-arfcn is enabled */
@@ -80,12 +78,48 @@
 };
 
 static const std::map<enum lms_dev_type, struct dev_desc> dev_param_map {
-	{ LMS_DEV_SDR_USB,   { true,  true,  73.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_SDR_USB_PREFIX_NAME } },
-	{ LMS_DEV_SDR_MINI,  { false, true,  66.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 8.2e-5, LMS_DEV_SDR_MINI_PREFIX_NAME } },
-	{ LMS_DEV_NET_MICRO, { true,  false, 71.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_NET_MICRO_PREFIX_NAME } },
-	{ LMS_DEV_UNKNOWN,   { true,  true,  73.0, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, "UNKNOWN" } },
+	{ LMS_DEV_SDR_USB,   { true,  true,  GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_SDR_USB_PREFIX_NAME } },
+	{ LMS_DEV_SDR_MINI,  { false, true,  GSMRATE, MCBTS_SPACING, 8.9e-5, 8.2e-5, LMS_DEV_SDR_MINI_PREFIX_NAME } },
+	{ LMS_DEV_NET_MICRO, { true,  false, GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, LMS_DEV_NET_MICRO_PREFIX_NAME } },
+	{ LMS_DEV_UNKNOWN,   { true,  true,  GSMRATE, MCBTS_SPACING, 8.9e-5, 7.9e-5, "UNKNOWN" } },
 };
 
+typedef std::tuple<lms_dev_type, enum gsm_band> dev_band_key;
+/* Maximum LimeSuite Tx Gain which can be set/used without distorting the output
+ * signal, and the resulting real output power measured when that gain is used.
+ */
+struct dev_band_desc {
+	double nom_lms_tx_gain;  /* dB */
+	double nom_out_tx_power; /* dBm */
+};
+typedef std::map<dev_band_key, dev_band_desc>::const_iterator dev_band_map_it;
+static const std::map<dev_band_key, dev_band_desc> dev_band_nom_power_param_map {
+	{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_850),	{ 73.0, 11.2 } },
+	{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_900),	{ 73.0, 10.8 } },
+	{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_1800),	{ 65.0, -3.5 } }, /* FIXME: OS#4583: 1800Mhz is failing above TxGain=65, which is around -3.5dBm (already < 0 dBm) */
+	{ std::make_tuple(LMS_DEV_SDR_USB, GSM_BAND_1900),	{ 73.0, 1.7 } }, /* FIXME: OS#4583: 1900MHz is failing in all TxGain values */
+	{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_850),	{ 66.0, 3.1 } }, /* FIXME: OS#4583: Ensure BAND2 is used at startup */
+	{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_900),	{ 66.0, 2.8 } }, /* FIXME: OS#4583: Ensure BAND2 is used at startup */
+	{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_1800),	{ 66.0, -11.6 } }, /* OS#4583: Any of BAND1 or BAND2 is fine */
+	{ std::make_tuple(LMS_DEV_SDR_MINI, GSM_BAND_1900),	{ 66.0, -9.2 } }, /* FIXME: OS#4583: Ensure BAND1 is used at startup */
+	{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_850),	{ 71.0, 6.8 } },
+	{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_900),	{ 71.0, 6.8 } },
+	{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_1800),	{ 65.0, -10.5 } }, /* OS#4583: TxGain=71 (-4.4dBm) FAIL rms phase errors ~10° */
+	{ std::make_tuple(LMS_DEV_NET_MICRO, GSM_BAND_1900),	{ 71.0, -6.3 } }, /* FIXME: OS#4583: all FAIL, BAND1/BAND2 rms phase errors >23° */
+};
+
+/* So far measurements done for B210 show really close to linear relationship
+ * between gain and real output power, so we simply adjust the measured offset
+ */
+static double TxGain2TxPower(const dev_band_desc &desc, double tx_gain_db)
+{
+	return desc.nom_out_tx_power - (desc.nom_lms_tx_gain - tx_gain_db);
+}
+static double TxPower2TxGain(const dev_band_desc &desc, double tx_power_dbm)
+{
+	return desc.nom_lms_tx_gain - (desc.nom_out_tx_power - tx_power_dbm);
+}
+
 static enum lms_dev_type parse_dev_type(lms_device_t *m_lms_dev)
 {
 	std::map<enum lms_dev_type, struct dev_desc>::const_iterator it = dev_param_map.begin();
@@ -110,7 +144,7 @@
 		     const std::vector<std::string>& tx_paths,
 		     const std::vector<std::string>& rx_paths):
 	RadioDevice(tx_sps, rx_sps, iface, chan_num, lo_offset, tx_paths, rx_paths),
-	m_lms_dev(NULL), started(false), m_dev_type(LMS_DEV_UNKNOWN)
+	m_lms_dev(NULL), started(false), band((enum gsm_band)0), m_dev_type(LMS_DEV_UNKNOWN)
 {
 	LOGC(DDEV, INFO) << "creating LMS device...";
 
@@ -197,6 +231,27 @@
 	return -1;
 }
 
+void LMSDevice::get_dev_band_desc(dev_band_desc& desc)
+{
+	dev_band_map_it it;
+	enum gsm_band req_band = band;
+
+	if (req_band == 0) {
+		LOGC(DDEV, ERROR) << "Nominal Tx Power requested before Tx Frequency was set! Providing band 900 by default... ";
+		req_band = GSM_BAND_900;
+	}
+	it = dev_band_nom_power_param_map.find(dev_band_key(m_dev_type, req_band));
+	if (it == dev_band_nom_power_param_map.end()) {
+		dev_desc desc = dev_param_map.at(m_dev_type);
+		LOGC(DDEV, ERROR) << "No Tx Power measurements exist for device "
+				    << desc.name_prefix << " on band " << gsm_band_name(req_band)
+				    << ", using LimeSDR-USB ones as fallback";
+		it = dev_band_nom_power_param_map.find(dev_band_key(LMS_DEV_SDR_USB, req_band));
+	}
+	OSMO_ASSERT(it != dev_band_nom_power_param_map.end())
+	desc = it->second;
+}
+
 int LMSDevice::open(const std::string &args, int ref, bool swap_channels)
 {
 	lms_info_str_t* info_list;
@@ -322,17 +377,20 @@
 	LOGC(DDEV, INFO) << "starting LMS...";
 
 	unsigned int i;
+	dev_band_desc desc;
 
 	if (started) {
 		LOGC(DDEV, ERR) << "Device already started";
 		return false;
 	}
 
+	get_dev_band_desc(desc);
+
 	/* configure the channels/streams */
 	for (i=0; i<chans; i++) {
 		/* Set gains for calibration/filter setup */
 		/* TX gain to maximum */
-		setTxGain(maxTxGain(), i);
+		LMS_SetGaindB(m_lms_dev, LMS_CH_TX, i, TxPower2TxGain(desc, desc.nom_out_tx_power));
 		/* RX gain to midpoint */
 		setRxGain((minRxGain() + maxRxGain()) / 2, i);
 
@@ -477,17 +535,6 @@
 	return true;
 }
 
-
-double LMSDevice::maxTxGain()
-{
-	return dev_param_map.at(m_dev_type).max_tx_gain;
-}
-
-double LMSDevice::minTxGain()
-{
-	return 0.0;
-}
-
 double LMSDevice::maxRxGain()
 {
 	return 73.0;
@@ -498,22 +545,6 @@
 	return 0.0;
 }
 
-double LMSDevice::setTxGain(double dB, size_t chan)
-{
-	if (dB > maxTxGain())
-		dB = maxTxGain();
-	if (dB < minTxGain())
-		dB = minTxGain();
-
-	LOGCHAN(chan, DDEV, NOTICE) << "Setting TX gain to " << dB << " dB";
-
-	if (LMS_SetGaindB(m_lms_dev, LMS_CH_TX, chan, dB) < 0)
-		LOGCHAN(chan, DDEV, ERR) << "Error setting TX gain to " << dB << " dB";
-	else
-		tx_gains[chan] = dB;
-	return tx_gains[chan];
-}
-
 double LMSDevice::setRxGain(double dB, size_t chan)
 {
 	if (dB > maxRxGain())
@@ -530,12 +561,45 @@
 	return rx_gains[chan];
 }
 
+double LMSDevice::setPowerAttenuation(int atten, size_t chan)
+{
+	double dB;
+	dev_band_desc desc;
+
+	if (chan >= tx_gains.size()) {
+		LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
+		return 0.0f;
+	}
+
+	get_dev_band_desc(desc);
+	dB = TxPower2TxGain(desc, desc.nom_out_tx_power - atten);
+
+	LOGCHAN(chan, DDEV, NOTICE) << "Setting TX gain to " << dB << " dB";
+
+	if (LMS_SetGaindB(m_lms_dev, LMS_CH_TX, chan, dB) < 0)
+		LOGCHAN(chan, DDEV, ERR) << "Error setting TX gain to " << dB << " dB";
+	else
+		tx_gains[chan] = dB;
+	return desc.nom_out_tx_power - TxGain2TxPower(desc, tx_gains[chan]);
+}
+
+double LMSDevice::getPowerAttenuation(size_t chan) {
+	dev_band_desc desc;
+	if (chan >= tx_gains.size()) {
+		LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
+		return 0.0f;
+	}
+
+	get_dev_band_desc(desc);
+	return desc.nom_out_tx_power - TxGain2TxPower(desc, tx_gains[chan]);
+}
+
 int LMSDevice::getNominalTxPower(size_t chan)
 {
-	/* TODO: return value based on some experimentally generated table depending on
-	 * band/arfcn, which is known here thanks to TXTUNE
-	 */
-	return 23;
+	dev_band_desc desc;
+	get_dev_band_desc(desc);
+
+	return desc.nom_out_tx_power;
 }
 
 void LMSDevice::log_ant_list(bool dir_tx, size_t chan, std::ostringstream& os)
@@ -904,13 +968,39 @@
 
 bool LMSDevice::setTxFreq(double wFreq, size_t chan)
 {
+	uint16_t req_arfcn;
+	enum gsm_band req_band;
+
+	if (chan >= chans) {
+		LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
+		return false;
+	}
+
 	LOGCHAN(chan, DDEV, NOTICE) << "Setting Tx Freq to " << wFreq << " Hz";
 
+	req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100 , 0);
+	if (req_arfcn == 0xffff) {
+		LOGCHAN(chan, DDEV, ALERT) << "Unknown ARFCN for Tx Frequency " << wFreq / 1000 << " kHz";
+		return false;
+	}
+	if (gsm_arfcn2band_rc(req_arfcn, &req_band) < 0) {
+		LOGCHAN(chan, DDEV, ALERT) << "Unknown GSM band for Tx Frequency " << wFreq
+					   << " Hz (ARFCN " << req_arfcn << " )";
+		return false;
+	}
+
+	if (band != 0 && req_band != band) {
+		LOGCHAN(chan, DDEV, ALERT) << "Requesting Tx Frequency " << wFreq
+					   << " Hz different from previous band " << gsm_band_name(band);
+		return false;
+	}
+
 	if (LMS_SetLOFrequency(m_lms_dev, LMS_CH_TX, chan, wFreq) < 0) {
 		LOGCHAN(chan, DDEV, ERROR) << "Error setting Tx Freq to " << wFreq << " Hz";
 		return false;
 	}
 
+	band = req_band;
 	return true;
 }
 
diff --git a/Transceiver52M/device/lms/LMSDevice.h b/Transceiver52M/device/lms/LMSDevice.h
index c83fed2..b6a6ab9 100644
--- a/Transceiver52M/device/lms/LMSDevice.h
+++ b/Transceiver52M/device/lms/LMSDevice.h
@@ -32,6 +32,10 @@
 #include <iostream>
 #include <lime/LimeSuite.h>
 
+extern "C" {
+#include <osmocom/gsm/gsm_utils.h>
+}
+
 /* Definition of LIMESDR_TX_AMPL limits maximum amplitude of I and Q
  * channels separately. Hence LIMESDR_TX_AMPL value must be 1/sqrt(2) =
  * 0.7071.... to get an amplitude of 1 of the complex signal:
@@ -48,6 +52,8 @@
 	LMS_DEV_UNKNOWN,
 };
 
+struct dev_band_desc;
+
 /** A class to handle a LimeSuite supported device */
 class LMSDevice:public RadioDevice {
 
@@ -66,6 +72,7 @@
 	TIMESTAMP ts_initial, ts_offset;
 
 	std::vector<double> tx_gains, rx_gains;
+	enum gsm_band band;
 
 	enum lms_dev_type m_dev_type;
 
@@ -77,19 +84,11 @@
 	void update_stream_stats_rx(size_t chan, bool *overrun);
 	void update_stream_stats_tx(size_t chan, bool *underrun);
 	bool do_clock_src_freq(enum ReferenceType ref, double freq);
-	/** sets the transmit chan gain, returns the gain setting **/
-	double setTxGain(double dB, size_t chan = 0);
+	void get_dev_band_desc(dev_band_desc& desc);
 
-	/** get transmit gain */
-	double getTxGain(size_t chan = 0) {
-		return tx_gains[chan];
-	}
-
-	/** return maximum Tx Gain **/
-	double maxTxGain(void);
-
-	/** return minimum Rx Gain **/
-	double minTxGain(void);
+	double setTxGain(double db, size_t chan) {OSMO_ASSERT(false); return 0.0f; }
+	double getTxGain(size_t chan = 0) { OSMO_ASSERT(false); return 0.0f; };
+	double maxTxGain(void) { OSMO_ASSERT(false); return 0.0f; };
 
 public:
 
@@ -178,6 +177,10 @@
 	/** return minimum Rx Gain **/
 	double minRxGain(void);
 
+
+	double setPowerAttenuation(int atten, size_t chan);
+	double getPowerAttenuation(size_t chan = 0);
+
 	int getNominalTxPower(size_t chan = 0);
 
 	/** sets the RX path to use, returns true if successful and false otherwise */

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

Gerrit-Project: osmo-trx
Gerrit-Branch: master
Gerrit-Change-Id: If154fe4d4cd118aa30ea43c22ee7119117b77da6
Gerrit-Change-Number: 18918
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200619/e2b1ef93/attachment.htm>


More information about the gerrit-log mailing list