summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xgui/api/__init__.py5
-rw-r--r--gui/dpd/Capture.py57
-rw-r--r--gui/dpd/__init__.py24
-rw-r--r--gui/static/js/odr-modulator.js6
-rw-r--r--gui/static/js/odr-predistortion.js22
-rw-r--r--gui/templates/modulator.html8
-rw-r--r--gui/templates/predistortion.html5
7 files changed, 96 insertions, 31 deletions
diff --git a/gui/api/__init__.py b/gui/api/__init__.py
index 959dedc..6c04a64 100755
--- a/gui/api/__init__.py
+++ b/gui/api/__init__.py
@@ -71,3 +71,8 @@ class API:
cherrypy.response.headers["Content-Type"] = "text/plain"
cherrypy.response.status = 400
return "POST only"
+
+ @cherrypy.expose
+ def dpd_status(self, **kwargs):
+ cherrypy.response.headers["Content-Type"] = "application/json"
+ return json.dumps(self.dpd.status()).encode()
diff --git a/gui/dpd/Capture.py b/gui/dpd/Capture.py
index d6d0307..31fa78d 100644
--- a/gui/dpd/Capture.py
+++ b/gui/dpd/Capture.py
@@ -77,8 +77,12 @@ class Capture:
self.binning_n_bins = 64 # Number of bins between binning_start and binning_end
self.binning_n_per_bin = 128 # Number of measurements pre bin
+ self.target_median = 0.01
+ self.median_max = self.target_median * 1.4
+ self.median_min = self.target_median / 1.4
+
# axis 1: 0=tx, 1=rx
- self.accumulated_samples = np.zeros((0, 2), dtype=np.complex64)
+ self.accumulated_bins = [np.zeros((0, 2), dtype=np.complex64) for i in range(self.binning_n_bins)]
def _recv_exact(self, sock, num_bytes):
"""Receive an exact number of bytes from a socket. This is
@@ -156,42 +160,45 @@ class Capture:
txframe, tx_ts, rxframe, rx_ts = self.receive_tcp()
# Normalize received signal with sent signal
- rx_median = np.median(np.abs(rxframe))
tx_median = np.median(np.abs(txframe))
- rxframe = rxframe / rx_median * tx_median
- txframe_aligned, rxframe_aligned = align_samples(txframe, rxframe)
+ if self.median_max < tx_median:
+ raise ValueError("Median {} too high, decrease digital_gain!".format(tx_median))
+ elif tx_median < self.median_min:
+ raise ValueError("Median {} too low, increase digital_gain!".format(tx_median))
+ else:
+ rx_median = np.median(np.abs(rxframe))
+ rxframe = rxframe / rx_median * tx_median
+
+ txframe_aligned, rxframe_aligned = align_samples(txframe, rxframe)
- self._bin_and_accumulate(txframe_aligned, rxframe_aligned)
+ self._bin_and_accumulate(txframe_aligned, rxframe_aligned)
- return txframe_aligned, tx_ts, tx_median, rxframe_aligned, rx_ts, rx_median
+ return txframe_aligned, tx_ts, tx_median, rxframe_aligned, rx_ts, rx_median
- def num_accumulated(self):
- return self.accumulated_samples.shape[0]
+ def bin_histogram(self):
+ return [b.shape[0] for b in self.accumulated_bins]
def _bin_and_accumulate(self, txframe, rxframe):
"""Bin the samples and extend the accumulated samples"""
bin_edges = np.linspace(self.binning_start, self.binning_end, self.binning_n_bins)
- binned_sample_pairs = {}
-
minsize = self.num_samples_to_request
for i, (tx_start, tx_end) in enumerate(zip(bin_edges, bin_edges[1:])):
- indices = np.bitwise_and(tx_start < txframe, txframe <= tx_end)
- binned_sample_pairs[i] = (txframe[indices], rxframe[indices])
- len_bin = len(txframe[indices])
-
- #TODO this doesn't work, the min is always 0
- if len_bin < minsize:
- minsize = len_bin
-
- # axis 0: bins, axis 1: sample index, axis 2: tx(0) and rx(1)
- samples = np.zeros((self.binning_n_bins, len_bin, 2), dtype=np.complex64)
-
- for i in binned_sample_pairs:
- tx, rx = binned_sample_pairs[i]
- new_samples = np.array((tx[:minsize], rx[:minsize]), dtype=np.complex64)
- self.accumulated_samples = np.concatenate((self.accumulated_samples, new_samples.T))
+ txframe_abs = np.abs(txframe)
+ indices = np.bitwise_and(tx_start < txframe_abs, txframe_abs <= tx_end)
+ txsamples = np.asmatrix(txframe[indices])
+ rxsamples = np.asmatrix(rxframe[indices])
+ binned_sample_pairs = np.concatenate((txsamples, rxsamples)).T
+
+ missing_in_bin = self.binning_n_per_bin - self.accumulated_bins[i].shape[0]
+ num_to_append = min(missing_in_bin, binned_sample_pairs.shape[0])
+ print("Handling bin {} {}-{}, {} available, {} missing".format(i, tx_start, tx_end, binned_sample_pairs.shape[0], missing_in_bin))
+ if num_to_append:
+ print("Appending {} to bin {} with shape {}".format(num_to_append, i, self.accumulated_bins[i].shape))
+
+ self.accumulated_bins[i] = np.concatenate((self.accumulated_bins[i], binned_sample_pairs[:num_to_append,...]))
+ print("{} now has shape {}".format(i, self.accumulated_bins[i].shape))
diff --git a/gui/dpd/__init__.py b/gui/dpd/__init__.py
index c0c76cc..d006c1c 100644
--- a/gui/dpd/__init__.py
+++ b/gui/dpd/__init__.py
@@ -35,19 +35,31 @@ class DPD:
self.T_U = oversample * 2048 # Inverse of carrier spacing
self.T_C = oversample * 504 # Duration of cyclic prefix
+ self.last_capture_info = {}
+
port = 50055
samples_to_capture = 81920
self.capture = Capture.Capture(self.samplerate, port, samples_to_capture)
+ def status(self):
+ r = {}
+ r['histogram'] = self.capture.bin_histogram()
+ r['capture'] = self.last_capture_info
+ return r
+
def capture_samples(self):
"""Captures samples and store them in the accumulated samples,
returns a string with some info"""
- txframe_aligned, tx_ts, tx_median, rxframe_aligned, rx_ts, rx_median = self.capture.get_samples()
-
- num_acc = self.capture.num_accumulated()
-
- return "Captured {} with median {}/{}, accumulated {} samples".format(
- len(txframe_aligned), tx_median, rx_median, num_acc)
+ try:
+ txframe_aligned, tx_ts, tx_median, rxframe_aligned, rx_ts, rx_median = self.capture.get_samples()
+ self.last_capture_info['length'] = len(txframe_aligned)
+ self.last_capture_info['tx_median'] = tx_median
+ self.last_capture_info['rx_median'] = rx_median
+ self.last_capture_info['tx_ts'] = tx_ts
+ self.last_capture_info['rx_ts'] = rx_ts
+ return "Captured {} samples, tx median {}, rx median {}".format(len(txframe_aligned, tx_median, rx_median))
+ except ValueError as e:
+ return "Error: {}".format(e)
# tx, rx, phase_diff, n_per_bin = extStat.extract(txframe_aligned, rxframe_aligned)
# off = SA.calc_offset(txframe_aligned)
diff --git a/gui/static/js/odr-modulator.js b/gui/static/js/odr-modulator.js
index 9671fb3..273d9f7 100644
--- a/gui/static/js/odr-modulator.js
+++ b/gui/static/js/odr-modulator.js
@@ -64,6 +64,7 @@ function getRc(callback) {
function requestAllParams(callback) {
getRc(function(data) {
$('#windowlength').val(data.guardinterval.windowlen.value);
+ $('#digitalgain').val(data.gain.digital.value);
$('#cfrenable').prop("checked", data.ofdm.cfr.value == 1);
$('#cfrclip').val(data.ofdm.clip.value);
$('#cfrerrorclip').val(data.ofdm.errorclip.value);
@@ -84,6 +85,11 @@ var updateTimer = setInterval(requestStats, 2000);
$(function(){
requestAllParams();
+ $('#setdigitalgain').click(function() {
+ set_rc("gain", "digital", $('#digitalgain').val(),
+ requestAllParams);
+ });
+
$('#setwindowlength').click(function() {
set_rc("guardinterval", "windowlen", $('#windowlength').val(),
requestAllParams);
diff --git a/gui/static/js/odr-predistortion.js b/gui/static/js/odr-predistortion.js
index d385f6c..dce3922 100644
--- a/gui/static/js/odr-predistortion.js
+++ b/gui/static/js/odr-predistortion.js
@@ -40,6 +40,28 @@ $(function(){
},
});
});
+
+ $('#dpdstatusbutton').click(function() {
+ $.ajax({
+ type: "GET",
+ url: "/api/dpd_status",
+ contentType: 'application/json',
+ dataType: '',
+ data: '',
+
+ error: function(data) {
+ $.gritter.add({
+ title: 'DPD Status Update',
+ text: "ERROR",
+ image: '/fonts/warning.png',
+ sticky: true,
+ });
+ },
+ success: function(data) {
+ $('#dpdstatus').val(data);
+ },
+ });
+ });
});
diff --git a/gui/templates/modulator.html b/gui/templates/modulator.html
index 2cd5765..07e7a82 100644
--- a/gui/templates/modulator.html
+++ b/gui/templates/modulator.html
@@ -30,6 +30,14 @@ along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>.
<div class="panel-group">
<div class="panel panel-default">
<div class="panel-body">
+ <h3>Gain</h3>
+ <div class="form-group">
+ <label for="digitalgain">Digital Gain:</label>
+ <input type="text" class="form-control" id="digitalgain">
+ <button type="button" class="btn btn-sm btn-info" id="setdigitalgain">Set</button>
+ </div>
+ </div>
+ <div class="panel-body">
<h3>OFDM Windowing</h3>
<div class="form-group">
<label for="windowlength">Window length:</label>
diff --git a/gui/templates/predistortion.html b/gui/templates/predistortion.html
index 6828f14..ef20a16 100644
--- a/gui/templates/predistortion.html
+++ b/gui/templates/predistortion.html
@@ -37,6 +37,11 @@ along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>.
<button type="button" class="btn btn-sm btn-info" id="capturebutton">Capture</button>
</div>
</div>
+ <div class="panel-body">
+ <h3>Status</h3>
+ <button type="button" class="btn btn-sm btn-info" id="dpdstatusbutton">Update</button>
+ <div id="dpdstatus"></div>
+ </div>
</div>
</div>
</div>