diff options
author | andreas128 <Andreas> | 2017-09-08 10:05:56 +0200 |
---|---|---|
committer | andreas128 <Andreas> | 2017-09-08 10:05:56 +0200 |
commit | 988e0b9472489657f86838362b176863ec42d0fd (patch) | |
tree | 9a782277c75c8477119716f24e4064879ac0c56c /dpd/src | |
parent | 1b6c5dd58658bbc1b423b50baa15ca3fae6a1065 (diff) | |
download | dabmod-988e0b9472489657f86838362b176863ec42d0fd.tar.gz dabmod-988e0b9472489657f86838362b176863ec42d0fd.tar.bz2 dabmod-988e0b9472489657f86838362b176863ec42d0fd.zip |
Cleanup and change logging plots to svg
Diffstat (limited to 'dpd/src')
-rw-r--r-- | dpd/src/Adapt.py | 9 | ||||
-rw-r--r-- | dpd/src/Agc.py | 6 | ||||
-rw-r--r-- | dpd/src/Dab_Util.py | 10 | ||||
-rw-r--r-- | dpd/src/MER.py | 2 | ||||
-rw-r--r-- | dpd/src/Model.py | 249 | ||||
-rw-r--r-- | dpd/src/TX_Agc.py | 15 | ||||
-rw-r--r-- | dpd/src/phase_align.py | 2 | ||||
-rwxr-xr-x | dpd/src/subsample_align.py | 2 |
8 files changed, 92 insertions, 203 deletions
diff --git a/dpd/src/Adapt.py b/dpd/src/Adapt.py index 5e05112..b4042d6 100644 --- a/dpd/src/Adapt.py +++ b/dpd/src/Adapt.py @@ -85,7 +85,7 @@ class Adapt: # TODO this is specific to the B200 if gain < 0 or gain > 89: raise ValueError("Gain has to be in [0,89]") - return self.send_receive("set uhd txgain %d" % gain) + return self.send_receive("set uhd txgain %.4f" % float(gain)) def get_txgain(self): """Get the txgain value in dB for the ODR-DabMod.""" @@ -103,12 +103,12 @@ class Adapt: # TODO this is specific to the B200 if gain < 0 or gain > 89: raise ValueError("Gain has to be in [0,89]") - return self.send_receive("set uhd rxgain %d" % gain) + return self.send_receive("set uhd rxgain %.4f" % float(gain)) def get_rxgain(self): """Get the rxgain value in dB for the ODR-DabMod.""" # TODO handle failure - return int(self.send_receive("get uhd rxgain")[0]) + return float(self.send_receive("get uhd rxgain")[0]) def set_digital_gain(self, gain): """Set a new rxgain for the ODR-DabMod. @@ -118,7 +118,8 @@ class Adapt: gain : int new RX gain, in the same format as ODR-DabMod's config file """ - return self.send_receive("set gain digital %.5f" % gain) + msg = "set gain digital %.5f" % gain + return self.send_receive(msg) def get_digital_gain(self): """Get the rxgain value in dB for the ODR-DabMod.""" diff --git a/dpd/src/Agc.py b/dpd/src/Agc.py index 1fd11c8..978b607 100644 --- a/dpd/src/Agc.py +++ b/dpd/src/Agc.py @@ -47,7 +47,7 @@ class Agc: def run(self): self.adapt.set_rxgain(self.rxgain) - for i in range(3): + for i in range(2): # Measure txframe_aligned, tx_ts, rxframe_aligned, rx_ts, rx_median= \ self.measure.get_samples() @@ -65,7 +65,7 @@ class Agc: )) self.adapt.set_rxgain(self.rxgain) - time.sleep(1) + time.sleep(0.5) def plot_estimates(self): """Plots the estimate of for Max, Median, Mean for different @@ -74,7 +74,7 @@ class Agc: time.sleep(1) dt = datetime.datetime.now().isoformat() - fig_path = logging_path + "/" + dt + "_agc.pdf" + fig_path = logging_path + "/" + dt + "_agc.svg" fig, axs = plt.subplots(2, 2, figsize=(3*6,1*6)) axs = axs.ravel() diff --git a/dpd/src/Dab_Util.py b/dpd/src/Dab_Util.py index 8a53004..a7403a3 100644 --- a/dpd/src/Dab_Util.py +++ b/dpd/src/Dab_Util.py @@ -45,7 +45,7 @@ class Dab_Util: if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot: dt = datetime.datetime.now().isoformat() - corr_path = (logging_path + "/" + dt + "_tx_rx_corr.pdf") + corr_path = (logging_path + "/" + dt + "_tx_rx_corr.svg") plt.plot(c, label="corr") plt.legend() plt.savefig(corr_path) @@ -99,7 +99,7 @@ class Dab_Util: if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot: dt = datetime.datetime.now().isoformat() - fig_path = logging_path + "/" + dt + "_sync_raw.pdf" + fig_path = logging_path + "/" + dt + "_sync_raw.svg" fig, axs = plt.subplots(2) axs[0].plot(np.abs(sig_tx[:128]), label="TX Frame") @@ -143,7 +143,7 @@ class Dab_Util: if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot: dt = datetime.datetime.now().isoformat() - fig_path = logging_path + "/" + dt + "_sync_sample_aligned.pdf" + fig_path = logging_path + "/" + dt + "_sync_sample_aligned.svg" fig, axs = plt.subplots(2) axs[0].plot(np.abs(sig_tx[:128]), label="TX Frame") @@ -168,7 +168,7 @@ class Dab_Util: if logging.getLogger().getEffectiveLevel() == logging.DEBUG: dt = datetime.datetime.now().isoformat() - fig_path = logging_path + "/" + dt + "_sync_subsample_aligned.pdf" + fig_path = logging_path + "/" + dt + "_sync_subsample_aligned.svg" fig, axs = plt.subplots(2) axs[0].plot(np.abs(sig_tx[:128]), label="TX Frame") @@ -192,7 +192,7 @@ class Dab_Util: if logging.getLogger().getEffectiveLevel() == logging.DEBUG: dt = datetime.datetime.now().isoformat() - fig_path = logging_path + "/" + dt + "_sync_phase_aligned.pdf" + fig_path = logging_path + "/" + dt + "_sync_phase_aligned.svg" fig, axs = plt.subplots(2) axs[0].plot(np.abs(sig_tx[:128]), label="TX Frame") diff --git a/dpd/src/MER.py b/dpd/src/MER.py index 2075ef5..00fcc23 100644 --- a/dpd/src/MER.py +++ b/dpd/src/MER.py @@ -77,7 +77,7 @@ class MER: if debug: dt = datetime.datetime.now().isoformat() - fig_path = logging_path + "/" + dt + "_MER.pdf" + fig_path = logging_path + "/" + dt + "_MER.svg" MERs = [] for i, (x, y) in enumerate(self._split_in_carrier( diff --git a/dpd/src/Model.py b/dpd/src/Model.py index dc526c5..bf52287 100644 --- a/dpd/src/Model.py +++ b/dpd/src/Model.py @@ -32,11 +32,11 @@ class Model: self.plot=plot - def sample_uniformly(self, txframe_aligned, rxframe_aligned, n_bins=4): + def sample_uniformly(self, tx_dpd, rx_received, n_bins=4): """This function returns tx and rx samples in a way that the tx amplitudes have an approximate uniform - distribution with respect to the txframe_aligned amplitudes""" - txframe_aligned_abs = np.abs(txframe_aligned) + distribution with respect to the tx_dpd amplitudes""" + txframe_aligned_abs = np.abs(tx_dpd) ccdf_min = 0 ccdf_max = np.max(txframe_aligned_abs) tx_hist, ccdf_edges = np.histogram(txframe_aligned_abs, @@ -50,219 +50,111 @@ class Model: indices = np.where((txframe_aligned_abs >= ccdf_edges[idx]) & (txframe_aligned_abs <= ccdf_edges[idx+1]))[0] indices_choise = np.random.choice(indices, n_choise, replace=False) - rx_choice[idx*n_choise:(idx+1)*n_choise] = rxframe_aligned[indices_choise] - tx_choice[idx*n_choise:(idx+1)*n_choise] = txframe_aligned[indices_choise] + rx_choice[idx*n_choise:(idx+1)*n_choise] = rx_received[indices_choise] + tx_choice[idx*n_choise:(idx+1)*n_choise] = tx_dpd[indices_choise] return tx_choice, rx_choice - def get_next_coefs(self, txframe_aligned, rxframe_aligned): - tx_choice, rx_choice = self.sample_uniformly(txframe_aligned, rxframe_aligned) + def amplitude_predistortion(self, sig): + sig_abs = np.abs(sig) + A_sig = np.vstack([np.ones(sig_abs.shape), + sig_abs ** 2, + sig_abs ** 4, + sig_abs ** 6, + sig_abs ** 8, + ]).T + sig_dpd = sig * np.sum(A_sig * self.coefs_am, axis=1) + return sig_dpd, A_sig + + def dpd_phase(self, tx): + tx_abs = np.abs(tx) + tx_A_complex = np.vstack([tx, + tx * tx_abs ** 1, + tx * tx_abs ** 2, + tx * tx_abs ** 3, + tx * tx_abs ** 4, + ]).T + tx_dpd = np.sum(tx_A_complex * self.coefs_pm, axis=1) + return tx_dpd + + def get_next_coefs(self, tx_dpd, rx_received): + normalization_error = np.abs(np.median(np.abs(tx_dpd)) - np.median(np.abs(rx_received)))/(np.median(np.abs(tx_dpd)) + np.median(np.abs(rx_received))) + assert normalization_error < 0.01, "Non normalized signals" + tx_choice, rx_choice = self.sample_uniformly(tx_dpd, rx_received) # Calculate new coefficients for AM/AM correction - rx_abs = np.abs(rx_choice) - rx_A = np.vstack([rx_abs, - rx_abs ** 3, - rx_abs ** 5, - rx_abs ** 7, - rx_abs ** 9, - ]).T - rx_dpd = np.sum(rx_A * self.coefs_am, axis=1) + rx_dpd, rx_A = self.amplitude_predistortion(rx_choice) rx_dpd = rx_dpd * ( - np.median(np.abs(tx_choice)) / np.median(np.abs(rx_dpd))) + np.median(np.abs(tx_choice)) / + np.median(np.abs(rx_dpd))) - err = rx_dpd - np.abs(tx_choice) + err = np.abs(rx_dpd) - np.abs(tx_choice) self.errs.append(np.mean(np.abs(err ** 2))) + mse = np.mean(np.abs((rx_dpd - tx_choice)**2)) + self.mses.append(mse) + a_delta = np.linalg.lstsq(rx_A, err)[0] new_coefs = self.coefs_am - 0.1 * a_delta new_coefs = new_coefs * (self.coefs_am[0] / new_coefs[0]) + assert np.abs(self.coefs_am[0] / new_coefs[0] - 1) < 0.1, \ + "Too large change in first " \ + "coefficient. {}, {}".format(self.coefs_am[0], new_coefs[0]) logging.debug("a_delta {}".format(a_delta)) logging.debug("new coefs_am {}".format(new_coefs)) - # Calculate new coefficients for AM/PM correction - phase_diff_rad = (( - (np.angle(tx_choice) - - np.angle(rx_choice) + - np.pi) % (2 * np.pi)) - - np.pi - ) - - tx_abs = np.abs(tx_choice) - tx_abs_A = np.vstack([tx_abs, - tx_abs ** 2, - tx_abs ** 3, - tx_abs ** 4, - tx_abs ** 5, - ]).T - phase_dpd = np.sum(tx_abs_A * self.coefs_pm, axis=1) - - err_phase = phase_dpd - phase_diff_rad - self.errs_phase.append(np.mean(np.abs(err_phase ** 2))) - a_delta = np.linalg.lstsq(tx_abs_A, err_phase)[0] - new_coefs_pm = self.coefs_pm - 0.1 * a_delta - logging.debug("a_delta {}".format(a_delta)) - logging.debug("new new_coefs_pm {}".format(new_coefs_pm)) - - def dpd_phase(tx): - tx_abs = np.abs(tx) - tx_A_complex = np.vstack([tx, - tx * tx_abs ** 1, - tx * tx_abs ** 2, - tx * tx_abs ** 3, - tx * tx_abs ** 4, - ]).T - tx_dpd = np.sum(tx_A_complex * self.coefs_pm, axis=1) - return tx_dpd - - tx_range = np.linspace(0, 2) - phase_range_dpd = dpd_phase(tx_range) - - rx_A_complex = np.vstack([rx_choice, - rx_choice * rx_abs ** 2, - rx_choice * rx_abs ** 4, - rx_choice * rx_abs ** 6, - rx_choice * rx_abs ** 8, - ]).T - rx_post_distored = np.sum(rx_A_complex * self.coefs_am, axis=1) - rx_post_distored = rx_post_distored * ( - np.median(np.abs(tx_choice)) / - np.median(np.abs(rx_post_distored))) - mse = np.mean(np.abs((tx_choice - rx_post_distored) ** 2)) - logging.debug("MSE: {}".format(mse)) - self.mses.append(mse) - - def dpd(tx): - tx_abs = np.abs(tx) - tx_A_complex = np.vstack([tx, - tx * tx_abs ** 2, - tx * tx_abs ** 4, - tx * tx_abs ** 6, - tx * tx_abs ** 8, - ]).T - tx_dpd = np.sum(tx_A_complex * self.coefs_am, axis=1) - return tx_dpd - rx_range = np.linspace(0, 1, num=100) - rx_range_dpd = dpd(rx_range) + rx_range_dpd = self.amplitude_predistortion(rx_range)[0] rx_range = rx_range[(rx_range_dpd > 0) & (rx_range_dpd < 2)] rx_range_dpd = rx_range_dpd[(rx_range_dpd > 0) & (rx_range_dpd < 2)] - logging.debug("txframe: min %f, max %f, median %f" % - (np.min(np.abs(txframe_aligned)), - np.max(np.abs(txframe_aligned)), - np.median(np.abs(txframe_aligned)) - )) - - logging.debug("rxframe: min %f, max %f, median %f" % - (np.min(np.abs(rx_choice)), - np.max(np.abs(rx_choice)), - np.median(np.abs(rx_choice)) - )) + logging.debug('txframe: min {:.2f}, max {:.2f}, ' \ + 'median {:.2f}; rxframe: min {:.2f}, max {:.2f}, ' \ + 'median {:.2f}; a_delta {}; new coefs_am {}'.format( + np.min(np.abs(tx_dpd)), + np.max(np.abs(tx_dpd)), + np.median(np.abs(tx_dpd)), + np.min(np.abs(rx_choice)), + np.max(np.abs(rx_choice)), + np.median(np.abs(rx_choice)), + a_delta, + new_coefs)) if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot: dt = datetime.datetime.now().isoformat() - fig_path = logging_path + "/" + dt + "_Model.pdf" + fig_path = logging_path + "/" + dt + "_Model.svg" - fig = plt.figure(figsize=(3*6, 1.5 * 6)) + fig = plt.figure(figsize=(3*6, 6)) - ax = plt.subplot(3,3,1) - ax.plot(np.abs(txframe_aligned[:128]), + ax = plt.subplot(2,3,1) + ax.plot(np.abs(tx_dpd[:128]), label="TX sent", linestyle=":") - ax.plot(np.abs(rxframe_aligned[:128]), + ax.plot(np.abs(rx_received[:128]), label="RX received", color="red") ax.set_title("Synchronized Signals of Iteration {}".format(len(self.coefs_history))) ax.set_xlabel("Samples") ax.set_ylabel("Amplitude") ax.text(0, 0, "TX (max {:01.3f}, mean {:01.3f}, median {:01.3f})".format( - np.max(np.abs(txframe_aligned)), - np.mean(np.abs(txframe_aligned)), - np.median(np.abs(txframe_aligned)) + np.max(np.abs(tx_dpd)), + np.mean(np.abs(tx_dpd)), + np.median(np.abs(tx_dpd)) ), size = 8) ax.legend(loc=4) - ax = plt.subplot(3,3,2) - ax.plot(np.real(txframe_aligned[:128]), - label="TX sent", - linestyle=":") - ax.plot(np.real(rxframe_aligned[:128]), - label="RX received", - color="red") - ax.set_title("Synchronized Signals") - ax.set_xlabel("Samples") - ax.set_ylabel("Real Part") - ax.legend(loc=4) - - ax = plt.subplot(3,3,3) - ax.plot(np.abs(txframe_aligned[:128]), - label="TX Frame", - linestyle=":", - linewidth=0.5) - ax.plot(np.abs(rxframe_aligned[:128]), - label="RX Frame", - linestyle="--", - linewidth=0.5) - - rx_abs = np.abs(rxframe_aligned) - rx_A = np.vstack([rx_abs, - rx_abs ** 3, - rx_abs ** 5, - rx_abs ** 7, - rx_abs ** 9, - ]).T - rx_dpd = np.sum(rx_A * self.coefs_am, axis=1) - rx_dpd = rx_dpd * ( - np.median(np.abs(tx_choice)) / np.median(np.abs(rx_dpd))) - - ax.plot(np.abs(rx_dpd[:128]), - label="RX DPD Frame", - linestyle="-.", - linewidth=0.5) - - tx_abs = np.abs(np.abs(txframe_aligned[:128])) - tx_A = np.vstack([tx_abs, - tx_abs ** 3, - tx_abs ** 5, - tx_abs ** 7, - tx_abs ** 9, - ]).T - tx_dpd = np.sum(tx_A * new_coefs, axis=1) - tx_dpd_norm = tx_dpd * ( - np.median(np.abs(tx_choice)) / np.median(np.abs(tx_dpd))) - - ax.plot(np.abs(tx_dpd_norm[:128]), - label="TX DPD Frame Norm", - linestyle="-.", - linewidth=0.5) - ax.legend(loc=4) - ax.set_title("RX DPD") - ax.set_xlabel("Samples") - ax.set_ylabel("Amplitude") - - ax = plt.subplot(3,3,4) + ax = plt.subplot(2,3,2) ax.scatter( - np.abs(tx_choice[:1024]), - np.abs(rx_choice[:1024]), + np.abs(tx_choice), + np.abs(rx_choice), s=0.1) ax.plot(rx_range_dpd / self.coefs_am[0], rx_range, linewidth=0.25) ax.set_title("Amplifier Characteristic") ax.set_xlabel("TX Amplitude") ax.set_ylabel("RX Amplitude") - ax = plt.subplot(3,3,5) - ax.scatter( - np.abs(tx_choice[:1024]), - phase_diff_rad[:1024] * 180 / np.pi, - s=0.1 - ) - ax.plot(tx_range, phase_range_dpd * 180 / np.pi, linewidth=0.25) - ax.set_title("Amplifier Characteristic") - ax.set_xlabel("TX Amplitude") - ax.set_ylabel("Phase Difference [deg]") - - ax = plt.subplot(3,3,6) + ax = plt.subplot(2,3,3) ccdf_min, ccdf_max = 0, 1 - tx_hist, ccdf_edges = np.histogram(np.abs(txframe_aligned), + tx_hist, ccdf_edges = np.histogram(np.abs(tx_dpd), bins=60, range=(ccdf_min, ccdf_max)) tx_hist_normalized = tx_hist.astype(float)/np.sum(tx_hist) @@ -278,7 +170,7 @@ class Model: ax.set_xlabel("TX Amplitude") ax.set_ylabel("Ratio of Samples larger than x") - ax = plt.subplot(3,3,7) + ax = plt.subplot(2,3,4) coefs_history = np.array(self.coefs_history) for idx, coef_hist in enumerate(coefs_history.T): ax.plot(coef_hist, @@ -289,7 +181,7 @@ class Model: ax.set_xlabel("Iterations") ax.set_ylabel("Coefficient Value") - ax = plt.subplot(3,3,8) + ax = plt.subplot(2,3,5) coefs_history = np.array(self.coefs_pm_history) for idx, coef_hist in enumerate(coefs_history.T): ax.plot(coef_hist, @@ -300,8 +192,7 @@ class Model: ax.set_xlabel("Iterations") ax.set_ylabel("Coefficient Value") - ax = plt.subplot(3,3,9) - coefs_history = np.array(self.coefs_history) + ax = plt.subplot(2,3,6) ax.plot(self.mses, label="MSE") ax.plot(self.errs, label="ERR") ax.legend(loc=4) @@ -315,8 +206,6 @@ class Model: self.coefs_am = new_coefs self.coefs_history.append(self.coefs_am) - self.coefs_pm = new_coefs_pm - self.coefs_pm_history.append(self.coefs_pm) return self.coefs_am, self.coefs_pm # The MIT License (MIT) diff --git a/dpd/src/TX_Agc.py b/dpd/src/TX_Agc.py index 6f4cee8..c3d0698 100644 --- a/dpd/src/TX_Agc.py +++ b/dpd/src/TX_Agc.py @@ -24,10 +24,10 @@ import src.Adapt as Adapt class TX_Agc: def __init__(self, adapt, - max_txgain=80, - tx_median_target=0.1, - tx_median_threshold_max=0.15, - tx_median_threshold_min=0.05): + max_txgain=85, + tx_median_target=0.04, + tx_median_threshold_max=0.07, + tx_median_threshold_min=0.02): """ In order to avoid digital clipping, this class increases the TX gain and reduces the digital gain. Digital clipping happens @@ -62,8 +62,7 @@ class TX_Agc: tx_median = np.median(np.abs(tx)) if tx_median > self.tx_median_threshold_tolerate_max or\ tx_median < self.tx_median_threshold_tolerate_min: - delta_db = \ - np.floor(20 * np.log10(self.tx_median_target / tx_median)).astype(int) + delta_db = 20 * np.log10(self.tx_median_target / tx_median) 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( @@ -77,8 +76,8 @@ class TX_Agc: self.adapt.set_digital_gain(digital_gain) logging.info( - "digital_gain = {}, txgain_new = {}, " \ - "delta_db = {}, tx_median {}, " \ + "digital_gain = {}, txgain_new = {}, "\ + "delta_db = {}, tx_median {}, "\ "digital_gain_factor = {}". format(digital_gain, txgain, delta_db, tx_median, digital_gain_factor)) diff --git a/dpd/src/phase_align.py b/dpd/src/phase_align.py index f8e38c4..7f82392 100644 --- a/dpd/src/phase_align.py +++ b/dpd/src/phase_align.py @@ -28,7 +28,7 @@ def phase_align(sig, ref_sig, plot=False): if logging.getLogger().getEffectiveLevel() == logging.DEBUG and plot: dt = datetime.datetime.now().isoformat() - fig_path = logging_path + "/" + dt + "_phase_align.pdf" + fig_path = logging_path + "/" + dt + "_phase_align.svg" plt.subplot(511) plt.hist(angle_diff, bins=60, label="Angle Diff") diff --git a/dpd/src/subsample_align.py b/dpd/src/subsample_align.py index cc2b975..6d1cd2a 100755 --- a/dpd/src/subsample_align.py +++ b/dpd/src/subsample_align.py @@ -74,7 +74,7 @@ def subsample_align(sig, ref_sig, plot=False): taus = corr(ixs) dt = datetime.datetime.now().isoformat() - tau_path = (logging_path + "/" + dt + "_tau.pdf") + tau_path = (logging_path + "/" + dt + "_tau.svg") plt.plot(ixs, taus) plt.title("Subsample correlation, minimum is best: {}".format(best_tau)) plt.savefig(tau_path) |