aboutsummaryrefslogtreecommitdiffstats
path: root/python/dpdce.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/dpdce.py')
-rwxr-xr-xpython/dpdce.py114
1 files changed, 84 insertions, 30 deletions
diff --git a/python/dpdce.py b/python/dpdce.py
index 6c373fd..27c5253 100755
--- a/python/dpdce.py
+++ b/python/dpdce.py
@@ -87,6 +87,7 @@ import numpy as np
import traceback
import os.path
import glob
+import re
from threading import Thread, Lock
from queue import Queue
from dpd.Model import Poly
@@ -134,19 +135,14 @@ if cli_args.reset:
cmd_socket = yamlrpc.Socket(bind_port=control_port)
# The following is accessed by both threads and need to be locked
-settings = {
- 'rx_gain': rx_gain,
- 'tx_gain': tx_gain,
- 'digital_gain': digital_gain,
- 'dpddata': dpddata,
- }
internal_data = {
'n_runs': 0,
}
results = {
+ 'adapt_dumps': [],
'statplot': None,
'modelplot': None,
- 'modeldata': "",
+ 'modeldata': repr(dpddata),
'tx_median': 0,
'rx_median': 0,
'state': 'Idle',
@@ -156,6 +152,17 @@ results = {
lock = Lock()
command_queue = Queue(maxsize=1)
+# Fill list of adapt dumps so that user can choose a previous
+# setting across restarts.
+results['adapt_dumps'].append("defaults")
+
+adapt_dump_files = glob.glob(os.path.join(plot_path, "adapt_*.pkl"))
+re_adaptfile = re.compile(r"adapt_(.*)\.pkl")
+for f in adapt_dump_files:
+ match = re_adaptfile.search(f)
+ if match:
+ results['adapt_dumps'].append(match.group(1))
+
# Automatic Gain Control for the RX gain
agc = Agc(meas, adapt, c)
@@ -171,8 +178,8 @@ def clear_pngs(results):
def engine_worker():
extStat = None
- try:
- while True:
+ while True:
+ try:
cmd = command_queue.get()
if cmd == "quit":
@@ -184,7 +191,7 @@ def engine_worker():
clear_pngs(results)
summary = []
- N_ITER = 5
+ N_ITER = 3
for i in range(N_ITER):
agc_success, agc_summary = agc.run()
summary += ["Iteration {}:".format(i)] + agc_summary.split("\n")
@@ -199,8 +206,6 @@ def engine_worker():
txframe_aligned, tx_ts, rxframe_aligned, rx_ts, rx_median, tx_median = meas.get_samples()
with lock:
- settings['rx_gain'] = adapt.get_rxgain()
- settings['digital_gain'] = adapt.get_digital_gain()
results['tx_median'] = float(tx_median)
results['rx_median'] = float(rx_median)
results['state'] = 'Idle'
@@ -233,9 +238,6 @@ def engine_worker():
with lock:
results['stateprogress'] += 5
- results['summary'] = ["Captured {} samples".format(len(txframe_aligned)),
- "TX/RX median: {} / {}".format(tx_median, rx_median),
- extStat.get_bin_info()]
# Extract usable data from measurement
tx, rx, phase_diff, n_per_bin = extStat.extract(txframe_aligned, rxframe_aligned)
@@ -248,8 +250,11 @@ def engine_worker():
with lock:
results['statplot'] = "dpd/" + plot_file
results['stateprogress'] += 5
- results['summary'] += ["Extracted Statistics: TX median={} RX median={}".format(tx_median, rx_median),
- "Runs: {}/{}".format(extStat.n_meas, n_meas)]
+ results['summary'] = ["Captured {} samples".format(len(txframe_aligned)),
+ "TX/RX median: {} / {}".format(tx_median, rx_median),
+ extStat.get_bin_info(),
+ "Extracted Statistics: TX median={} RX median={}".format(tx_median, rx_median),
+ "Runs: {}/{}".format(extStat.n_meas, n_meas)]
if extStat.n_meas >= n_meas:
break
@@ -303,7 +308,7 @@ def engine_worker():
iteration = internal_data['n_runs']
internal_data['n_runs'] += 1
- answer = adapt.set_predistorter(dpddata)
+ adapt.set_predistorter(dpddata)
time.sleep(2)
@@ -314,6 +319,9 @@ def engine_worker():
dump_file = "adapt_{}.pkl".format(utctime.strftime("%s"))
adapt.dump(os.path.join(plot_path, dump_file))
+ with lock:
+ results['adapt_dumps'].append(utctime.strftime("%s"))
+
# 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')
@@ -327,7 +335,7 @@ def engine_worker():
lr = Heuristics.get_learning_rate(iteration)
- summary = [f"Set predistorter: {answer}",
+ summary = [f"Set predistorter:",
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),
@@ -338,10 +346,59 @@ def engine_worker():
results['state'] = 'Update Predistorter'
results['stateprogress'] = 100
results['summary'] = ["Signal measurements after predistortion update"] + summary
- finally:
- with lock:
- results['state'] = 'Terminated'
- results['stateprogress'] = 0
+ elif cmd.startswith("restore_dump-"):
+ _, _, dump_id = cmd.partition("-")
+ if dump_id == "defaults":
+ model.reset_coefs()
+ dpddata = model.get_dpd_data()
+ adapt.set_predistorter(dpddata)
+
+ tx_gain = adapt.get_txgain()
+ rx_gain = adapt.get_rxgain()
+ digital_gain = adapt.get_digital_gain()
+ with lock:
+ results['state'] = 'Idle'
+ results['stateprogress'] = 100
+ results['summary'] = [f"Restored DPD defaults",
+ f"Running with digital gain {digital_gain}, TX gain {tx_gain} and RX gain {rx_gain}"]
+ results['modeldata'] = repr(dpddata)
+ else:
+ dump_file = os.path.join(plot_path, f"adapt_{dump_id}.pkl")
+ try:
+ d = adapt.restore(dump_file)
+ logging.info(f"Restore: {d}")
+ model.set_dpd_data(d['dpddata'])
+ with lock:
+ results['state'] = 'Idle'
+ results['stateprogress'] = 100
+ results['summary'] = [f"Restored DPD settings from dumpfile {dump_id}",
+ f"Running with digital gain {d['digital_gain']}, TX gain {d['txgain']} and RX gain {d['rxgain']}"]
+ results['modeldata'] = repr(d["dpddata"])
+ except:
+ e = traceback.format_exc()
+ with lock:
+ results['state'] = 'Idle'
+ results['stateprogress'] = 100
+ results['summary'] = [f"Failed to restore DPD settings from dumpfile {dump_id}",
+ f"Error: {e}"]
+ except:
+ e = traceback.format_exc()
+ logging.error(e)
+ with lock:
+ results['summary'] = [f"Exception:"] + e.split("\n")
+ results['state'] = 'Autorestart pending'
+ results['stateprogress'] = 0
+
+ for i in range(5):
+ time.sleep(2)
+ with lock:
+ results['stateprogress'] += 20
+ time.sleep(2)
+ with lock:
+ dt = datetime.datetime.utcnow().isoformat()
+ results['summary'] = [f"DPD engine auto-restarted at {dt} UTC", f"After exception {e}"]
+ results['state'] = 'Idle'
+ results['stateprogress'] = 0
engine = Thread(target=engine_worker)
@@ -367,13 +424,10 @@ try:
logging.info('YAML-RPC request : {}'.format(method))
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))
- # params == {'setting': ..., 'value': ...}
+ elif method == 'restore_dump':
+ logging.info('YAML-RPC restore dump {}'.format(params['dump_id']))
+ command_queue.put(f"restore_dump-{params['dump_id']}")
cmd_socket.send_success_response(addr, msg_id, None)
- elif method == 'get_settings':
- with lock:
- cmd_socket.send_success_response(addr, msg_id, settings)
elif method == 'get_results':
with lock:
cmd_socket.send_success_response(addr, msg_id, results)
@@ -511,7 +565,7 @@ while i < num_iter:
# The MIT License (MIT)
#
# Copyright (c) 2017 Andreas Steger
-# Copyright (c) 2018 Matthias P. Braendli
+# Copyright (c) 2019 Matthias P. Braendli
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal