diff options
| -rwxr-xr-x | dpd/main.py | 15 | ||||
| -rw-r--r-- | dpd/src/TX_Agc.py | 111 | 
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. | 
