From aa3abebd804129f2eff361a1b4f21d0c04c61cfd Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Wed, 19 Dec 2018 17:13:40 +0100 Subject: GUI: Add adapt step to DPD --- python/dpdce.py | 63 ++++++++++++++++++++++++------- python/gui/api.py | 9 +++++ python/gui/static/js/odr-predistortion.js | 18 ++++++--- python/gui/templates/predistortion.html | 39 ++++++++++++------- 4 files changed, 98 insertions(+), 31 deletions(-) (limited to 'python') 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 @@ -105,6 +105,15 @@ class API: cherrypy.response.status = 400 return send_error("POST only") + @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): 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 @@
Status and calibration
-
Current DPDCE status: -
-
N/A
-
-
- + +
+
+
+

Current DPDCE status

+
+
N/A
+
+
+ +
+
+
N/A
+
+
+

Summary

+

Calibration needs to be done once before the PA model + can be trained. Every time calibration is changed, the predistortion + parameters are invalidated!

+

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.

+

The capture and model analysis will calculate a new set of + DPD model data, that you can apply using the Update Predistorter button.

-
N/A
-
Calibration needs to be done once before the PA model - can be trained. Every time calibration is changed, the predistortion - parameters are invalidated!
-
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.
+
-- cgit v1.2.3