From b84657174850a86de70acba68d1e4fa2c355541c Mon Sep 17 00:00:00 2001 From: Christoph Mayer Date: Tue, 24 Sep 2019 13:31:22 +0200 Subject: [PATCH] make the current doppler offset estimate available --- python/msg_proxy.py | 9 +++++++-- python/physical_layer/HFDL_ARINC635.py | 21 ++++++++++++++++----- python/physical_layer/MIL_STD_188_110C.py | 1 + python/physical_layer/STANAG_4285.py | 16 +++++++++++++++- python/physical_layer_driver.py | 9 +++++++-- 5 files changed, 46 insertions(+), 10 deletions(-) diff --git a/python/msg_proxy.py b/python/msg_proxy.py index 267eee1..0ae2a23 100644 --- a/python/msg_proxy.py +++ b/python/msg_proxy.py @@ -34,6 +34,7 @@ class msg_proxy(gr.basic_block): out_sig=[]) self._obj = physical_layer_object self._quality = 0.0 + self._doppler = 0.0 self._port_doppler = pmt.intern("doppler") self.message_port_register_in(self._port_doppler) @@ -54,8 +55,9 @@ class msg_proxy(gr.basic_block): def msg_handler_doppler(self, msg_in): ## print('-------------------- msg_handler_doppler --------------------') iq_samples = pmt.to_python(pmt.cdr(msg_in)) - msg_out = pmt.to_pmt(self._obj.get_doppler(iq_samples)) - self.message_port_pub(self._port_doppler, msg_out) + doppler = self._obj.get_doppler(iq_samples) + self._doppler = doppler['doppler'] + self.message_port_pub(self._port_doppler, pmt.to_pmt(doppler)) def msg_handler_frame(self, msg_in): ## print('-------------------- msg_handler_frame --------------------') @@ -82,3 +84,6 @@ class msg_proxy(gr.basic_block): def get_quality(self): return ('%5.1f %%' % self._quality) + + def get_doppler(self): + return self._doppler diff --git a/python/physical_layer/HFDL_ARINC635.py b/python/physical_layer/HFDL_ARINC635.py index d514a1c..332d007 100644 --- a/python/physical_layer/HFDL_ARINC635.py +++ b/python/physical_layer/HFDL_ARINC635.py @@ -105,6 +105,7 @@ class PhysicalLayer(object): self._viterbi_dec = viterbi27(0x6d, 0x4f) self._repeat = 1 self._mode_descr = 'UNKNOWN' + self._fault_counter = 0 def get_constellations(self): return self._constellations @@ -121,6 +122,7 @@ class PhysicalLayer(object): success = True if len(symbols) == 0: self._frame_counter = -1 + self._fault_counter = 0 s = self.get_preamble() s.resize(15+len(s)) s['scramble'][-15:] = 1 @@ -177,12 +179,20 @@ class PhysicalLayer(object): tests = [np.abs(mean_s) > 0.4, np.real(mean_s) > np.imag(mean_s)] print('FRAME_QUALITY: ', s, mean_s, tests) - success = all(tests) + if all(tests): + self._fault_counter -= 1 + else: + self._fault_counter += 1 + self._fault_counter = min(11, max(0, self._fault_counter)) + success = self._fault_counter < 10 + if not success: + self._fault_counter = 0 return success def get_doppler(self, iq_samples): """quality check and doppler estimation for preamble""" r = {'success': False, ## -- quality flag + 'use_amp_est': self._frame_counter < 0, 'doppler': 0} ## -- doppler estimate (rad/symb) if len(iq_samples) != 0: sps = self._sps @@ -215,10 +225,11 @@ class PhysicalLayer(object): tt[0] = np.abs(np.vdot(t, self._preamble['symb'][0:15])) for i in range(1,len(tt)): tt[i] = np.abs(np.vdot(t, np.roll(M1, -SHIFTS[i-1])[0:15])) - print('XXX ', tt) - ii = np.argmax(tt) - ## TODO: add a meaningful QA test - return True,ii + imax = np.argmax(tt) + test = tt[imax] / (np.sum(tt) - tt[imax]) * len(MODES) + success = test > 3 + print('XXX ', test, tt) + return success,imax def set_mode(self, _): pass diff --git a/python/physical_layer/MIL_STD_188_110C.py b/python/physical_layer/MIL_STD_188_110C.py index 48773fb..20a3d92 100644 --- a/python/physical_layer/MIL_STD_188_110C.py +++ b/python/physical_layer/MIL_STD_188_110C.py @@ -309,6 +309,7 @@ class PhysicalLayer(object): def get_doppler(self, iq_samples): """quality check and doppler estimation for preamble""" r = {'success': False, ## -- quality flag + 'use_amp_est': self._frame_counter < 0, 'doppler': 0} ## -- doppler estimate (rad/symb) if len(iq_samples) != 0: sps = self._sps diff --git a/python/physical_layer/STANAG_4285.py b/python/physical_layer/STANAG_4285.py index fbb4fd7..c9113d3 100644 --- a/python/physical_layer/STANAG_4285.py +++ b/python/physical_layer/STANAG_4285.py @@ -52,6 +52,8 @@ class PhysicalLayer(object): self._data = self.get_data() self._viterbi_decoder = viterbi27(0x6d, 0x4f) self._mode_description = None + self._frame_counter = -1 + self._fault_counter = 0 def set_mode(self, mode): """set modulation and interleaver: 'BPS/S' or 'BPS/L'""" @@ -61,6 +63,7 @@ class PhysicalLayer(object): self._deinterleaver = Deinterleaver(DEINTERLEAVER_INCR[intl] * MODES[bps]['deintl_multiple']) self._depuncturer = common.Depuncturer(repeat = MODES[bps]['repeat'], puncture_pattern = MODES[bps]['punct']) + self._fault_counter = 0 def get_mode(self): return self._mode_description @@ -82,8 +85,18 @@ class PhysicalLayer(object): frame_description = [self._preamble,MODE_BPSK,success,False] else: ## current frame is a preamble frame idx = range(30,80) + idx = range(50) z = symbols[idx]*np.conj(self._preamble['symb'][idx]) - success = bool(np.sum(np.real(z)<0) < 30) + mean_z = np.mean(z) + if np.sum(np.real(z)<0) < 30 and np.real(mean_z) > np.abs(np.imag(mean_z)) and np.real(mean_z) > 0.3: + self._fault_counter -= 1 + else: + self._fault_counter += 1 + self._fault_counter = min(11, max(0, self._fault_counter)) + success = self._fault_counter < 10 + if not success: + self._frame_counter = -2 + self._fault_counter = 0 frame_description = [self._data,self._mode,success,True] self._frame_counter += 1 @@ -91,6 +104,7 @@ class PhysicalLayer(object): def get_doppler(self, iq_samples): r = {'success': False, ## -- quality flag + 'use_amp_est': self._frame_counter < 0, 'doppler': 0} ## -- doppler estimate (rad/symb) if len(iq_samples) == 0: return r diff --git a/python/physical_layer_driver.py b/python/physical_layer_driver.py index 2a73df1..7b60e3c 100644 --- a/python/physical_layer_driver.py +++ b/python/physical_layer_driver.py @@ -20,6 +20,7 @@ # import importlib +import math from gnuradio import blocks from gnuradio import digital from gnuradio import filter @@ -46,6 +47,7 @@ class physical_layer_driver(gr.hier_block2): self._nB = nB self._nF = nF self._nW = nW + self._samp_rate = samp_rate m = importlib.import_module('digitalhf.physical_layer.'+description_name) self._physical_layer_driver_description = m.PhysicalLayer(sps) @@ -60,8 +62,8 @@ class physical_layer_driver(gr.hier_block2): self._corr_est = digital.corr_est_cc(symbols = (preamble_samples.tolist()), sps = sps, mark_delay = preamble_offset, - threshold = 0.1, - threshold_method = 1) + threshold = 1-math.exp(-5), + threshold_method = 0) self._doppler_correction = digitalhf.doppler_correction_cc(preamble_length, len(preamble_samples)) self._adaptive_filter = digitalhf.adaptive_dfe(sps, nB, nF, nW, mu, alpha) self._msg_proxy = digitalhf.msg_proxy(self._physical_layer_driver_description) @@ -109,3 +111,6 @@ class physical_layer_driver(gr.hier_block2): def get_mode(self): return self._physical_layer_driver_description.get_mode() + + def get_doppler(self): + return '%+4.1f Hz' % (self._msg_proxy.get_doppler()*self._samp_rate/(2*math.pi))