summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandreas128 <Andreas>2017-09-04 20:05:28 +0200
committerandreas128 <Andreas>2017-09-05 09:08:50 +0200
commitb9aab4c9ab542823ec751e32ea7462428d98419c (patch)
tree766d2a1d69cbe4451fc5dd4efead930b6ebd4ea4
parent85ab46bfa7f28530cdd30f2bf3129479e735de7f (diff)
downloaddabmod-b9aab4c9ab542823ec751e32ea7462428d98419c.tar.gz
dabmod-b9aab4c9ab542823ec751e32ea7462428d98419c.tar.bz2
dabmod-b9aab4c9ab542823ec751e32ea7462428d98419c.zip
Add TX_Agc class for TX automatic gain control
-rwxr-xr-xdpd/main.py15
-rw-r--r--dpd/src/TX_Agc.py111
2 files changed, 126 insertions, 0 deletions
diff --git a/dpd/main.py b/dpd/main.py
index 57bfed6..5e4f29f 100755
--- a/dpd/main.py
+++ b/dpd/main.py
@@ -12,6 +12,7 @@ predistortion module of ODR-DabMod."""
import datetime
import os
+import time
import logging
@@ -34,11 +35,13 @@ console.setFormatter(formatter)
# add the handler to the root logger
logging.getLogger('').addHandler(console)
+import numpy as np
import traceback
import src.Measure as Measure
import src.Model as Model
import src.Adapt as Adapt
import src.Agc as Agc
+import src.TX_Agc as TX_Agc
import src.Symbol_align
import src.const
import src.MER
@@ -66,6 +69,10 @@ parser.add_argument('--rxgain', default=30,
help='TX Gain',
required=False,
type=int)
+parser.add_argument('--digital_gain', default=1.0,
+ help='Digital Gain',
+ required=False,
+ type=float)
parser.add_argument('--samps', default='81920',
help='Number of samples to request from ODR-DabMod',
required=False)
@@ -81,6 +88,7 @@ cli_args = parser.parse_args()
port = int(cli_args.port)
port_rc = int(cli_args.rc_port)
coef_path = cli_args.coefs
+digital_gain = cli_args.digital_gain
txgain = cli_args.txgain
rxgain = cli_args.rxgain
num_req = int(cli_args.samps)
@@ -99,6 +107,7 @@ if cli_args.load_poly:
model = Model.Model(coefs_am, coefs_pm, plot=True)
else:
model = Model.Model([1, 0, 0, 0, 0], [0, 0, 0, 0, 0], plot=True)
+adapt.set_txgain(digital_gain)
adapt.set_txgain(txgain)
adapt.set_rxgain(rxgain)
adapt.set_coefs(model.coefs_am, model.coefs_pm)
@@ -112,6 +121,8 @@ logging.info(
)
)
+tx_agc = TX_Agc.TX_Agc(adapt)
+
# Automatic Gain Control
agc = Agc.Agc(meas, adapt)
agc.run()
@@ -120,6 +131,10 @@ for i in range(num_iter):
try:
txframe_aligned, tx_ts, rxframe_aligned, rx_ts, rx_median = meas.get_samples()
logging.debug("tx_ts {}, rx_ts {}".format(tx_ts, rx_ts))
+ assert tx_ts - rx_ts < 1e-5, "Time Stamps do not match."
+ if tx_agc.adapt_if_necessary(txframe_aligned):
+ continue
+
coefs_am, coefs_pm = model.get_next_coefs(txframe_aligned, rxframe_aligned)
adapt.set_coefs(coefs_am, coefs_pm)
diff --git a/dpd/src/TX_Agc.py b/dpd/src/TX_Agc.py
new file mode 100644
index 0000000..832c4d4
--- /dev/null
+++ b/dpd/src/TX_Agc.py
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+#
+# Automatic Gain Control
+#
+# http://www.opendigitalradio.org
+# Licence: The MIT License, see notice at the end of this file
+
+import datetime
+import os
+import logging
+import time
+
+logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+
+import numpy as np
+import matplotlib
+
+matplotlib.use('agg')
+import matplotlib.pyplot as plt
+
+import src.Adapt as Adapt
+import src.Measure as Measure
+
+
+#TODO fix for float tx_gain
+class TX_Agc:
+ def __init__(self,
+ adapt,
+ max_txgain=70,
+ tx_max_target=0.85,
+ tx_max_threshold_max=0.95,
+ tx_max_threshold_min=0.65):
+ """
+ In order to avoid digital clipping, this class increases the
+ TX gain and reduces the digital gain. Digital clipping happens
+ when the digital analog converter receives values greater than
+ it's maximal output. This class solves that problem by adapting
+ the TX gain in a way that the peaks of the TX signal are in a
+ specified range. The TX gain is adapted accordingly.
+
+ :param adapt: Instance of Adapt Class to update
+ txgain and coefficients
+ :param max_txgain: limit for TX gain
+ :param tx_max_threshold_max: if the maximum of TX is larger
+ than this value, then the digital gain is reduced
+ :param tx_max_threshold_min: if the maximum of TX is smaller
+ than this value, then the digital gain is increased
+ :param tx_max_target: The digital gain is reduced in a way that
+ the maximal TX value is expected to be lower than this value.
+ """
+ assert isinstance(adapt, Adapt.Adapt)
+ self.adapt = adapt
+ self.max_txgain = max_txgain
+ self.txgain = self.max_txgain
+
+ assert tx_max_threshold_max > tx_max_target,\
+ "The tolerated tx_max has to be larger then the goal tx_max"
+ self.tx_max_threshold_tolerate_max = tx_max_threshold_max
+ self.tx_max_threshold_tolerate_min = tx_max_threshold_min
+ self.tx_max_target = tx_max_target
+
+ def adapt_if_necessary(self, tx):
+ tx_max = np.max(np.abs(tx))
+ if tx_max > self.tx_max_threshold_tolerate_max or\
+ tx_max < self.tx_max_threshold_tolerate_min:
+ delta_db = \
+ np.floor(20 * np.log10(self.tx_max_target / tx_max)).astype(int)
+ new_txgain = self.adapt.get_txgain() - delta_db
+ assert new_txgain < self.max_txgain,\
+ "TX_Agc failed. New TX gain of {} is too large.".format(
+ new_txgain
+ )
+ self.adapt.set_txgain(new_txgain)
+ txgain = self.adapt.get_txgain()
+
+ digital_gain_factor = 10 ** (delta_db / 20.)
+ digital_gain = self.adapt.get_digital_gain() * digital_gain_factor
+ self.adapt.set_digital_gain(digital_gain)
+
+ logging.info(
+ "digital_gain = {}, txgain_new = {}, " \
+ "delta_db = {}, tx_max {}, " \
+ "digital_gain_factor = {}".
+ format(digital_gain, txgain, delta_db,
+ tx_max, digital_gain_factor))
+
+ time.sleep(1)
+ return True
+ return False
+
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Andreas Steger
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.