From a0a9742fad8632fc56047602b19242d1ba9562b6 Mon Sep 17 00:00:00 2001 From: Christoph Mayer Date: Tue, 5 Nov 2019 21:25:48 +0100 Subject: [PATCH] STANAG_4539_AppD (intermediate) --- examples/qt_physical_layer.grc | 2 +- examples/test_s4285.grc | 2972 ++------------------- python/physical_layer/CMakeLists.txt | 1 + python/physical_layer/MIL_STD_188_110A.py | 8 +- python/physical_layer/STANAG_4539_AppD.py | 208 ++ python/physical_layer/STANAG_5511.py | 55 +- 6 files changed, 471 insertions(+), 2775 deletions(-) create mode 100644 python/physical_layer/STANAG_4539_AppD.py diff --git a/examples/qt_physical_layer.grc b/examples/qt_physical_layer.grc index e8fcdaa..025bbd4 100644 --- a/examples/qt_physical_layer.grc +++ b/examples/qt_physical_layer.grc @@ -375,7 +375,7 @@ value - 0.005 + 0.01 _enabled diff --git a/examples/test_s4285.grc b/examples/test_s4285.grc index cc27b9e..93cde39 100644 --- a/examples/test_s4285.grc +++ b/examples/test_s4285.grc @@ -1,5 +1,5 @@ - + Fri Oct 19 14:08:05 2018 @@ -10,7 +10,7 @@ window_size - + (1400,700) category @@ -20,10 +20,6 @@ comment - - copyright - - description @@ -62,7 +58,7 @@ realtime_scheduling - + 1 run_command @@ -93,132 +89,6 @@ (0,0) - - variable_qtgui_range - - comment - - - - value - 1536 - - - _enabled - True - - - _coordinate - (970, 5) - - - gui_hint - tab@4:1,0,1,1 - - - _rotation - 0 - - - id - frame_len - - - label - frame length - - - min_len - 200 - - - orient - Qt.Horizontal - - - start - 0 - - - step - 1 - - - stop - 4096 - - - rangeType - int - - - widget - counter_slider - - - - variable_qtgui_range - - comment - - - - value - 4932 - - - _enabled - 0 - - - _coordinate - (1141, 16) - - - gui_hint - (3,0,1,2) - - - _rotation - 0 - - - id - freq - - - label - frequency - - - min_len - 200 - - - orient - Qt.Horizontal - - - start - 0 - - - step - 0.0001 - - - stop - 30e3 - - - rangeType - float - - - widget - counter_slider - - variable_qtgui_chooser @@ -235,7 +105,7 @@ _coordinate - (810, 16) + (633, 16) gui_hint @@ -271,7 +141,7 @@ label - mode + "STANAG4285 mode" labels @@ -318,69 +188,6 @@ combo_box - - variable_qtgui_range - - comment - - - - value - 0.004 - - - _enabled - True - - - _coordinate - (1152, 144) - - - gui_hint - (3,0,1,2) - - - _rotation - 0 - - - id - mu - - - label - mu - - - min_len - 200 - - - orient - Qt.Horizontal - - - start - 0.0001 - - - step - 0.0001 - - - stop - 0.01 - - - rangeType - float - - - widget - counter_slider - - variable @@ -405,7 +212,7 @@ value - 9 + 8 @@ -432,7 +239,7 @@ value - 9 + 8 @@ -459,7 +266,7 @@ value - 3 + 4 @@ -489,6 +296,49 @@ 12000 + + variable_function_probe + + block_id + wavfile_source_block + + + comment + + + + _enabled + 1 + + + function_args + + + + function_name + sample_rate + + + _coordinate + (12, 252) + + + _rotation + 0 + + + id + samp_rate_0 + + + value + 12000 + + + poll_rate + 10 + + variable @@ -520,7 +370,7 @@ analog_agc2_xx attack_rate - 1e-1 + 10e-3 alias @@ -536,15 +386,15 @@ decay_rate - 1e-1 + 10e-3 _enabled - 1 + 2 _coordinate - (480, 154) + (710, 150) _rotation @@ -552,7 +402,7 @@ gain - 5 + 1 id @@ -560,7 +410,7 @@ max_gain - 20 + 50 maxoutbuf @@ -579,186 +429,6 @@ complex - - blocks_add_const_vxx - - alias - - - - comment - - - - const - -0.4 - - - affinity - - - - _enabled - True - - - _coordinate - (256, 634) - - - _rotation - 180 - - - id - blocks_add_const_vxx_0 - - - type - float - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - vlen - 1 - - - - blocks_complex_to_mag - - alias - - - - comment - - - - affinity - - - - _enabled - True - - - _coordinate - (490, 464) - - - _rotation - 180 - - - id - blocks_complex_to_mag_0 - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - vlen - 1 - - - - blocks_complex_to_mag - - alias - - - - comment - - - - affinity - - - - _enabled - True - - - _coordinate - (938, 250) - - - _rotation - 0 - - - id - blocks_complex_to_mag_1 - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - vlen - 1 - - - - blocks_complex_to_magphase - - alias - - - - comment - - - - affinity - - - - _enabled - True - - - _coordinate - (437, 762) - - - _rotation - 180 - - - id - blocks_complex_to_magphase_0 - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - vlen - 1 - - blocks_file_sink @@ -783,11 +453,11 @@ file - /Users/chm/Software/gr-digitalhf/examples/bits.bin + bits.bin _coordinate - (160, 272) + (262, 368) _rotation @@ -803,7 +473,7 @@ unbuffered - False + True vlen @@ -830,7 +500,7 @@ _coordinate - (277, 154) + (256, 188) _rotation @@ -853,57 +523,6 @@ 1 - - blocks_multiply_const_vxx - - alias - - - - comment - - - - const - exp(0.4j) - - - affinity - - - - _enabled - True - - - _coordinate - (645, 608) - - - _rotation - 270 - - - id - blocks_multiply_const_vxx_0 - - - type - complex - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - vlen - 1 - - blocks_null_sink @@ -928,7 +547,54 @@ _coordinate - (277, 805) + (326, 326) + + + _rotation + 180 + + + id + blocks_null_sink_0 + + + type + complex + + + num_inputs + 1 + + + vlen + 1 + + + + blocks_null_sink + + alias + + + + bus_conns + [[0,],] + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (377, 262) _rotation @@ -951,53 +617,6 @@ 1 - - blocks_pdu_to_tagged_stream - - alias - - - - comment - - - - affinity - - - - _enabled - 1 - - - _coordinate - (448, 314) - - - _rotation - 180 - - - id - blocks_pdu_to_tagged_stream_0 - - - type - byte - - - tag - packet_len - - - maxoutbuf - 0 - - - minoutbuf - 0 - - blocks_throttle @@ -1018,7 +637,7 @@ _coordinate - (682, 176) + (889, 179) _rotation @@ -1042,7 +661,7 @@ samples_per_second - samp_rate + samp_rate/5*sps type @@ -1054,7 +673,58 @@ - blocks_vector_to_stream + fractional_resampler_xx + + alias + + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (473, 163) + + + _rotation + 0 + + + id + fractional_resampler_xx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + phase_shift + 0 + + + resamp_ratio + 12001.0/12000*5/sps + + + type + complex + + + + qt_pysical_layer alias @@ -1073,19 +743,19 @@ _coordinate - (757, 250) + (601, 300) + + + gui_hint + _rotation - 0 + 180 id - blocks_vector_to_stream_0 - - - type - complex + qt_pysical_layer_0 maxoutbuf @@ -1096,12 +766,40 @@ 0 - num_items - (1+(nB+nF)*sps) + samp_rate + samp_rate - vlen - 1 + sps + sps + + + physical_layer_type + "STANAG_4285" + + + frame_len_symb + 256 + + + frame_len_bits + 64 + + + physical_layer_mode + mode + + + nB + nB + + + nF + nF + + + nW + nW @@ -1124,11 +822,11 @@ file - /Users/chm/Downloads/3OJp_2.wav + /home/cmayer/Downloads/kphsdr.com_2019-09-10T06_10_22Z_4272.80_iq.wav _coordinate - (21, 154) + (19, 185) _rotation @@ -1136,7 +834,7 @@ id - blocks_wavfile_source_0 + wavfile_source_block maxoutbuf @@ -1155,2276 +853,58 @@ False - - digitalhf_physical_layer_driver - - alias - - - - comment - - - - affinity - - - - description_name - STANAG_4285 - - - _enabled - True - - - _coordinate - (768, 325) - - - _rotation - 180 - - - id - digitalhf_physical_layer_driver_0 - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - sps - sps - - - alpha - 0.1 - - - mode - mode - - - mu - mu - - - nB - nB - - - nF - nF - - - nW - nW - - - samp_rate - samp_rate - - - - import - - alias - - - - comment - - - - _enabled - True - - - _coordinate - (10, 96) - - - _rotation - 0 - - - id - import_0 - - - import - from numpy import exp,pi - - - - qtgui_const_sink_x - - autoscale - False - - - axislabels - True - - - alias - - - - comment - - - - affinity - - - - _enabled - True - - - _coordinate - (373, 549) - - - gui_hint - (2,2,3,2) - - - _rotation - 180 - - - grid - True - - - id - qtgui_const_sink_x_0 - - - legend - False - - - alpha1 - 1 - - - color1 - "blue" - - - label1 - descrambled symbols - - - marker1 - 0 - - - style1 - 0 - - - width1 - 1 - - - alpha10 - 1.0 - - - color10 - "red" - - - label10 - - - - marker10 - 0 - - - style10 - 0 - - - width10 - 1 - - - alpha2 - 1.0 - - - color2 - "red" - - - label2 - - - - marker2 - 0 - - - style2 - 0 - - - width2 - 1 - - - alpha3 - 1.0 - - - color3 - "red" - - - label3 - - - - marker3 - 0 - - - style3 - 0 - - - width3 - 1 - - - alpha4 - 1.0 - - - color4 - "red" - - - label4 - - - - marker4 - 0 - - - style4 - 0 - - - width4 - 1 - - - alpha5 - 1.0 - - - color5 - "red" - - - label5 - - - - marker5 - 0 - - - style5 - 0 - - - width5 - 1 - - - alpha6 - 1.0 - - - color6 - "red" - - - label6 - - - - marker6 - 0 - - - style6 - 0 - - - width6 - 1 - - - alpha7 - 1.0 - - - color7 - "red" - - - label7 - - - - marker7 - 0 - - - style7 - 0 - - - width7 - 1 - - - alpha8 - 1.0 - - - color8 - "red" - - - label8 - - - - marker8 - 0 - - - style8 - 0 - - - width8 - 1 - - - alpha9 - 1.0 - - - color9 - "red" - - - label9 - - - - marker9 - 0 - - - style9 - 0 - - - width9 - 1 - - - name - "" - - - nconnections - 1 - - - size - 1024 - - - tr_chan - 0 - - - tr_level - 0.0 - - - tr_mode - qtgui.TRIG_MODE_FREE - - - tr_slope - qtgui.TRIG_SLOPE_POS - - - tr_tag - "" - - - type - complex - - - update_time - 0.1 - - - xmax - 2 - - - xmin - -2 - - - ymax - 2 - - - ymin - -2 - - - - qtgui_time_raster_sink_x - - axislabels - True - - - alias - - - - comment - - - - affinity - - - - _enabled - True - - - _coordinate - (10, 618) - - - gui_hint - tab@1 - - - _rotation - 180 - - - grid - True - - - id - qtgui_time_raster_sink_x_0 - - - zmax - pi - - - zmin - -pi - - - alpha1 - 1.0 - - - color1 - 0 - - - label1 - arg(symbol) - - - alpha10 - 1.0 - - - color10 - 0 - - - label10 - - - - alpha2 - 1.0 - - - color2 - 0 - - - label2 - - - - alpha3 - 1.0 - - - color3 - 0 - - - label3 - - - - alpha4 - 1.0 - - - color4 - 0 - - - label4 - - - - alpha5 - 1.0 - - - color5 - 0 - - - label5 - - - - alpha6 - 1.0 - - - color6 - 0 - - - label6 - - - - alpha7 - 1.0 - - - color7 - 0 - - - label7 - - - - alpha8 - 1.0 - - - color8 - 0 - - - label8 - - - - alpha9 - 1.0 - - - color9 - 0 - - - label9 - - - - mult - [] - - - name - "arg(descrambled symbol)" - - - ncols - 256 - - - nrows - 100 - - - nconnections - 1 - - - offset - [] - - - samp_rate - samp_rate/sps - - - type - float - - - update_time - 0.10 - - - - qtgui_time_raster_sink_x - - axislabels - True - - - alias - - - - comment - - - - affinity - - - - _enabled - True - - - _coordinate - (1034, 330) - - - gui_hint - tab@3 - - - _rotation - 270 - - - grid - True - - - id - qtgui_time_raster_sink_x_0_0 - - - zmax - .5 - - - zmin - 0 - - - alpha1 - 1.0 - - - color1 - 0 - - - label1 - - - - alpha10 - 1.0 - - - color10 - 0 - - - label10 - - - - alpha2 - 1.0 - - - color2 - 0 - - - label2 - - - - alpha3 - 1.0 - - - color3 - 0 - - - label3 - - - - alpha4 - 1.0 - - - color4 - 0 - - - label4 - - - - alpha5 - 1.0 - - - color5 - 0 - - - label5 - - - - alpha6 - 1.0 - - - color6 - 0 - - - label6 - - - - alpha7 - 1.0 - - - color7 - 0 - - - label7 - - - - alpha8 - 1.0 - - - color8 - 0 - - - label8 - - - - alpha9 - 1.0 - - - color9 - 0 - - - label9 - - - - mult - [] - - - name - "abs(adaptive filter taps)" - - - ncols - (1+(nB+nF)*sps) - - - nrows - 100 - - - nconnections - 1 - - - offset - [] - - - samp_rate - samp_rate - - - type - float - - - update_time - 0.10 - - - - qtgui_time_raster_sink_x - - axislabels - True - - - alias - - - - comment - - - - affinity - - - - _enabled - True - - - _coordinate - (149, 352) - - - gui_hint - tab@4:0,0,1,1 - - - _rotation - 180 - - - grid - True - - - id - qtgui_time_raster_sink_x_0_1 - - - zmax - 1 - - - zmin - 0 - - - alpha1 - 1.0 - - - color1 - 0 - - - label1 - arg(symbol) - - - alpha10 - 1.0 - - - color10 - 0 - - - label10 - - - - alpha2 - 1.0 - - - color2 - 0 - - - label2 - - - - alpha3 - 1.0 - - - color3 - 0 - - - label3 - - - - alpha4 - 1.0 - - - color4 - 0 - - - label4 - - - - alpha5 - 1.0 - - - color5 - 0 - - - label5 - - - - alpha6 - 1.0 - - - color6 - 0 - - - label6 - - - - alpha7 - 1.0 - - - color7 - 0 - - - label7 - - - - alpha8 - 1.0 - - - color8 - 0 - - - label8 - - - - alpha9 - 1.0 - - - color9 - 0 - - - label9 - - - - mult - [] - - - name - "bits" - - - ncols - frame_len - - - nrows - 100 - - - nconnections - 1 - - - offset - [] - - - samp_rate - samp_rate/sps - - - type - byte - - - update_time - 0.10 - - - - qtgui_time_sink_x - - autoscale - False - - - axislabels - True - - - alias - - - - comment - - - - ctrlpanel - False - - - affinity - - - - entags - True - - - _enabled - True - - - _coordinate - (245, 453) - - - gui_hint - (2,0,1,2) - - - _rotation - 180 - - - grid - False - - - id - qtgui_time_sink_x_0 - - - legend - False - - - alpha1 - 1.0 - - - color1 - "blue" - - - label1 - preamble cross-correlation - - - marker1 - -1 - - - style1 - 1 - - - width1 - 1 - - - alpha10 - 1.0 - - - color10 - "blue" - - - label10 - - - - marker10 - -1 - - - style10 - 1 - - - width10 - 1 - - - alpha2 - 1.0 - - - color2 - "red" - - - label2 - rate - - - marker2 - -1 - - - style2 - 1 - - - width2 - 1 - - - alpha3 - 1.0 - - - color3 - "green" - - - label3 - phase - - - marker3 - -1 - - - style3 - 1 - - - width3 - 1 - - - alpha4 - 1.0 - - - color4 - "black" - - - label4 - - - - marker4 - -1 - - - style4 - 1 - - - width4 - 1 - - - alpha5 - 1.0 - - - color5 - "cyan" - - - label5 - - - - marker5 - -1 - - - style5 - 1 - - - width5 - 1 - - - alpha6 - 1.0 - - - color6 - "magenta" - - - label6 - - - - marker6 - -1 - - - style6 - 1 - - - width6 - 1 - - - alpha7 - 1.0 - - - color7 - "yellow" - - - label7 - - - - marker7 - -1 - - - style7 - 1 - - - width7 - 1 - - - alpha8 - 1.0 - - - color8 - "dark red" - - - label8 - - - - marker8 - -1 - - - style8 - 1 - - - width8 - 1 - - - alpha9 - 1.0 - - - color9 - "dark green" - - - label9 - - - - marker9 - -1 - - - style9 - 1 - - - width9 - 1 - - - name - "" - - - nconnections - 1 - - - size - 80*sps - - - srate - samp_rate - - - stemplot - False - - - tr_chan - 0 - - - tr_delay - 0.007 - - - tr_level - 0.0 - - - tr_mode - qtgui.TRIG_MODE_TAG - - - tr_slope - qtgui.TRIG_SLOPE_POS - - - tr_tag - "time_est" - - - type - float - - - update_time - .1 - - - ylabel - preamble correlation - - - yunit - "" - - - ymax - 300 - - - ymin - 0 - - - - qtgui_time_sink_x - - autoscale - False - - - axislabels - True - - - alias - - - - comment - - - - ctrlpanel - False - - - affinity - - - - entags - True - - - _enabled - True - - - _coordinate - (490, 389) - - - gui_hint - tab@2 - - - _rotation - 180 - - - grid - False - - - id - qtgui_time_sink_x_1 - - - legend - False - - - alpha1 - 1.0 - - - color1 - "blue" - - - label1 - - - - marker1 - -1 - - - style1 - 1 - - - width1 - 1 - - - alpha10 - 1.0 - - - color10 - "blue" - - - label10 - - - - marker10 - -1 - - - style10 - 1 - - - width10 - 1 - - - alpha2 - 1.0 - - - color2 - "red" - - - label2 - - - - marker2 - -1 - - - style2 - 1 - - - width2 - 1 - - - alpha3 - 1.0 - - - color3 - "green" - - - label3 - - - - marker3 - -1 - - - style3 - 1 - - - width3 - 1 - - - alpha4 - 1.0 - - - color4 - "black" - - - label4 - - - - marker4 - -1 - - - style4 - 1 - - - width4 - 1 - - - alpha5 - 1.0 - - - color5 - "cyan" - - - label5 - - - - marker5 - -1 - - - style5 - 1 - - - width5 - 1 - - - alpha6 - 1.0 - - - color6 - "magenta" - - - label6 - - - - marker6 - -1 - - - style6 - 1 - - - width6 - 1 - - - alpha7 - 1.0 - - - color7 - "yellow" - - - label7 - - - - marker7 - -1 - - - style7 - 1 - - - width7 - 1 - - - alpha8 - 1.0 - - - color8 - "dark red" - - - label8 - - - - marker8 - -1 - - - style8 - 1 - - - width8 - 1 - - - alpha9 - 1.0 - - - color9 - "dark green" - - - label9 - - - - marker9 - -1 - - - style9 - 1 - - - width9 - 1 - - - name - "" - - - nconnections - 1 - - - size - 1024 - - - srate - samp_rate/sps/2 - - - stemplot - False - - - tr_chan - 0 - - - tr_delay - 0 - - - tr_level - 0.0 - - - tr_mode - qtgui.TRIG_MODE_TAG - - - tr_slope - qtgui.TRIG_SLOPE_POS - - - tr_tag - "packet_len" - - - type - msg_float - - - update_time - 0.10 - - - ylabel - Soft Decision LLR - - - yunit - "" - - - ymax - 7 - - - ymin - -7 - - - - qtgui_waterfall_sink_x - - axislabels - True - - - bw - samp_rate - - - alias - - - - fc - 0 - - - comment - - - - affinity - - - - _enabled - True - - - fftsize - 1024*4 - - - _coordinate - (992, 154) - - - gui_hint - tab@0 - - - _rotation - 0 - - - grid - False - - - id - qtgui_waterfall_sink_x_0 - - - int_max - 10 - - - int_min - -80 - - - legend - True - - - alpha1 - 1.0 - - - color1 - 0 - - - label1 - - - - alpha10 - 1.0 - - - color10 - 0 - - - label10 - - - - alpha2 - 1.0 - - - color2 - 0 - - - label2 - - - - alpha3 - 1.0 - - - color3 - 0 - - - label3 - - - - alpha4 - 1.0 - - - color4 - 0 - - - label4 - - - - alpha5 - 1.0 - - - color5 - 0 - - - label5 - - - - alpha6 - 1.0 - - - color6 - 0 - - - label6 - - - - alpha7 - 1.0 - - - color7 - 0 - - - label7 - - - - alpha8 - 1.0 - - - color8 - 0 - - - label8 - - - - alpha9 - 1.0 - - - color9 - 0 - - - label9 - - - - maxoutbuf - 0 - - - minoutbuf - 0 - - - name - "" - - - nconnections - 1 - - - showports - True - - - freqhalf - True - - - type - complex - - - update_time - 0.10 - - - wintype - firdes.WIN_BLACKMAN_hARRIS - - - - qtgui_tab_widget - - alias - - - - comment - - - - _enabled - True - - - _coordinate - (640, 16) - - - gui_hint - 0,0,2,4 - - - _rotation - 0 - - - id - tab - - - label0 - I/Q Waterfall - - - label1 - Descrambled Symbols - - - label10 - Tab 10 - - - label11 - Tab 11 - - - label12 - Tab 12 - - - label13 - Tab 13 - - - label14 - Tab 14 - - - label15 - Tab 15 - - - label16 - Tab 16 - - - label17 - Tab 17 - - - label18 - Tab 18 - - - label19 - Tab 19 - - - label2 - Soft Decisions - - - label3 - Adaptive Filter Taps - - - label4 - BIt Stream - - - label5 - Tab 5 - - - label6 - Tab 6 - - - label7 - Tab 7 - - - label8 - Tab 8 - - - label9 - Tab 9 - - - num_tabs - 5 - - analog_agc2_xx_0 blocks_throttle_0 0 0 - - blocks_add_const_vxx_0 - qtgui_time_raster_sink_x_0 - 0 - 0 - - - blocks_complex_to_mag_0 - qtgui_time_sink_x_0 - 0 - 0 - - - blocks_complex_to_mag_1 - qtgui_time_raster_sink_x_0_0 - 0 - 0 - - - blocks_complex_to_magphase_0 - blocks_null_sink_1 - 0 - 0 - - - blocks_complex_to_magphase_0 - blocks_add_const_vxx_0 - 1 - 0 - blocks_float_to_complex_0 + fractional_resampler_xx_0 + 0 + 0 + + + blocks_throttle_0 + qt_pysical_layer_0 + 0 + 0 + + + fractional_resampler_xx_0 analog_agc2_xx_0 0 0 - blocks_multiply_const_vxx_0 - blocks_complex_to_magphase_0 - 0 - 0 - - - blocks_pdu_to_tagged_stream_0 + qt_pysical_layer_0 blocks_file_sink_0 0 0 - blocks_pdu_to_tagged_stream_0 - qtgui_time_raster_sink_x_0_1 - 0 + qt_pysical_layer_0 + blocks_null_sink_1 + 2 0 - blocks_throttle_0 - digitalhf_physical_layer_driver_0 - 0 + qt_pysical_layer_0 + blocks_null_sink_0 + 1 0 - blocks_throttle_0 - qtgui_waterfall_sink_x_0 - 0 - 0 - - - blocks_vector_to_stream_0 - blocks_complex_to_mag_1 - 0 - 0 - - - blocks_wavfile_source_0 + wavfile_source_block blocks_float_to_complex_0 0 0 - blocks_wavfile_source_0 + wavfile_source_block blocks_float_to_complex_0 1 1 - - digitalhf_physical_layer_driver_0 - blocks_pdu_to_tagged_stream_0 - bits - pdus - - - digitalhf_physical_layer_driver_0 - blocks_complex_to_mag_0 - 1 - 0 - - - digitalhf_physical_layer_driver_0 - blocks_multiply_const_vxx_0 - 0 - 0 - - - digitalhf_physical_layer_driver_0 - qtgui_const_sink_x_0 - 0 - 0 - - - digitalhf_physical_layer_driver_0 - qtgui_time_sink_x_1 - soft_dec - in - - - digitalhf_physical_layer_driver_0 - blocks_vector_to_stream_0 - 2 - 0 - diff --git a/python/physical_layer/CMakeLists.txt b/python/physical_layer/CMakeLists.txt index d637ce1..8075908 100644 --- a/python/physical_layer/CMakeLists.txt +++ b/python/physical_layer/CMakeLists.txt @@ -39,6 +39,7 @@ GR_PYTHON_INSTALL( MIL_STD_188_110D.py STANAG_5511.py HFDL_ARINC635.py + STANAG_4539_AppD.py DESTINATION ${GR_PYTHON_DIR}/digitalhf/physical_layer ) diff --git a/python/physical_layer/MIL_STD_188_110A.py b/python/physical_layer/MIL_STD_188_110A.py index c9c4512..f24b8ed 100644 --- a/python/physical_layer/MIL_STD_188_110A.py +++ b/python/physical_layer/MIL_STD_188_110A.py @@ -241,8 +241,8 @@ class PhysicalLayer(object): r['success'] = np.bool(np.mean(apks) > 5*np.mean(tpks) and apks[0]/apks[1] > 0.5 and apks[0]/apks[1] < 2.0) if r['success']: idx = np.arange(32*sps) - pks = [np.correlate(iq_samples[imax+i*32*sps+idx], - zp[ i*32*sps+idx])[0] + pks = [np.vdot(zp[ i*32*sps+idx], + iq_samples[imax+i*32*sps+idx]) for i in range(9)] r['doppler'] = common.freq_est(pks)/(32*sps) print('success=', r['success'], 'doppler=', r['doppler'], @@ -259,7 +259,9 @@ class PhysicalLayer(object): print('data=',data) self._pre_counter = sum([(x&3)*(1<<2*y) for (x,y) in zip(data[11:14][::-1], range(3))]) self._d1d2 = data[9:11] - print('MODE:', data[9:11]) + print('MODE:', data[9:11], 'pre_counter=', self._pre_counter) + data[9]=5 + data[10]=5 self._mode = mode = MODE[data[9]][data[10]] self._block_len = 11520 if mode['interleaver'][0] == 'L' else 1440 self._frame_len = mode['known'] + mode['unknown'] diff --git a/python/physical_layer/STANAG_4539_AppD.py b/python/physical_layer/STANAG_4539_AppD.py new file mode 100644 index 0000000..9f4a1aa --- /dev/null +++ b/python/physical_layer/STANAG_4539_AppD.py @@ -0,0 +1,208 @@ +## -*- python -*- + +from __future__ import print_function +import numpy as np +import common + +PREAMBLE = common.n_psk(8, np.array([ 2,6,4,4,6,4,6,2,6,0 # 1 + ,2,2,0,4,6,2,2,0,2,6 # 2 + ,0,6,4,0,2,0,6,6,6,4 # 3 + ,0,6,0,6,2,2,0,4,2,4 # 4 + ,0,2,2,2,2,6,4,6,6,2 # 5 + ,4,6,4,6,2,6,0,2,4,0 # 6 + ,0,0,6,6,2,6,2,2,0,2 # 7 + ,4,4,6,4,6,0,4,0,6,6 # 8 + ,2,2,0,0,6,6,4,0,4,0 # 9 + ,0,6,6,6,4,6,4,6,0,2 # 10 + ,2,6,0,0,0,2,6,2,0,0 # 11 + ,6,2,6,0,4,6,6,4,0,6 # 12 + ,2,6,2,4,4,2,0,6,2,6 # 13 + ,0,0,4,2,4,0,6,0,4,4 # 14 + ,2,2,6,0,2,2,0,6,4,2 # 15 + ,2,4,0,6,0,4,6,4,0,2 # 16 + ,2,0,2,2,2,2,4,4,0,2 # 17 + ,6,2,2,4,6,6,6,2,6,4 # 18 + ,2,0,0,0,2,2,4,0,0,6 # 19 + ,6,4,2,0,0,0,0,2,0,4 # 20 + ,2,2,4])) ## 203 symbols + +## ---- constellatios ----------------------------------------------------------- +BPSK=np.array(zip(np.exp(2j*np.pi*np.arange(2)/2), [0,1]), common.CONST_DTYPE) +QPSK=np.array(zip(np.exp(2j*np.pi*np.arange(4)/4), [0,1,3,2]), common.CONST_DTYPE) +PSK8=np.array(zip(np.exp(2j*np.pi*np.arange(8)/8), [0,1,3,2,6,7,5,4]), common.CONST_DTYPE) + +## ---- constellation indices --------------------------------------------------- +MODE_BPSK=0 +MODE_QPSK=1 +MODE_8PSK=2 + + +## ---- physcal layer class ----------------------------------------------------- +class PhysicalLayer(object): + """Physical layer description for STANAG 4539 Appendix D""" + + def __init__(self, sps): + """intialization""" + self._sps = sps + self._frame_counter = -1 + self._constellations = [BPSK, QPSK, PSK8] + self._preamble = self.get_preamble() + self._mode = {} + self._mode_description = 'UNKNOWN' + + def get_constellations(self): + return self._constellations + + def get_next_frame(self, symbols): + """returns a tuple describing the frame: + [0] ... known+unknown symbols and scrambling + [1] ... modulation type after descrambling + [2] ... a boolean indicating if the processing should continue + [3] ... a boolean indicating if the soft decision for the unknown + symbols are saved""" + print('-------------------- get_frame --------------------', + self._frame_counter, len(symbols)) + success = True + if self._frame_counter == -1: ## preamble mode + if len(symbols) == 0: + return [self._preamble,MODE_BPSK,success,False] + else: + success = self.decode_preamble(symbols) + return [self._preamble,MODE_BPSK,success,False] + # else: ## data mode + # self._frame_counter += 1 + # ##print('test:', symbols[self._mode['unknown']:], np.mean(np.real(symbols[self._mode['unknown']:]))) + # if self._mode['known'] == 0: ## orthogonal WALSH modulation + # success = True + # for i in range(5): + # a = symbols[32*i:32*(i+1)] + # success &= np.max(np.imag(np.mean(a.reshape(8,4),0))) < 0.25 + # elif self._frame_counter < self._num_frames_per_block-2: + # success = np.mean(np.real(symbols[self._mode['unknown']:])) > 0.4 or np.max(np.imag(symbols[self._mode['unknown']:])) < 0.6 + # if not success: + # print('aborting: ', symbols[self._mode['unknown']:])# np.mean(np.real(symbols[self._mode['unknown']:])), + # #np.max(np.imag(symbols[self._mode['unknown']:]))) + # return [self.get_next_data_frame(success),self._mode['ci'],success,success] + + def get_next_data_frame(self, success): + # if self._frame_counter == self._num_frames_per_block: + # self._frame_counter = 0 + # scramble_for_frame = common.n_psk(8, np.array([self._scr_data.next() + # for _ in range(self._frame_len)])) + # a = common.make_scr(scramble_for_frame, scramble_for_frame) + # n_unknown = self._mode['unknown'] + # a['symb'][0:n_unknown] = 0 + # if self._mode['known'] != 0 and self._frame_counter >= self._num_frames_per_block-2: + # idx_d1d2 = self._frame_counter - self._num_frames_per_block + 2; + # a['symb'][n_unknown :n_unknown+ 8] *= common.n_psk(2, WALSH8[self._d1d2[idx_d1d2]][:]) + # a['symb'][n_unknown+8:n_unknown+16] *= common.n_psk(2, WALSH8[self._d1d2[idx_d1d2]][:]) + # if not success: + # self._frame_counter = -1 + # self._pre_counter = -1 + # return a + return False + + def get_doppler(self, iq_samples): + """quality check and doppler estimation for preamble""" + r = {'success': False, ## -- quality flag + 'use_amp_est': False, ##self._frame_counter < 0, + 'doppler': 0} ## -- doppler estimate (rad/symb) + if len(iq_samples) != 0: + sps = self._sps + ## find starting point + _,zp = self.get_preamble_z() + cc = np.correlate(iq_samples, zp[0:40*sps]) + imax = np.argmax(np.abs(cc[0:20*sps])) + print('imax=', imax, len(iq_samples), len(cc)) + apk = np.abs(cc[imax]) + tpk = np.abs(cc[imax+20*sps]) + print('imax=', imax, 'apk=', apk, 'tpk=', tpk) + r['success'] = np.bool(apk > 2*tpk) + if r['success']: + idx = np.arange(40*sps) + pks = [np.vdot(zp[ i*40*sps+idx], + iq_samples[imax+i*40*sps+idx]) + for i in range(4)] + r['doppler'] = common.freq_est(pks)/(40*sps) + print('success=', r['success'], 'doppler=', r['doppler'], + np.abs(np.array(pks)), + np.angle(np.array(pks))) + return r + + def decode_preamble(self, symbols): + print('decode_preamble', symbols) + mean_symb = np.mean(symbols[-40:]) + success = np.real(mean_symb) > 0.6 + print('decode_preamble', mean_symb, success) + return success + # data = [FROM_WALSH8[np.packbits + # (np.real + # (np.sum + # (symbols[i:i+32].reshape((4,8)),0))<0)[0]] + # for i in range(0,15*32,32)] + # print('data=',data) + # self._pre_counter = sum([(x&3)*(1<<2*y) for (x,y) in zip(data[11:14][::-1], range(3))]) + # self._d1d2 = data[9:11] + # print('MODE:', data[9:11]) + # self._mode = mode = MODE[data[9]][data[10]] + # self._block_len = 11520 if mode['interleaver'][0] == 'L' else 1440 + # self._frame_len = mode['known'] + mode['unknown'] + # if mode['known'] == 0: ## orthogonal WALSH modulation + # self._num_frames_per_block = mode['interleaver'][1]*mode['interleaver'][2]/2*32/160 + # else: + # self._num_frames_per_block = self._block_len/self._frame_len + # self._deinterleaver = Deinterleaver(mode['interleaver'][1], mode['interleaver'][2]) + # self._depuncturer = common.Depuncturer(repeat=mode['repeat']) + # self._viterbi_decoder = viterbi27(0x6d, 0x4f) + # self._mode_description = 'MIL_STD_188-110A: (%d,%d) %dbps intl=%s [U=%d,K=%d]' % (data[9],data[10], + # mode['bit_rate'], + # mode['interleaver'][0], + # mode['unknown'], mode['known']) + # print(self._d1d2, mode, self._frame_len, self._mode_description) + + def set_mode(self, _): + pass + + def get_mode(self): + return self._mode_description + + def decode_soft_dec(self, soft_dec): + print('decode_soft_dec', len(soft_dec), soft_dec.dtype) + if self._mode['known'] == 0: ## orthogonal WALSH modulation + n = len(soft_dec) // 32 + soft_bits = np.zeros(2*n, dtype=np.float32) + for i in range(n): + w = np.sum(soft_dec[32*i:32*(i+1)].reshape(4,8),0) + b = FROM_WALSH4[np.packbits(w[0:4]>0)[0]] + print('WALSH', i, w, b) + abs_soft_dec = np.mean(np.abs(w)) + soft_bits[2*i] = abs_soft_dec*(2*(b>>1)-1) + soft_bits[2*i+1] = abs_soft_dec*(2*(b &1)-1) + print('WALSH soft_bits=', soft_bits) + r = self._deinterleaver.load(soft_bits) + else: + r = self._deinterleaver.load(soft_dec) + print('decode_soft_dec r=', r.shape) + if r.shape[0] == 0: + return [],0.0 + ##print('deinterleaved bits: ', [x for x in 1*(r>0)]) + rd = self._depuncturer.process(r) + self._viterbi_decoder.reset() + decoded_bits = self._viterbi_decoder.udpate(rd) + ##print('bits=', decoded_bits) + quality = 100.0*self._viterbi_decoder.quality()/(2*len(decoded_bits)) + print('quality={}%'.format(quality)) + return decoded_bits,quality + + @staticmethod + def get_preamble(): + """preamble symbols + scrambler""" + return common.make_scr(PREAMBLE,PREAMBLE) + def get_preamble_z(self): + """preamble symbols for preamble correlation""" + a = PhysicalLayer.get_preamble() + return 1,np.array([z for z in a['symb'] + for _ in range(self._sps)]) + +if __name__ == '__main__': + print(PREAMBLE) diff --git a/python/physical_layer/STANAG_5511.py b/python/physical_layer/STANAG_5511.py index 126a0b3..a0903d6 100644 --- a/python/physical_layer/STANAG_5511.py +++ b/python/physical_layer/STANAG_5511.py @@ -6,14 +6,13 @@ import common from digitalhf.digitalhf_swig import viterbi27 -## 192 = 6*32 -PREAMBLE=np.array([7,0,3,4,1,1,1,0,2,6,1,5,1,7,0,3,5,4,2,2,6,1,2,2,0,4,5,4,1,2,2,6, - 7,0,7,0,1,1,5,4,2,6,5,1,1,7,4,7,5,4,6,6,6,1,6,6,0,4,1,0,1,2,6,2, - 7,4,7,4,1,5,5,0,2,2,5,5,1,3,4,3,5,0,6,2,6,5,6,2,0,0,1,4,1,6,6,6, - 7,0,3,4,5,5,5,4,2,6,1,5,5,3,4,7,5,4,2,2,2,5,6,6,0,4,5,4,5,6,6,2, - 7,4,3,0,1,5,1,4,2,2,1,1,1,3,0,7,5,0,2,6,6,5,2,6,0,0,5,0,1,6,2,2, - 7,4,3,0,5,1,5,0,2,2,1,1,5,7,4,3,5,0,2,6,2,1,6,2,0,0,5,0,5,2,6,6], - dtype=np.uint8) +## 192 = 6*32 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1 # 32 +PREAMBLE = common.n_psk(8, np.array([7,0,3,4,1,1,1,0,2,6,1,5,1,7,0,3,5,4,2,2,6,1,2,2,0,4,5,4,1,2,2,6, # 1 + 7,0,7,0,1,1,5,4,2,6,5,1,1,7,4,7,5,4,6,6,6,1,6,6,0,4,1,0,1,2,6,2, # 2 + 7,4,7,4,1,5,5,0,2,2,5,5,1,3,4,3,5,0,6,2,6,5,6,2,0,0,1,4,1,6,6,6, # 3 + 7,0,3,4,5,5,5,4,2,6,1,5,5,3,4,7,5,4,2,2,2,5,6,6,0,4,5,4,5,6,6,2, # 4 + 7,4,3,0,1,5,1,4,2,2,1,1,1,3,0,7,5,0,2,6,6,5,2,6,0,0,5,0,1,6,2,2, # 5 + 7,4,3,0,5,1,5,0,2,2,1,1,5,7,4,3,5,0,2,6,2,1,6,2,0,0,5,0,5,2,6,6])) # 6 ## ---- data scrambler ----------------------------------------------------------- class ScrambleData(object): @@ -101,20 +100,23 @@ class PhysicalLayer(object): [1] ... doppler estimate (rad/symbol) if available""" print('-------------------- get_doppler --------------------', self._frame_counter,len(iq_samples)) + r = {'success': False, ## -- quality flag + 'use_amp_est': False, ##self._frame_counter < 0, + 'doppler': 0} ## -- doppler estimate (rad/symb) sps = self._sps _,zp = self.get_preamble_z() wlen = 32 - cc = np.correlate(iq_samples, zp) + cc = np.correlate(iq_samples, zp[0:wlen]) imax = np.argmax(np.abs(cc[0:wlen*sps])) idx = np.arange(wlen*sps) - pks = [np.correlate(iq_samples[imax+i*wlen*sps+idx], - zp[i*wlen*sps+idx])[0] + pks = [np.vdot(zp[ i*wlen*sps+idx], + iq_samples[imax+i*wlen*sps+idx]) for i in range((len(iq_samples)-imax) // (wlen*sps))] print('get_doppler pks: ', pks, np.angle(pks)) - doppler = common.freq_est(pks)/(wlen*sps) - print('get_doppler doppler: ', doppler) - success = True - return success,0*doppler + r['doppler'] = common.freq_est(pks)/(wlen*sps) + print('get_doppler doppler: ', r['doppler']) + r['success'] = True + return r def set_mode(self, mode): pass @@ -125,14 +127,16 @@ class PhysicalLayer(object): deintl_soft_dec = np.zeros(90, dtype=np.float64) deintl_soft_dec[self._intl_idx] = soft_dec print('decode_soft_dec', deintl_soft_dec) + decoded_bits = [] + quality = 0.0 if self._frame_counter == 2: self._viterbi_decoder.reset() decoded_bits = self._viterbi_decoder.udpate(deintl_soft_dec) - print('bits=', decoded_bits) - print('quality={}% ({},{})'.format(100.0*self._viterbi_decoder.quality()/(2*len(decoded_bits)), + quality = 100.0*self._viterbi_decoder.quality()/(2*len(decoded_bits)) + print('bits=', len(decoded_bits), decoded_bits) + print('quality={}% ({},{})'.format(quality, self._viterbi_decoder.quality(), len(decoded_bits))) - return decoded_bits else: depunct_deintl_soft_dec = np.zeros(90//3*4, dtype=np.float64) depunct_deintl_soft_dec[0::4] = deintl_soft_dec[0::3] @@ -141,19 +145,20 @@ class PhysicalLayer(object): depunct_deintl_soft_dec[3::4] = 0 self._viterbi_decoder2.reset() decoded_bits = self._viterbi_decoder2.udpate(depunct_deintl_soft_dec) - print('bits=', decoded_bits) - print('quality={}% ({},{})'.format(100.0*4/3.5*self._viterbi_decoder2.quality()/(2*len(decoded_bits)), + quality = 100.0*4/3.5*self._viterbi_decoder2.quality()/(2*len(decoded_bits)) + print('bits=', len(decoded_bits), decoded_bits) + print('quality={}% ({},{})'.format(quality, self._viterbi_decoder2.quality(), len(decoded_bits))) - return decoded_bits + if quality > 90: + return decoded_bits,quality + else: + return [],0.0 def get_preamble(self): """preamble symbols + scrambler""" - a = np.zeros(len(PREAMBLE), dtype=common.SYMB_SCRAMBLE_DTYPE) - a['symb'] = common.n_psk(8, PREAMBLE) - a['scramble'] = common.n_psk(8, PREAMBLE) - return a + return common.make_scr(PREAMBLE,PREAMBLE) def get_preamble_z(self): """preamble symbols for preamble correlation"""