diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2018-12-19 17:13:40 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2018-12-19 17:13:40 +0100 |
commit | aa3abebd804129f2eff361a1b4f21d0c04c61cfd (patch) | |
tree | e88a4a8e07f46be38fe8289c68eb19ac3f234d92 | |
parent | 49620ea6940543a875e0499a1554b33ffb85fa85 (diff) | |
download | dabmod-aa3abebd804129f2eff361a1b4f21d0c04c61cfd.tar.gz dabmod-aa3abebd804129f2eff361a1b4f21d0c04c61cfd.tar.bz2 dabmod-aa3abebd804129f2eff361a1b4f21d0c04c61cfd.zip |
GUI: Add adapt step to DPD
-rwxr-xr-x | python/dpdce.py | 63 | ||||
-rwxr-xr-x | python/gui/api.py | 9 | ||||
-rw-r--r-- | python/gui/static/js/odr-predistortion.js | 18 | ||||
-rw-r--r-- | python/gui/templates/predistortion.html | 39 |
4 files changed, 98 insertions, 31 deletions
diff --git a/python/dpdce.py b/python/dpdce.py index f76b0f6..90cd436 100755 --- a/python/dpdce.py +++ b/python/dpdce.py @@ -80,6 +80,7 @@ else: logging.info("DPDCE starting up"); +import time import socket from lib import yamlrpc import numpy as np @@ -238,9 +239,9 @@ def engine_worker(): # Extract usable data from measurement tx, rx, phase_diff, n_per_bin = extStat.extract(txframe_aligned, rxframe_aligned) - time = datetime.datetime.utcnow() - plot_file = "stats_{}.png".format(time.strftime("%s")) - extStat.plot(os.path.join(plot_path, plot_file), time.strftime("%Y-%m-%dT%H%M%S")) + utctime = datetime.datetime.utcnow() + plot_file = "stats_{}.png".format(utctime.strftime("%s")) + extStat.plot(os.path.join(plot_path, plot_file), utctime.strftime("%Y-%m-%dT%H%M%S")) n_meas = Heuristics.get_n_meas(n_runs) with lock: @@ -248,7 +249,6 @@ def engine_worker(): results['stateprogress'] += 5 results['summary'] += ["Extracted Statistics: TX median={} RX median={}".format(tx_median, rx_median), "Runs: {}/{}".format(extStat.n_meas, n_meas)] - internal_data['n_runs'] += 1 if extStat.n_meas >= n_meas: break @@ -265,11 +265,11 @@ def engine_worker(): model.train(tx, rx, phase_diff, lr=Heuristics.get_learning_rate(n_runs)) - time = datetime.datetime.utcnow() - model_plot_file = "model_{}.png".format(time.strftime("%s")) + utctime = datetime.datetime.utcnow() + model_plot_file = "model_{}.png".format(utctime.strftime("%s")) model.plot( os.path.join(plot_path, model_plot_file), - time.strftime("%Y-%m-%dT%H%M%S")) + utctime.strftime("%Y-%m-%dT%H%M%S")) with lock: results['modelplot'] = "dpd/" + model_plot_file @@ -293,6 +293,47 @@ def engine_worker(): results['state'] = 'Idle' results['stateprogress'] = 100 results['summary'] += ["New DPD coefficients calculated"] + elif cmd == "adapt": + with lock: + dpddata = internal_data['dpddata'] + results['state'] = 'Update Predistorter' + results['stateprogress'] = 50 + results['summary'] = [""] + iteration = internal_data['n_runs'] + internal_data['n_runs'] += 1 + + adapt.set_predistorter(dpddata) + + time.sleep(2) + + txframe_aligned, tx_ts, rxframe_aligned, rx_ts, rx_median, tx_median = meas.get_samples() + + # Store all settings for pre-distortion, tx and rx + adapt.dump() + + # Collect logging data + off = symbol_align.calc_offset(txframe_aligned) + tx_mer = mer.calc_mer(txframe_aligned[off:off + c.T_U], debug_name='TX') + rx_mer = mer.calc_mer(rxframe_aligned[off:off + c.T_U], debug_name='RX') + mse = np.mean(np.abs((txframe_aligned - rxframe_aligned) ** 2)) + tx_gain = adapt.get_txgain() + rx_gain = adapt.get_rxgain() + digital_gain = adapt.get_digital_gain() + rx_shoulder_tuple = meas_shoulders.average_shoulders(rxframe_aligned) + tx_shoulder_tuple = meas_shoulders.average_shoulders(txframe_aligned) + + lr = Heuristics.get_learning_rate(iteration) + + summary = [f"Signal measurements after iteration {iteration} with learning rate {lr}", + f"TX MER {tx_mer}, RX MER {rx_mer}", + "Shoulders: TX {!r}, RX {!r}".format(tx_shoulder_tuple, rx_shoulder_tuple), + f"Mean-square error: {mse}", + f"Running with digital gain {digital_gain}, TX gain {tx_gain} and RX gain {rx_gain}"] + + with lock: + results['state'] = 'Update Predistorter' + results['stateprogress'] = 100 + results['summary'] = ["Signal measurements after predistortion update"] + summary finally: with lock: results['state'] = 'Terminated' @@ -318,13 +359,9 @@ try: logging.error('YAML-RPC unknown error') break - if method == 'trigger_run': - logging.info('YAML-RPC request : {}'.format(method)) - command_queue.put('trigger_run') - cmd_socket.send_success_response(addr, msg_id, None) - elif method == 'reset': + if any(method == m for m in ['trigger_run', 'reset', 'adapt']): logging.info('YAML-RPC request : {}'.format(method)) - command_queue.put('reset') + command_queue.put(method) cmd_socket.send_success_response(addr, msg_id, None) elif method == 'set_setting': logging.info('YAML-RPC request : {} -> {}'.format(method, params)) diff --git a/python/gui/api.py b/python/gui/api.py index bff224e..42c89c9 100755 --- a/python/gui/api.py +++ b/python/gui/api.py @@ -107,6 +107,15 @@ class API: @cherrypy.expose @cherrypy.tools.json_out() + def dpd_adapt(self, **kwargs): + if cherrypy.request.method == 'POST': + return self._wrap_dpd("adapt") + else: + cherrypy.response.status = 400 + return send_error("POST only") + + @cherrypy.expose + @cherrypy.tools.json_out() def dpd_reset(self, **kwargs): if cherrypy.request.method == 'POST': return self._wrap_dpd("reset") diff --git a/python/gui/static/js/odr-predistortion.js b/python/gui/static/js/odr-predistortion.js index f46219c..b5f29ea 100644 --- a/python/gui/static/js/odr-predistortion.js +++ b/python/gui/static/js/odr-predistortion.js @@ -67,17 +67,25 @@ $(function(){ }); }); + $('#triggerbtn').click(function() { + doApiRequestPOST("/api/dpd_trigger_run", {}, function(data) { + console.log("run succeeded: " + JSON.stringify(data)); + }); + }); + + $('#adaptbtn').click(function() { + doApiRequestPOST("/api/dpd_adapt", {}, function(data) { + console.log("adapt succeeded: " + JSON.stringify(data)); + }); + }); + + $('#resetbtn').click(function() { doApiRequestPOST("/api/dpd_reset", {}, function(data) { console.log("reset succeeded: " + JSON.stringify(data)); }); }); - $('#triggerbtn').click(function() { - doApiRequestPOST("/api/dpd_trigger_run", {}, function(data) { - console.log("run succeeded: " + JSON.stringify(data)); - }); - }); }); /* diff --git a/python/gui/templates/predistortion.html b/python/gui/templates/predistortion.html index d102101..8682054 100644 --- a/python/gui/templates/predistortion.html +++ b/python/gui/templates/predistortion.html @@ -11,28 +11,41 @@ <div class="panel panel-default"> <div class="panel-heading">Status and calibration</div> <div class="panel-body"> - <div>Current DPDCE status: - <div> - <div id="dpdstatus" style="font-weight:bold;">N/A</div> - <div class="progress"> - <div id="dpdprogress" class="progress-bar" role="progressbar" style="width:0%"> - <span id="dpdprogresstext"></span> + + <div class="container-fluid"> + <div class="row"> + <div class="col-sm-8"> + <h2>Current DPDCE status</h2> + <div> + <div id="dpdstatus" style="font-weight:bold;">N/A</div> + <div class="progress"> + <div id="dpdprogress" class="progress-bar" role="progressbar" style="width:0%"> + <span id="dpdprogresstext"></span> + </div> + </div> </div> + <div class="well well-sm" id="dpdresults">N/A</div> + </div> + <div class="col-sm-4"> + <h2>Summary</h2> + <p>Calibration needs to be done once before the PA model + can be trained. Every time calibration is changed, the predistortion + parameters are invalidated!</p> + <p>Once calibration succeeded and correct RX gain is set, you + can trigger a capture and model the PA. Usually, several capture + runs are needed before the model can be trained.</p> + <p>The capture and model analysis will calculate a new set of + DPD model data, that you can apply using the Update Predistorter button.</p> </div> </div> - <div class="well well-sm" id="dpdresults">N/A</div> </div> - <div>Calibration needs to be done once before the PA model - can be trained. Every time calibration is changed, the predistortion - parameters are invalidated!</div> - <div>Once calibration succeeded and correct RX gain is set, you - can trigger a capture and model the PA. Usually, several capture - runs are needed before the model can be trained.</div> <button type="button" class="btn btn-sm btn-warning" id="calibratebtn"> Calibrate</button> <button type="button" class="btn btn-sm btn-warning" id="triggerbtn"> Trigger Capture and PA Modeling</button> + <button type="button" class="btn btn-sm btn-warning" id="adaptbtn"> + Update Predistorter</button> <button type="button" class="btn btn-sm btn-info" id="resetbtn"> Reset captured data</button> </div> |