doppler correction separated from adaptive filtering

* pulse filter, preamble detection, doppler correction, and adaptive filter combined into one hier block
This commit is contained in:
cmayer 2018-11-12 18:28:02 +01:00
parent 9298637d69
commit d25b06a9d7
32 changed files with 1566 additions and 1881 deletions

View File

@ -96,7 +96,7 @@ set(Boost_ADDITIONAL_VERSIONS
"1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64"
"1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69"
)
find_package(Boost "1.35" COMPONENTS filesystem system python numpy)
find_package(Boost "1.35" COMPONENTS filesystem system)
if(NOT Boost_FOUND)
message(FATAL_ERROR "Boost required to compile digitalhf")
@ -178,7 +178,6 @@ include_directories(
${CMAKE_SOURCE_DIR}/include
${CMAKE_BINARY_DIR}/lib
${CMAKE_BINARY_DIR}/include
${PYTHON_INCLUDE_DIR}
${Boost_INCLUDE_DIRS}
${CPPUNIT_INCLUDE_DIRS}
${GNURADIO_ALL_INCLUDE_DIRS}

View File

@ -109,7 +109,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1141, 80)</value>
<value>(810, 16)</value>
</param>
<param>
<key>gui_hint</key>
@ -156,33 +156,6 @@
<value>counter_slider</value>
</param>
</block>
<block>
<key>variable</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(320, 16)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>lpz</value>
</param>
<param>
<key>value</key>
<value>MIL_STD_188_110A.PhysicalLayer.get_preamble_z(sps).tolist()</value>
</param>
</block>
<block>
<key>variable_qtgui_range</key>
<param>
@ -199,7 +172,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1024, 80)</value>
<value>(682, 16)</value>
</param>
<param>
<key>gui_hint</key>
@ -258,7 +231,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(533, 16)</value>
<value>(405, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -285,7 +258,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(608, 16)</value>
<value>(480, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -312,7 +285,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(682, 16)</value>
<value>(565, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -327,49 +300,6 @@
<value>4</value>
</param>
</block>
<block>
<key>variable_rrc_filter_taps</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>1</value>
</param>
<param>
<key>alpha</key>
<value>0.35</value>
</param>
<param>
<key>_coordinate</key>
<value>(469, 352)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>gain</key>
<value>1.0</value>
</param>
<param>
<key>id</key>
<value>rrc_taps</value>
</param>
<param>
<key>ntaps</key>
<value>11*sps</value>
</param>
<param>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
<param>
<key>sym_rate</key>
<value>samp_rate/sps</value>
</param>
</block>
<block>
<key>variable</key>
<param>
@ -409,7 +339,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(458, 16)</value>
<value>(320, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -424,6 +354,69 @@
<value>5</value>
</param>
</block>
<block>
<key>analog_agc2_xx</key>
<param>
<key>attack_rate</key>
<value>1e-1</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>decay_rate</key>
<value>1e-2</value>
</param>
<param>
<key>_enabled</key>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(458, 154)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>gain</key>
<value>5</value>
</param>
<param>
<key>id</key>
<value>analog_agc2_xx_0</value>
</param>
<param>
<key>max_gain</key>
<value>8</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>reference</key>
<value>1.0</value>
</param>
<param>
<key>type</key>
<value>complex</value>
</param>
</block>
<block>
<key>blocks_complex_to_mag</key>
<param>
@ -444,11 +437,11 @@
</param>
<param>
<key>_coordinate</key>
<value>(928, 314)</value>
<value>(426, 368)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>id</key>
@ -483,7 +476,7 @@
</param>
<param>
<key>_enabled</key>
<value>True</value>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
@ -510,57 +503,6 @@
<value>1</value>
</param>
</block>
<block>
<key>blocks_multiply_const_vxx</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>const</key>
<value>5</value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(426, 176)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>blocks_multiply_const_vxx_0</value>
</param>
<param>
<key>type</key>
<value>complex</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>vlen</key>
<value>1</value>
</param>
</block>
<block>
<key>blocks_tag_debug</key>
<param>
@ -585,7 +527,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(917, 133)</value>
<value>(1002, 282)</value>
</param>
<param>
<key>_rotation</key>
@ -636,7 +578,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(586, 176)</value>
<value>(672, 176)</value>
</param>
<param>
<key>_rotation</key>
@ -687,7 +629,7 @@
</param>
<param>
<key>_enabled</key>
<value>True</value>
<value>1</value>
</param>
<param>
<key>file</key>
@ -719,11 +661,11 @@
</param>
<param>
<key>repeat</key>
<value>False</value>
<value>True</value>
</param>
</block>
<block>
<key>digitalhf_adaptive_dfe</key>
<key>digitalhf_physical_layer_driver</key>
<param>
<key>alias</key>
<value></value>
@ -736,21 +678,25 @@
<key>affinity</key>
<value></value>
</param>
<param>
<key>description_name</key>
<value>MIL_STD_188_110A</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(874, 389)</value>
<value>(661, 325)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>id</key>
<value>digitalhf_adaptive_dfe_0</value>
<value>digitalhf_physical_layer_driver_0</value>
</param>
<param>
<key>maxoutbuf</key>
@ -766,11 +712,11 @@
</param>
<param>
<key>alpha</key>
<value>0.0005</value>
<value>0.005</value>
</param>
<param>
<key>mode</key>
<value>''</value>
<value>""</value>
</param>
<param>
<key>mu</key>
@ -789,215 +735,8 @@
<value>nW</value>
</param>
<param>
<key>py_obj_name</key>
<value>MIL_STD_188_110A</value>
</param>
</block>
<block>
<key>fir_filter_xxx</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>decim</key>
<value>1</value>
</param>
<param>
<key>_enabled</key>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(330, 293)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>fir_filter_xxx_0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>samp_delay</key>
<value>0</value>
</param>
<param>
<key>taps</key>
<value>rrc_taps</value>
</param>
<param>
<key>type</key>
<value>ccc</value>
</param>
</block>
<block>
<key>import</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(1034, 21)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>import_0</value>
</param>
<param>
<key>import</key>
<value>import digitalhf.physical_layer.MIL_STD_188_110A as MIL_STD_188_110A</value>
</param>
</block>
<block>
<key>import</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(960, 21)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>import_0_0</value>
</param>
<param>
<key>import</key>
<value>from gnuradio import gr</value>
</param>
</block>
<block>
<key>import</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(810, 32)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>import_1</value>
</param>
<param>
<key>import</key>
<value>import numpy as np</value>
</param>
</block>
<block>
<key>digital_corr_est_cc</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(640, 272)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>preamble</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>sps</key>
<value>sps</value>
</param>
<param>
<key>symbols</key>
<value>lpz</value>
</param>
<param>
<key>mark_delay</key>
<value>nF*sps-2</value>
</param>
<param>
<key>threshold_method</key>
<value>digital.corr_est_cc.THRESHOLD_DYNAMIC</value>
</param>
<param>
<key>threshold</key>
<value>0.35</value>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
</block>
<block>
@ -1028,7 +767,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1109, 410)</value>
<value>(394, 464)</value>
</param>
<param>
<key>gui_hint</key>
@ -1036,7 +775,7 @@
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>grid</key>
@ -1383,7 +1122,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1120, 304)</value>
<value>(181, 357)</value>
</param>
<param>
<key>gui_hint</key>
@ -1391,7 +1130,7 @@
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>grid</key>
@ -1746,11 +1485,11 @@
</param>
<param>
<key>_enabled</key>
<value>True</value>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(1002, 602)</value>
<value>(426, 293)</value>
</param>
<param>
<key>gui_hint</key>
@ -1758,7 +1497,7 @@
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>grid</key>
@ -2117,7 +1856,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1120, 218)</value>
<value>(938, 165)</value>
</param>
<param>
<key>gui_hint</key>
@ -2304,6 +2043,12 @@
<value>firdes.WIN_BLACKMAN_hARRIS</value>
</param>
</block>
<connection>
<source_block_id>analog_agc2_xx_0</source_block_id>
<sink_block_id>blocks_throttle_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_complex_to_mag_0</source_block_id>
<sink_block_id>qtgui_time_sink_x_0</sink_block_id>
@ -2312,19 +2057,19 @@
</connection>
<connection>
<source_block_id>blocks_float_to_complex_0</source_block_id>
<sink_block_id>blocks_multiply_const_vxx_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_multiply_const_vxx_0</source_block_id>
<sink_block_id>blocks_throttle_0</sink_block_id>
<sink_block_id>analog_agc2_xx_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_throttle_0</source_block_id>
<sink_block_id>fir_filter_xxx_0</sink_block_id>
<sink_block_id>digitalhf_physical_layer_driver_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_throttle_0</source_block_id>
<sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
@ -2341,45 +2086,21 @@
<sink_key>1</sink_key>
</connection>
<connection>
<source_block_id>digitalhf_adaptive_dfe_0</source_block_id>
<sink_block_id>qtgui_const_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>digitalhf_adaptive_dfe_0</source_block_id>
<sink_block_id>qtgui_time_sink_x_1</sink_block_id>
<source_key>soft_dec</source_key>
<sink_key>in</sink_key>
</connection>
<connection>
<source_block_id>fir_filter_xxx_0</source_block_id>
<sink_block_id>preamble</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>blocks_complex_to_mag_0</sink_block_id>
<source_key>1</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<sink_block_id>blocks_tag_debug_0</sink_block_id>
<source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>qtgui_const_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<sink_block_id>digitalhf_adaptive_dfe_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
<source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>qtgui_time_sink_x_1</sink_block_id>
<source_key>soft_dec</source_key>
<sink_key>in</sink_key>
</connection>
</flow_graph>

View File

@ -109,7 +109,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1141, 80)</value>
<value>(1141, 240)</value>
</param>
<param>
<key>gui_hint</key>
@ -156,33 +156,6 @@
<value>counter_slider</value>
</param>
</block>
<block>
<key>variable</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(320, 16)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>lpz</value>
</param>
<param>
<key>value</key>
<value>MIL_STD_188_110C.PhysicalLayer.get_preamble_z(sps).tolist()</value>
</param>
</block>
<block>
<key>variable_qtgui_range</key>
<param>
@ -199,7 +172,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1024, 80)</value>
<value>(629, 16)</value>
</param>
<param>
<key>gui_hint</key>
@ -258,7 +231,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(533, 16)</value>
<value>(416, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -285,7 +258,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(608, 16)</value>
<value>(480, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -312,7 +285,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(682, 16)</value>
<value>(554, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -327,49 +300,6 @@
<value>4</value>
</param>
</block>
<block>
<key>variable_rrc_filter_taps</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>1</value>
</param>
<param>
<key>alpha</key>
<value>0.35</value>
</param>
<param>
<key>_coordinate</key>
<value>(469, 352)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>gain</key>
<value>1.0</value>
</param>
<param>
<key>id</key>
<value>rrc_taps</value>
</param>
<param>
<key>ntaps</key>
<value>11*sps</value>
</param>
<param>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
<param>
<key>sym_rate</key>
<value>samp_rate/sps</value>
</param>
</block>
<block>
<key>variable</key>
<param>
@ -409,7 +339,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(458, 16)</value>
<value>(330, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -424,6 +354,69 @@
<value>5</value>
</param>
</block>
<block>
<key>analog_agc2_xx</key>
<param>
<key>attack_rate</key>
<value>.1</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>decay_rate</key>
<value>.01</value>
</param>
<param>
<key>_enabled</key>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(448, 133)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>gain</key>
<value>5</value>
</param>
<param>
<key>id</key>
<value>analog_agc2_xx_0</value>
</param>
<param>
<key>max_gain</key>
<value>8</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>reference</key>
<value>1.0</value>
</param>
<param>
<key>type</key>
<value>complex</value>
</param>
</block>
<block>
<key>blocks_complex_to_mag</key>
<param>
@ -444,11 +437,11 @@
</param>
<param>
<key>_coordinate</key>
<value>(928, 314)</value>
<value>(576, 453)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>id</key>
@ -487,7 +480,7 @@
</param>
<param>
<key>_enabled</key>
<value>True</value>
<value>1</value>
</param>
<param>
<key>file</key>
@ -495,11 +488,11 @@
</param>
<param>
<key>_coordinate</key>
<value>(693, 677)</value>
<value>(277, 293)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>id</key>
@ -534,11 +527,11 @@
</param>
<param>
<key>_enabled</key>
<value>True</value>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(256, 154)</value>
<value>(256, 133)</value>
</param>
<param>
<key>_rotation</key>
@ -561,57 +554,6 @@
<value>1</value>
</param>
</block>
<block>
<key>blocks_multiply_const_vxx</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>const</key>
<value>5</value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(426, 176)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>blocks_multiply_const_vxx_0</value>
</param>
<param>
<key>type</key>
<value>complex</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>vlen</key>
<value>1</value>
</param>
</block>
<block>
<key>blocks_pdu_to_tagged_stream</key>
<param>
@ -628,15 +570,15 @@
</param>
<param>
<key>_enabled</key>
<value>True</value>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(458, 581)</value>
<value>(544, 368)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>id</key>
@ -683,7 +625,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(917, 133)</value>
<value>(1162, 421)</value>
</param>
<param>
<key>_rotation</key>
@ -734,7 +676,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(586, 176)</value>
<value>(661, 154)</value>
</param>
<param>
<key>_rotation</key>
@ -785,7 +727,7 @@
</param>
<param>
<key>_enabled</key>
<value>True</value>
<value>1</value>
</param>
<param>
<key>file</key>
@ -793,7 +735,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(10, 154)</value>
<value>(10, 133)</value>
</param>
<param>
<key>_rotation</key>
@ -817,11 +759,11 @@
</param>
<param>
<key>repeat</key>
<value>True</value>
<value>False</value>
</param>
</block>
<block>
<key>digitalhf_adaptive_dfe</key>
<key>digitalhf_physical_layer_driver</key>
<param>
<key>alias</key>
<value></value>
@ -834,21 +776,25 @@
<key>affinity</key>
<value></value>
</param>
<param>
<key>description_name</key>
<value>MIL_STD_188_110C</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(874, 389)</value>
<value>(821, 400)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>id</key>
<value>digitalhf_adaptive_dfe_0</value>
<value>digitalhf_physical_layer_driver_0</value>
</param>
<param>
<key>maxoutbuf</key>
@ -864,11 +810,11 @@
</param>
<param>
<key>alpha</key>
<value>0.0001</value>
<value>0.005</value>
</param>
<param>
<key>mode</key>
<value>''</value>
<value>""</value>
</param>
<param>
<key>mu</key>
@ -887,215 +833,8 @@
<value>nW</value>
</param>
<param>
<key>py_obj_name</key>
<value>MIL_STD_188_110C</value>
</param>
</block>
<block>
<key>fir_filter_xxx</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>decim</key>
<value>1</value>
</param>
<param>
<key>_enabled</key>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(330, 293)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>fir_filter_xxx_0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>samp_delay</key>
<value>0</value>
</param>
<param>
<key>taps</key>
<value>rrc_taps</value>
</param>
<param>
<key>type</key>
<value>ccc</value>
</param>
</block>
<block>
<key>import</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(1034, 21)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>import_0</value>
</param>
<param>
<key>import</key>
<value>import digitalhf.physical_layer.MIL_STD_188_110C as MIL_STD_188_110C</value>
</param>
</block>
<block>
<key>import</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(960, 21)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>import_0_0</value>
</param>
<param>
<key>import</key>
<value>from gnuradio import gr</value>
</param>
</block>
<block>
<key>import</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(810, 32)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>import_1</value>
</param>
<param>
<key>import</key>
<value>import numpy as np</value>
</param>
</block>
<block>
<key>digital_corr_est_cc</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(640, 272)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>preamble</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>sps</key>
<value>sps</value>
</param>
<param>
<key>symbols</key>
<value>lpz</value>
</param>
<param>
<key>mark_delay</key>
<value>nF*sps-2</value>
</param>
<param>
<key>threshold_method</key>
<value>digital.corr_est_cc.THRESHOLD_DYNAMIC</value>
</param>
<param>
<key>threshold</key>
<value>0.5</value>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
</block>
<block>
@ -1126,7 +865,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1109, 410)</value>
<value>(554, 538)</value>
</param>
<param>
<key>gui_hint</key>
@ -1134,7 +873,7 @@
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>grid</key>
@ -1481,7 +1220,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1120, 304)</value>
<value>(288, 474)</value>
</param>
<param>
<key>gui_hint</key>
@ -1489,7 +1228,7 @@
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>grid</key>
@ -1844,11 +1583,11 @@
</param>
<param>
<key>_enabled</key>
<value>True</value>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(1002, 602)</value>
<value>(298, 378)</value>
</param>
<param>
<key>gui_hint</key>
@ -1856,7 +1595,7 @@
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>grid</key>
@ -2215,7 +1954,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1120, 218)</value>
<value>(1066, 101)</value>
</param>
<param>
<key>gui_hint</key>
@ -2402,6 +2141,12 @@
<value>firdes.WIN_BLACKMAN_hARRIS</value>
</param>
</block>
<connection>
<source_block_id>analog_agc2_xx_0</source_block_id>
<sink_block_id>blocks_throttle_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_complex_to_mag_0</source_block_id>
<sink_block_id>qtgui_time_sink_x_0</sink_block_id>
@ -2410,13 +2155,7 @@
</connection>
<connection>
<source_block_id>blocks_float_to_complex_0</source_block_id>
<sink_block_id>blocks_multiply_const_vxx_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_multiply_const_vxx_0</source_block_id>
<sink_block_id>blocks_throttle_0</sink_block_id>
<sink_block_id>analog_agc2_xx_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
@ -2434,7 +2173,13 @@
</connection>
<connection>
<source_block_id>blocks_throttle_0</source_block_id>
<sink_block_id>fir_filter_xxx_0</sink_block_id>
<sink_block_id>digitalhf_physical_layer_driver_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_throttle_0</source_block_id>
<sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
@ -2451,45 +2196,21 @@
<sink_key>1</sink_key>
</connection>
<connection>
<source_block_id>digitalhf_adaptive_dfe_0</source_block_id>
<sink_block_id>qtgui_const_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>digitalhf_adaptive_dfe_0</source_block_id>
<sink_block_id>blocks_pdu_to_tagged_stream_0</sink_block_id>
<source_key>soft_dec</source_key>
<sink_key>pdus</sink_key>
</connection>
<connection>
<source_block_id>fir_filter_xxx_0</source_block_id>
<sink_block_id>preamble</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>blocks_complex_to_mag_0</sink_block_id>
<source_key>1</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<sink_block_id>blocks_tag_debug_0</sink_block_id>
<source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>qtgui_const_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<sink_block_id>digitalhf_adaptive_dfe_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
<source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>blocks_pdu_to_tagged_stream_0</sink_block_id>
<source_key>soft_dec</source_key>
<sink_key>pdus</sink_key>
</connection>
</flow_graph>

View File

@ -93,33 +93,6 @@
<value>(0,0)</value>
</param>
</block>
<block>
<key>variable</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(757, 16)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>dummy</value>
</param>
<param>
<key>value</key>
<value>[lpz[0].extend(x) for x in lpz[1:]]</value>
</param>
</block>
<block>
<key>variable_qtgui_range</key>
<param>
@ -136,7 +109,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1141, 80)</value>
<value>(1141, 16)</value>
</param>
<param>
<key>gui_hint</key>
@ -183,33 +156,6 @@
<value>counter_slider</value>
</param>
</block>
<block>
<key>variable</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(320, 16)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>lpz</value>
</param>
<param>
<key>value</key>
<value>[[x,x,x,x,x] for x in STANAG_4285.PhysicalLayer.get_preamble()['symb'][9:40].tolist()]</value>
</param>
</block>
<block>
<key>variable_qtgui_chooser</key>
<param>
@ -226,7 +172,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1152, 490)</value>
<value>(1152, 277)</value>
</param>
<param>
<key>gui_hint</key>
@ -325,7 +271,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1024, 80)</value>
<value>(1152, 144)</value>
</param>
<param>
<key>gui_hint</key>
@ -384,7 +330,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(533, 16)</value>
<value>(394, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -411,7 +357,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(608, 16)</value>
<value>(469, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -438,7 +384,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(682, 16)</value>
<value>(544, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -453,49 +399,6 @@
<value>4</value>
</param>
</block>
<block>
<key>variable_rrc_filter_taps</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>alpha</key>
<value>0.25</value>
</param>
<param>
<key>_coordinate</key>
<value>(469, 352)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>gain</key>
<value>1.0</value>
</param>
<param>
<key>id</key>
<value>rrc_taps</value>
</param>
<param>
<key>ntaps</key>
<value>11*sps</value>
</param>
<param>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
<param>
<key>sym_rate</key>
<value>samp_rate/sps</value>
</param>
</block>
<block>
<key>variable</key>
<param>
@ -535,7 +438,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(458, 16)</value>
<value>(320, 16)</value>
</param>
<param>
<key>_rotation</key>
@ -550,6 +453,69 @@
<value>5</value>
</param>
</block>
<block>
<key>analog_agc2_xx</key>
<param>
<key>attack_rate</key>
<value>1e-1</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>decay_rate</key>
<value>1e-2</value>
</param>
<param>
<key>_enabled</key>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(480, 154)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>gain</key>
<value>5</value>
</param>
<param>
<key>id</key>
<value>analog_agc2_xx_0</value>
</param>
<param>
<key>max_gain</key>
<value>8</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>reference</key>
<value>1.0</value>
</param>
<param>
<key>type</key>
<value>complex</value>
</param>
</block>
<block>
<key>blocks_complex_to_mag</key>
<param>
@ -570,11 +536,11 @@
</param>
<param>
<key>_coordinate</key>
<value>(928, 314)</value>
<value>(533, 368)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>id</key>
@ -613,7 +579,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(256, 154)</value>
<value>(277, 154)</value>
</param>
<param>
<key>_rotation</key>
@ -636,57 +602,6 @@
<value>1</value>
</param>
</block>
<block>
<key>blocks_multiply_const_vxx</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>const</key>
<value>5</value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(426, 176)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>blocks_multiply_const_vxx_0</value>
</param>
<param>
<key>type</key>
<value>complex</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>vlen</key>
<value>1</value>
</param>
</block>
<block>
<key>blocks_tag_debug</key>
<param>
@ -711,7 +626,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(917, 133)</value>
<value>(1184, 464)</value>
</param>
<param>
<key>_rotation</key>
@ -762,7 +677,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(586, 176)</value>
<value>(682, 176)</value>
</param>
<param>
<key>_rotation</key>
@ -817,7 +732,7 @@
</param>
<param>
<key>file</key>
<value>/Users/chm/Downloads/kiwi-sm2gct.mooo.com_2018-10-30T10_35_39Z_8700.00_iq.wav</value>
<value>/Users/chm/Software/signal-analysis/gnuradio/20181027T095433Z_6407800_SM2GCT_iq.wav</value>
</param>
<param>
<key>_coordinate</key>
@ -845,11 +760,11 @@
</param>
<param>
<key>repeat</key>
<value>False</value>
<value>True</value>
</param>
</block>
<block>
<key>digitalhf_adaptive_dfe</key>
<key>digitalhf_physical_layer_driver</key>
<param>
<key>alias</key>
<value></value>
@ -862,21 +777,25 @@
<key>affinity</key>
<value></value>
</param>
<param>
<key>description_name</key>
<value>STANAG_4285</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(874, 389)</value>
<value>(736, 314)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>id</key>
<value>digitalhf_adaptive_dfe_0</value>
<value>digitalhf_physical_layer_driver_0</value>
</param>
<param>
<key>maxoutbuf</key>
@ -915,235 +834,8 @@
<value>nW</value>
</param>
<param>
<key>py_obj_name</key>
<value>STANAG_4285</value>
</param>
</block>
<block>
<key>fir_filter_xxx</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>decim</key>
<value>1</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(330, 293)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>fir_filter_xxx_0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>samp_delay</key>
<value>0</value>
</param>
<param>
<key>taps</key>
<value>rrc_taps</value>
</param>
<param>
<key>type</key>
<value>ccc</value>
</param>
</block>
<block>
<key>fractional_resampler_xx</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(96, 293)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>fractional_resampler_xx_0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>phase_shift</key>
<value>0</value>
</param>
<param>
<key>resamp_ratio</key>
<value>12001./11999.*0+1</value>
</param>
<param>
<key>type</key>
<value>complex</value>
</param>
</block>
<block>
<key>import</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(1034, 21)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>import_0</value>
</param>
<param>
<key>import</key>
<value>import digitalhf.physical_layer.STANAG_4285 as STANAG_4285</value>
</param>
</block>
<block>
<key>import</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(960, 21)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>import_0_0</value>
</param>
<param>
<key>import</key>
<value>from gnuradio import gr</value>
</param>
</block>
<block>
<key>digital_corr_est_cc</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(640, 272)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>preamble</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>sps</key>
<value>sps</value>
</param>
<param>
<key>symbols</key>
<value>lpz[0]</value>
</param>
<param>
<key>mark_delay</key>
<value>(nF-9)*sps+2</value>
</param>
<param>
<key>threshold_method</key>
<value>digital.corr_est_cc.THRESHOLD_DYNAMIC</value>
</param>
<param>
<key>threshold</key>
<value>0.5</value>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
</block>
<block>
@ -1174,7 +866,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1109, 410)</value>
<value>(320, 442)</value>
</param>
<param>
<key>gui_hint</key>
@ -1182,7 +874,7 @@
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>grid</key>
@ -1529,7 +1221,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1120, 304)</value>
<value>(320, 357)</value>
</param>
<param>
<key>gui_hint</key>
@ -1537,7 +1229,7 @@
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>grid</key>
@ -1801,7 +1493,7 @@
</param>
<param>
<key>size</key>
<value>1024/2</value>
<value>80*sps</value>
</param>
<param>
<key>srate</key>
@ -1817,7 +1509,7 @@
</param>
<param>
<key>tr_delay</key>
<value>0.01</value>
<value>0.007</value>
</param>
<param>
<key>tr_level</key>
@ -1896,7 +1588,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1002, 602)</value>
<value>(320, 293)</value>
</param>
<param>
<key>gui_hint</key>
@ -1904,7 +1596,7 @@
</param>
<param>
<key>_rotation</key>
<value>0</value>
<value>180</value>
</param>
<param>
<key>grid</key>
@ -2263,7 +1955,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(1120, 218)</value>
<value>(896, 101)</value>
</param>
<param>
<key>gui_hint</key>
@ -2450,6 +2142,12 @@
<value>firdes.WIN_BLACKMAN_hARRIS</value>
</param>
</block>
<connection>
<source_block_id>analog_agc2_xx_0</source_block_id>
<sink_block_id>blocks_throttle_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_complex_to_mag_0</source_block_id>
<sink_block_id>qtgui_time_sink_x_0</sink_block_id>
@ -2458,19 +2156,19 @@
</connection>
<connection>
<source_block_id>blocks_float_to_complex_0</source_block_id>
<sink_block_id>blocks_multiply_const_vxx_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_multiply_const_vxx_0</source_block_id>
<sink_block_id>fractional_resampler_xx_0</sink_block_id>
<sink_block_id>analog_agc2_xx_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_throttle_0</source_block_id>
<sink_block_id>fir_filter_xxx_0</sink_block_id>
<sink_block_id>digitalhf_physical_layer_driver_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_throttle_0</source_block_id>
<sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
@ -2487,51 +2185,21 @@
<sink_key>1</sink_key>
</connection>
<connection>
<source_block_id>digitalhf_adaptive_dfe_0</source_block_id>
<sink_block_id>qtgui_const_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>digitalhf_adaptive_dfe_0</source_block_id>
<sink_block_id>qtgui_time_sink_x_1</sink_block_id>
<source_key>soft_dec</source_key>
<sink_key>in</sink_key>
</connection>
<connection>
<source_block_id>fir_filter_xxx_0</source_block_id>
<sink_block_id>preamble</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>fractional_resampler_xx_0</source_block_id>
<sink_block_id>blocks_throttle_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>blocks_complex_to_mag_0</sink_block_id>
<source_key>1</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<sink_block_id>blocks_tag_debug_0</sink_block_id>
<source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>qtgui_const_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<sink_block_id>digitalhf_adaptive_dfe_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>preamble</source_block_id>
<sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
<source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>qtgui_time_sink_x_1</sink_block_id>
<source_key>soft_dec</source_key>
<sink_key>in</sink_key>
</connection>
</flow_graph>

View File

@ -18,5 +18,8 @@
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
install(FILES
digitalhf_adaptive_dfe.xml DESTINATION share/gnuradio/grc/blocks
digitalhf_adaptive_dfe.xml
digitalhf_physical_layer_driver.xml
digitalhf_doppler_correction_cc.xml
digitalhf_msg_proxy.xml DESTINATION share/gnuradio/grc/blocks
)

View File

@ -4,9 +4,8 @@
<key>digitalhf_adaptive_dfe</key>
<category>[digitalhf]</category>
<import>import digitalhf</import>
<make>digitalhf.adaptive_dfe($sps,$nB,$nF,$nW,$mu,$alpha,$py_obj_name)</make>
<make>digitalhf.adaptive_dfe($sps,$nB,$nF,$nW,$mu,$alpha)</make>
<callback>set_mu($mu)</callback>
<callback>set_mode($mode)</callback>
<!-- Make one 'param' node for every Parameter you want settable from the GUI.
Sub-nodes:
* name
@ -42,16 +41,6 @@
<key>alpha</key>
<type>float</type>
</param>
<param>
<name>py_obj_name</name>
<key>py_obj_name</key>
<type>string</type>
</param>
<param>
<name>mode</name>
<key>mode</key>
<type>string</type>
</param>
<!-- Make one 'sink' node per input. Sub-nodes:
* name (an identifier for the GUI)

View File

@ -0,0 +1,38 @@
<?xml version="1.0"?>
<block>
<name>doppler_correction_cc</name>
<key>digitalhf_doppler_correction_cc</key>
<category>[digitalhf]</category>
<import>import digitalhf</import>
<make>digitalhf.doppler_correction_cc($length)</make>
<!-- Make one 'param' node for every Parameter you want settable from the GUI.
Sub-nodes:
* name
* key (makes the value accessible as $keyname, e.g. in the make node)
* type -->
<param>
<name>...</name>
<key>...</key>
<type>...</type>
</param>
<!-- Make one 'sink' node per input. Sub-nodes:
* name (an identifier for the GUI)
* type
* vlen
* optional (set to 1 for optional inputs) -->
<sink>
<name>in</name>
<type><!-- e.g. int, float, complex, byte, short, xxx_vector, ...--></type>
</sink>
<!-- Make one 'source' node per output. Sub-nodes:
* name (an identifier for the GUI)
* type
* vlen
* optional (set to 1 for optional inputs) -->
<source>
<name>out</name>
<type><!-- e.g. int, float, complex, byte, short, xxx_vector, ...--></type>
</source>
</block>

View File

@ -0,0 +1,38 @@
<?xml version="1.0"?>
<block>
<name>msg_proxy</name>
<key>digitalhf_msg_proxy</key>
<category>[digitalhf]</category>
<import>import digitalhf</import>
<make>digitalhf.msg_proxy($physical_layer_object)</make>
<!-- Make one 'param' node for every Parameter you want settable from the GUI.
Sub-nodes:
* name
* key (makes the value accessible as $keyname, e.g. in the make node)
* type -->
<param>
<name>...</name>
<key>...</key>
<type>...</type>
</param>
<!-- Make one 'sink' node per input. Sub-nodes:
* name (an identifier for the GUI)
* type
* vlen
* optional (set to 1 for optional inputs) -->
<sink>
<name>in</name>
<type><!-- e.g. int, float, complex, byte, short, xxx_vector, ...--></type>
</sink>
<!-- Make one 'source' node per output. Sub-nodes:
* name (an identifier for the GUI)
* type
* vlen
* optional (set to 1 for optional inputs) -->
<source>
<name>out</name>
<type><!-- e.g. int, float, complex, byte, short, xxx_vector, ...--></type>
</source>
</block>

View File

@ -0,0 +1,76 @@
<?xml version="1.0"?>
<block>
<name>physical_layer_driver</name>
<key>digitalhf_physical_layer_driver</key>
<category>[digitalhf]</category>
<import>import digitalhf</import>
<make>digitalhf.physical_layer_driver($samp_rate, $sps, $alpha, $mu, $nB, $nF, $nW, $description_name, $mode)</make>
<callback>set_mu($mu)</callback>
<callback>set_alpha($alpha)</callback>
<callback>set_mode($mode)</callback>
<param>
<name>Description</name>
<key>description_name</key>
<type>string</type>
</param>
<param>
<name>sample rate</name>
<key>samp_rate</key>
<type>int</type>
</param>
<param>
<name>SPS</name>
<key>sps</key>
<type>int</type>
</param>
<param>
<name>nB</name>
<key>nB</key>
<type>int</type>
</param>
<param>
<name>nF</name>
<key>nF</key>
<type>int</type>
</param>
<param>
<name>nW</name>
<key>nW</key>
<type>int</type>
</param>
<param>
<name>mu</name>
<key>mu</key>
<type>float</type>
</param>
<param>
<name>alpha</name>
<key>alpha</key>
<type>float</type>
</param>
<param>
<name>mode</name>
<key>mode</key>
<type>string</type>
</param>
<sink>
<name>in</name>
<type>complex</type>
</sink>
<source>
<name>out_symb</name>
<type>complex</type>
</source>
<source>
<name>out_cc</name>
<type>complex</type>
</source>
<source>
<name>soft_dec</name>
<type>message</type>
<optional>1</optional>
</source>
</block>

View File

@ -23,5 +23,6 @@
########################################################################
install(FILES
api.h
adaptive_dfe.h DESTINATION include/digitalhf
adaptive_dfe.h
doppler_correction_cc.h DESTINATION include/digitalhf
)

View File

@ -50,13 +50,12 @@ class DIGITALHF_API adaptive_dfe : virtual public gr::block
static sptr make(int sps, // samples per symbol
int nB, // number of forward FIR taps
int nF, // number of backward FIR taps
int nW, // number of feedback taps
float mu, //
float alpha, //
std::string physical_layer_description);
int nW, // number of feedback symbol taps
float mu, // mu - decision-feedback equalizer
float alpha); // alpha - decision-feedback equalizer
virtual void set_mu(float) = 0;
virtual void set_mode(std::string) = 0;
virtual void set_alpha(float) = 0;
} ;
} // namespace digitalhf

View File

@ -0,0 +1,58 @@
/* -*- c++ -*- */
/*
* Copyright 2018 hcab14@gmail.com.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DIGITALHF_DOPPLER_CORRECTION_CC_H
#define INCLUDED_DIGITALHF_DOPPLER_CORRECTION_CC_H
#include <digitalhf/api.h>
#include <gnuradio/sync_block.h>
namespace gr {
namespace digitalhf {
/*!
* \brief <+description of block+>
* \ingroup digitalhf
*
*/
class DIGITALHF_API doppler_correction_cc : virtual public gr::sync_block
{
public:
typedef boost::shared_ptr<doppler_correction_cc> sptr;
/*!
* \brief Return a shared_ptr to a new instance of digitalhf::doppler_correction_cc.
*
* To avoid accidental use of raw pointers, digitalhf::doppler_correction_cc's
* constructor is in a private implementation
* class. digitalhf::doppler_correction_cc::make is the public interface for
* creating new instances.
*/
static sptr make(unsigned int preamble_length,
unsigned int preamble_length_cc);
};
} // namespace digitalhf
} // namespace gr
#endif /* INCLUDED_DIGITALHF_DOPPLER_CORRECTION_CC_H */

View File

@ -26,7 +26,8 @@ include(GrPlatform) #define LIB_SUFFIX
include_directories(${Boost_INCLUDE_DIR})
link_directories(${Boost_LIBRARY_DIRS})
list(APPEND digitalhf_sources
adaptive_dfe_impl.cc )
adaptive_dfe_impl.cc
doppler_correction_cc_impl.cc )
set(digitalhf_sources "${digitalhf_sources}" PARENT_SCOPE)
if(NOT digitalhf_sources)
@ -59,6 +60,7 @@ include_directories(${CPPUNIT_INCLUDE_DIRS})
list(APPEND test_digitalhf_sources
${CMAKE_CURRENT_SOURCE_DIR}/test_digitalhf.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_digitalhf.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_doppler_correction_cc.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_adaptive_dfe.cc
)
@ -66,13 +68,11 @@ add_executable(test-digitalhf ${test_digitalhf_sources})
target_link_libraries(
test-digitalhf
${PYTHON_LIBRARIES}
${GNURADIO_RUNTIME_LIBRARIES}
${Boost_LIBRARIES}
${CPPUNIT_LIBRARIES}
gnuradio-digitalhf
)
MESSAGE("XXX ${PYTHON_LIBRARIES}")
GR_ADD_TEST(test_digitalhf test-digitalhf)
########################################################################

View File

@ -39,51 +39,24 @@
namespace gr {
namespace digitalhf {
namespace {
class GILLock {
PyGILState_STATE _state;
public:
GILLock()
:_state(PyGILState_Ensure()) {}
~GILLock() {
PyGILState_Release(_state);
}
} ;
boost::python::numpy::ndarray
complex_vector_to_ndarray(std::vector<gr_complex> const& v) {
return boost::python::numpy::from_data
(&v.front(),
boost::python::numpy::dtype::get_builtin<gr_complex>(),
boost::python::make_tuple(v.size()),
boost::python::make_tuple(sizeof(gr_complex)),
boost::python::object());
}
} // anonymous namespace
adaptive_dfe::sptr
adaptive_dfe::make(int sps, // samples per symbol
int nB, // number of forward FIR taps
int nF, // number of backward FIR taps
int nW, // number of feedback taps
float mu,
float alpha,
std::string python_module_name)
float alpha)
{
return gnuradio::get_initial_sptr
(new adaptive_dfe_impl(sps, nB, nF, nW, mu, alpha, python_module_name));
(new adaptive_dfe_impl(sps, nB, nF, nW, mu, alpha));
}
/*
* The private constructor
*/
adaptive_dfe_impl::adaptive_dfe_impl(int sps, // samples per symbol
int nB, // number of forward FIR taps
int nF, // number of backward FIR taps
int nW, // number of feedback taps
float mu,
float alpha,
std::string python_module_name)
float alpha)
: gr::block("adaptive_dfe",
gr::io_signature::make(1, 1, sizeof(gr_complex)),
gr::io_signature::make(1, 1, sizeof(gr_complex)))
@ -91,63 +64,61 @@ adaptive_dfe_impl::adaptive_dfe_impl(int sps, // samples per symbol
, _nB(nB*sps)
, _nF(nF*sps)
, _nW(nW)
, _nGuard(2*sps)
, _mu(mu)
, _alpha(alpha)
, _use_symbol_taps(true)
, _py_module_name(python_module_name)
, _physicalLayer()
// , _py_module_name(python_module_name)
// , _physicalLayer()
, _taps_samples(nullptr)
, _taps_symbols(nullptr)
, _hist_samples(nullptr)
, _hist_symbols(nullptr)
, _hist_sample_index(0)
, _hist_symbol_index(0)
, _ignore_filter_updates(0)
, _saved_samples()
, _sample_counter(0)
, _constellations()
, _npwr()
, _npwr_counter()
, _npwr_max_time_constant(10)
, _constellation_index()
, _samples()
, _symbols()
, _scramble()
, _descrambled_symbols()
, _symbol_counter(0)
, _need_samples(false)
, _save_soft_decisions(false)
, _vec_soft_decisions()
, _msg_port_name(pmt::mp("soft_dec"))
, _msg_ports{{"soft_dec", pmt::mp("soft_dec")},
{"frame_info", pmt::mp("frame_info")}}
, _msg_metadata(pmt::make_dict())
, _df(0)
, _phase(0)
, _b{0.338187046465954, -0.288839024460507}
, _ud(0)
, _state(WAIT_FOR_PREAMBLE)
{
GR_LOG_DECLARE_LOGPTR(d_logger);
GR_LOG_ASSIGN_LOGPTR(d_logger, "adaptive_dfe");
message_port_register_out(_msg_port_name);
set_history(_nGuard+_nB+1);
message_port_register_out(_msg_ports["soft_dec"]);
pmt::pmt_t constellations_port = pmt::mp("constellations");
message_port_register_in(constellations_port);
set_msg_handler(constellations_port, boost::bind(&adaptive_dfe_impl::update_constellations, this, _1));
pmt::pmt_t frame_info_port = _msg_ports["frame_info"];
message_port_register_in(frame_info_port);
message_port_register_out(frame_info_port);
set_msg_handler(frame_info_port, boost::bind(&adaptive_dfe_impl::update_frame_info, this, _1));
}
/*
* Our virtual destructor.
*/
adaptive_dfe_impl::~adaptive_dfe_impl()
{
_msg_port_name = pmt::PMT_NIL;
_msg_metadata = pmt::PMT_NIL;
_msg_metadata = pmt::PMT_NIL;
VOLK_SAFE_DELETE(_taps_samples);
VOLK_SAFE_DELETE(_taps_symbols);
VOLK_SAFE_DELETE(_hist_samples);
VOLK_SAFE_DELETE(_hist_symbols);
}
void
adaptive_dfe_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
adaptive_dfe_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required)
{
ninput_items_required[0] = _sps*noutput_items;
// [guard | nB | 1 | nF | guard ]
ninput_items_required[0] = _sps*noutput_items + 2*_nGuard + _nB + _nF + 1;
}
int
@ -160,234 +131,102 @@ adaptive_dfe_impl::general_work(int noutput_items,
gr_complex const* in = (gr_complex const *)input_items[0];
gr_complex *out = (gr_complex *)output_items[0];
const int nin = ninput_items[0];
assert(ninput_items[0] >= 2*_nGuard + _nB + _nF + 1);
if (ninput_items[0] < 2*_nGuard + _nB + _nF + 1)
return 0;
int const ninput = ninput_items[0] - _nGuard - _nF;
int nout = 0; // counter for produced output items
int i = 0; // counter for consumed input items
for (; i<ninput_items[0] && nout < noutput_items;) {
assert(nout < noutput_items);
switch (_state) {
case WAIT_FOR_PREAMBLE: {
insert_sample(in[i++]);
uint64_t offset = 0;
float phase_est = 0;
if (get_correlation_tag(i, offset, phase_est)) {
GR_LOG_DEBUG(d_logger, "next state > INITIAL_DOPPLER_ESTIMATE");
_state = INITIAL_DOPPLER_ESTIMATE;
_sample_counter = 0;
switch (_state) {
case WAIT_FOR_PREAMBLE: {
std::vector<tag_t> v;
get_tags_in_window(v, 0, history()-1, ninput, pmt::mp("preamble_start"));
if (v.empty()) {
consume(0, ninput - history()+1);
} else {
tag_t const& tag = v.front();
// uint64_t const offset = tag.offset - nitems_read(0) + history() - 1;
// std::cout << "========= offset= " << offset
// << " tag.offset= " << tag.offset
// << " nitems_read(0)= " << nitems_read(0)
// << " tag.offset-nitems_read(0)= " << tag.offset - nitems_read(0) << " ==========" << std::endl;
// for (int k=0; k<ninput; ++k)
// std::cout << "SAMPLE: " << k << " " << k-int(offset) << " " << k+nitems_read(0) << " " << in[k] << std::endl;
reset_filter();
_descrambled_symbols.clear();
publish_frame_info();
consume(0, tag.offset - nitems_read(0));
_state = WAIT_FOR_FRAME_INFO;
GR_LOG_DEBUG(d_logger, "got preamble tag > wait for frame info");
}
break;
} // WAIT_FOR_PREAMBLE
case WAIT_FOR_FRAME_INFO: {
//update_frame_info(delete_head_blocking(_msg_ports["frame_info"]));
break;
} // WAIT_FOR_MESSAGE
case DO_FILTER: {
// std::cout << "========= offset (DO_FILTER) nitems_read(0)= " << nitems_read(0) << " ==========" << std::endl;
int ninput_processed = 0;
for (int i=history()-1; i<ninput && nout<noutput_items; i+=_sps, ninput_processed+=_sps) {
if (_symbol_counter == _symbols.size()) {
publish_frame_info();
publish_soft_dec();
_symbol_counter = 0;
// _symbols.clear();
// _scramble.clear();
_descrambled_symbols.clear();
// _hist_sample_index = 0;
_hist_symbol_index = 0;
_ignore_filter_updates = 0;
_saved_samples.clear();
std::fill_n(_hist_symbols, 2*_nW, gr_complex(0));
std::fill_n(_taps_samples, _nB+_nF+1, gr_complex(0));
std::fill_n(_taps_symbols, _nW, gr_complex(0));
_use_symbol_taps = true;
_samples.clear();
_phase = -phase_est;
_taps_samples[_nB+1] = 0.01;
_taps_symbols[0] = 1;
GILLock gil_lock;
try {
update_frame_information(_physicalLayer.attr("get_frame")());
} catch (boost::python::error_already_set const&) {
PyErr_Print();
}
}
break;
} // WAIT_FOR_PREAMBLE
case INITIAL_DOPPLER_ESTIMATE: {
_samples.push_back(in[i++]);
// buffer samples and replay them later once the initial doppler estimate is there
if (_samples.size() == _sps * _symbols.size()) {
GILLock gil_lock;
try {
std::vector<gr_complex> const empty_vec;
// initial doppler estimate
if (!update_doppler_information(_physicalLayer.attr("get_doppler")
(complex_vector_to_ndarray(empty_vec),
complex_vector_to_ndarray(_samples)))) {
GR_LOG_DEBUG(d_logger, "next state > WAIT_FOR_PREAMBLE");
_state = WAIT_FOR_PREAMBLE;
break;
}
} catch (boost::python::error_already_set const&) {
PyErr_Print();
}
// (1) correct all samples in the circular buffer with the inital doppler estimate
for (int j=_nB+1; j<_nB+_nF+1; ++j) {
assert(_hist_sample_index+j < 2*(_nB+_nF+1));
_hist_samples[_hist_sample_index+j] *= gr_expj(-_phase);
update_local_oscillator();
}
// (2) insert all buffered samples and run the adaptive filter for them
// instead of pop_front() we first reverse _samples and then insert back() + pop_back()
// O(N) instead of O(N^2)
std::reverse(_samples.begin(), _samples.end());
while (!_samples.empty() && nout < noutput_items) {
insert_sample(_samples.back());
_sample_counter += 1;
_samples.pop_back();
if ((_sample_counter%_sps) == 0)
out[nout++] = filter();
}
if (_samples.empty()) {
GR_LOG_DEBUG(d_logger,"next state > DO_FILTER");
_state = DO_FILTER;
break;
} else {
GR_LOG_DEBUG(d_logger, "next state > INITIAL_DOPPLER_ESTIMATE_CONTINUE");
_state = INITIAL_DOPPLER_ESTIMATE_CONTINUE;
break;
}
}
} // INITIAL_DOPPLER_ESTIMATE_CONTINUE
int const shift = recenter_filter_taps();
if (shift != 0)
ninput_processed += shift;
case INITIAL_DOPPLER_ESTIMATE_CONTINUE: {
GR_LOG_DEBUG(d_logger, "INITIAL_DOPPLER_ESTIMATE_CONTINUE");
while (!_samples.empty() && nout < noutput_items) {
insert_sample(_samples.back());
_sample_counter += 1;
_samples.pop_back();
if ((_sample_counter%_sps) == 0)
out[nout++] = filter();
_state = WAIT_FOR_FRAME_INFO;
break;
}
if (_samples.empty()) {
GR_LOG_DEBUG(d_logger, "next state > DO_FILTER");
_state = DO_FILTER;
} else {
GR_LOG_DEBUG(d_logger, "next state > INITIAL_DOPPLER_ESTIMATE_CONTINUE");
_state = INITIAL_DOPPLER_ESTIMATE_CONTINUE;
}
break;
} // INITIAL_DOPPLER_ESTIMATE_CONTINUE
case DO_FILTER: {
if ((_sample_counter%_sps) == 0) {
if (_symbol_counter == _symbols.size()) { // frame is ready
_symbol_counter = 0;
GILLock gil_lock;
try {
// update doppler estimate
if (!update_doppler_information(_physicalLayer.attr("get_doppler")
(complex_vector_to_ndarray(_descrambled_symbols),
complex_vector_to_ndarray(_samples)))) {
GR_LOG_DEBUG(d_logger, "next state > WAIT_FOR_PREAMBLE");
_state = WAIT_FOR_PREAMBLE;
break;
}
// publish soft decisions
if (!_vec_soft_decisions.empty()) {
std::cout << "soft_dec " << _vec_soft_decisions.size() << "\n";
unsigned int const bits_per_symbol = _constellations[_constellation_index]->bits_per_symbol();
_msg_metadata = pmt::dict_add(_msg_metadata, pmt::mp("bits_per_symbol"), pmt::from_long(bits_per_symbol));
_msg_metadata = pmt::dict_add(_msg_metadata, pmt::mp("packet_len"), pmt::mp(_vec_soft_decisions.size()));
message_port_pub(_msg_port_name,
pmt::cons(_msg_metadata,
pmt::init_f32vector(_vec_soft_decisions.size(), _vec_soft_decisions)));
_vec_soft_decisions.clear();
}
_samples.clear();
// get information about the following frame
update_frame_information(_physicalLayer.attr("get_frame")());
} catch (boost::python::error_already_set const&) {
PyErr_Print();
}
} // frame is ready
if (_ignore_filter_updates == 0) {
out[nout++] = filter();
if (_symbol_counter+1 == _symbols.size())
recenter_filter_taps();
} else {
_ignore_filter_updates -= 1;
}
} // (_sample_counter%_sps) == 0
if (_need_samples) {
_samples.push_back(_hist_samples[_hist_sample_index+_nB+1]);
}
if (_saved_samples.empty()) {
insert_sample(in[i++]);
} else {
insert_sample(_saved_samples.back());
_saved_samples.pop_back();
}
_sample_counter += 1;
} // DO_FILTER
} // switch _state
} // next input sample
consume(0, i);
// Tell runtime system how many output items we produced.
// std::cout << "FILTER_CHECK: " << i << " " << i-1-_nB << " " << i+_nF << " " << in[i] << std::endl;
assert(i+_nF < nin && i-1-_nB >= 0);
out[nout++] = filter(in + i - _nB, in + i + _nF+1);
} // next sample
consume(0, ninput_processed);
break;
} // DO_FILTER
}
return nout;
}
bool adaptive_dfe_impl::start()
{
gr::thread::scoped_lock lock(d_setlock);
// make sure python is ready for threading
if( Py_IsInitialized() ){
GILLock gil_lock;
if(PyEval_ThreadsInitialized() != 1 ){
PyEval_InitThreads();
}
boost::python::numpy::initialize();
} else {
throw std::runtime_error("dont use adaptive_dfe without python!");
}
_taps_samples = (gr_complex*)(volk_malloc( (_nB+_nF+1)*sizeof(gr_complex), volk_get_alignment()));
_taps_symbols = (gr_complex*)(volk_malloc( _nW*sizeof(gr_complex), volk_get_alignment()));
_hist_samples = (gr_complex*)(volk_malloc(2*(_nB+_nF+1)*sizeof(gr_complex), volk_get_alignment()));
_hist_symbols = (gr_complex*)(volk_malloc( 2*_nW*sizeof(gr_complex), volk_get_alignment()));
_samples.clear();
std::fill_n(_hist_samples, 2*(_nB+_nF+1), gr_complex(0));
std::fill_n(_hist_symbols, 2*_nW, gr_complex(0));
std::fill_n(_taps_samples, (_nB+_nF+1), gr_complex(0));
std::fill_n(_taps_symbols, _nW, gr_complex(0));
_taps_samples[_nB+1] = 0.01;
_taps_symbols[0] = 1;
_taps_samples = (gr_complex*)(volk_malloc((_nB+_nF+1)*sizeof(gr_complex), volk_get_alignment()));
_taps_symbols = (gr_complex*)(volk_malloc( _nW*sizeof(gr_complex), volk_get_alignment()));
_hist_symbols = (gr_complex*)(volk_malloc( 2*_nW*sizeof(gr_complex), volk_get_alignment()));
reset_filter();
GR_LOG_DEBUG(d_logger,str(boost::format("adaptive_dfe_impl::start() nB=%d nF=%d mu=%f alpha=%f")
% _nB % _nF % _mu % _alpha));
GILLock gil_lock;
try {
boost::python::object module = boost::python::import(boost::python::str("digitalhf.physical_layer." + _py_module_name));
boost::python::object PhysicalLayer = module.attr("PhysicalLayer");
_physicalLayer = PhysicalLayer(_sps);
update_constellations(_physicalLayer.attr("get_constellations")());
} catch (boost::python::error_already_set const&) {
PyErr_Print();
return false;
}
return true;
}
bool adaptive_dfe_impl::stop()
{
gr::thread::scoped_lock lock(d_setlock);
GR_LOG_DEBUG(d_logger, "adaptive_dfe_impl::stop()");
GILLock gil_lock;
_physicalLayer = boost::python::object();
VOLK_SAFE_DELETE(_taps_samples);
VOLK_SAFE_DELETE(_taps_symbols);
VOLK_SAFE_DELETE(_hist_samples);
VOLK_SAFE_DELETE(_hist_symbols);
return true;
}
gr_complex adaptive_dfe_impl::filter() {
gr_complex adaptive_dfe_impl::filter(gr_complex const* start, gr_complex const* end) {
assert(end-start == _nB + _nF + 1);
gr_complex filter_output = 0;
volk_32fc_x2_dot_prod_32fc(&filter_output,
_hist_samples+_hist_sample_index,
start,
_taps_samples,
_nB+_nF+1);
gr_complex dot_symbols=0;
gr::digital::constellation_sptr constell = _constellations[_constellation_index];
bool const update_taps = constell->bits_per_symbol() <= 3;
bool const update_taps = true;//constell->bits_per_symbol() <= 3;
if (constell->bits_per_symbol() > 3)
_use_symbol_taps = false;
if (_use_symbol_taps) {
@ -397,30 +236,28 @@ gr_complex adaptive_dfe_impl::filter() {
}
filter_output += dot_symbols;
}
assert(_symbol_counter < _symbols.size());
gr_complex known_symbol = _symbols[_symbol_counter];
bool const is_known = std::abs(known_symbol) > 1e-5;
if (not is_known) { // not known
if (not is_known) {
gr_complex const descrambled_filter_output = std::conj(_scramble[_symbol_counter]) * filter_output;
unsigned int jc = constell->decision_maker(&descrambled_filter_output);
unsigned int const jc = constell->decision_maker(&descrambled_filter_output);
gr_complex descrambled_symbol = 0;
constell->map_to_points(jc, &descrambled_symbol);
if (_save_soft_decisions) {
float const err = std::abs(descrambled_filter_output - descrambled_symbol);
_npwr_counter[_constellation_index] += (_npwr_counter[_constellation_index] < _npwr_max_time_constant);
float const alpha = 1.0f/_npwr_counter[_constellation_index];
_npwr[_constellation_index] = (1-alpha)*_npwr[_constellation_index] + alpha*err;
std::vector<float> const soft_dec = constell->calc_soft_dec(descrambled_filter_output, _npwr[_constellation_index]);
std::vector<float> const soft_dec = constell->calc_soft_dec
(descrambled_filter_output, _npwr[_constellation_index].filter(err));
std::copy(soft_dec.begin(), soft_dec.end(), std::back_inserter<std::vector<float> >(_vec_soft_decisions));
}
known_symbol = _scramble[_symbol_counter] * descrambled_symbol;
}
// std::cout << "FILTER: " << filter_output <<" " << known_symbol << " " << start[_nB+1] << std::endl;
if (is_known || update_taps) {
gr_complex const err = filter_output - known_symbol;
for (int j=0; j<_nB+_nF+1; ++j) {
assert(_hist_sample_index+j < 2*(_nB+_nF+1));
_taps_samples[j] -= _mu*err*std::conj(_hist_samples[_hist_sample_index+j]);
}
for (int j=0; j<_nB+_nF+1; ++j)
_taps_samples[j] -= _mu*err*std::conj(start[j]);
if (_use_symbol_taps) {
for (int j=0; j<_nW; ++j) {
assert(_hist_symbol_index+j < 2*_nW);
@ -435,165 +272,98 @@ gr_complex adaptive_dfe_impl::filter() {
return filter_output*std::conj(_scramble[_symbol_counter++]);
}
void adaptive_dfe_impl::recenter_filter_taps() {
int
adaptive_dfe_impl::recenter_filter_taps() {
// get max(abs(taps))
ssize_t const idx_max = std::distance(_taps_samples,
std::max_element(_taps_samples+_nB+1-3*_sps, _taps_samples+_nB+1+3*_sps,
[](gr_complex a, gr_complex b) {
return std::norm(a) < std::norm(b);
}));
GR_LOG_DEBUG(d_logger, str(boost::format("idx_max=%2d abs(tap_max)=%f") % idx_max % std::abs(_taps_samples[idx_max])));
if (idx_max-_nB-1 >= 2*_sps && _saved_samples.empty() && _ignore_filter_updates==0) {
// GR_LOG_DEBUG(d_logger, str(boost::format("idx_max=%2d abs(tap_max)=%f") % idx_max % std::abs(_taps_samples[idx_max])));
if (idx_max-_nB-1 > +2*_sps) {
// maximum is right of the center tap
// -> shift taps to the left left
GR_LOG_DEBUG(d_logger, "shift left");
std::copy(_taps_samples+2*_sps, _taps_samples+_nB+_nF+1, _taps_samples);
std::fill_n(_taps_samples+_nB+_nF+1-2*_sps, 2*_sps, gr_complex(0));
// and omit the next two calls to filter in order to keep the alignment between samples and taps
_ignore_filter_updates = 2;
} else if (idx_max-_nB-1 <= -2*_sps && _saved_samples.empty() && _ignore_filter_updates==0) {
return +2*_sps;
}
if (idx_max-_nB-1 < -2*_sps) {
// maximum is left of the center tap
// -> shift taps to the right
GR_LOG_DEBUG(d_logger, "shift right");
std::copy_backward(_taps_samples, _taps_samples+_nB+_nF+1-2*_sps,
_taps_samples+_nB+_nF+1);
std::fill_n(_taps_samples, 2*_sps, gr_complex(0));
// save the last 2*_sps samples (will be reinserted)
_saved_samples.resize(2*_sps);
std::reverse_copy(_hist_samples+_hist_sample_index+(_nB+_nF+1)-2*_sps,
_hist_samples+_hist_sample_index+(_nB+_nF+1),
_saved_samples.begin());
// shift samples index
_hist_sample_index += (_nB+_nF+1)-2*_sps;
_hist_sample_index %= (_nB+_nF+1);
// set the 1st 2*_sps unknown old samples to zero
for (int l=_hist_sample_index; l<_hist_sample_index+2*_sps; ++l) {
int const k = (l+_nB+_nF+1)%(2*(_nB+_nF+1));
_hist_samples[l] = _hist_samples[k] = gr_complex(0);
}
}
}
void adaptive_dfe_impl::set_mode(std::string mode) {
gr::thread::scoped_lock lock(d_setlock);
GR_LOG_DEBUG(d_logger, "adaptive_dfe_impl::set_mode "+ mode);
GILLock gil_lock;
try {
_physicalLayer.attr("set_mode")(mode);
} catch (boost::python::error_already_set const&) {
PyErr_Print();
return;
return -2*_sps;
}
return 0;
}
void adaptive_dfe_impl::update_constellations(boost::python::object obj)
void adaptive_dfe_impl::reset_filter()
{
int const n = boost::python::extract<int>(obj.attr("__len__")());
std::fill_n(_taps_samples, _nB+_nF+1, gr_complex(0));
std::fill_n(_taps_symbols, _nW, gr_complex(0));
std::fill_n(_hist_symbols, 2*_nW, gr_complex(0));
_taps_samples[_nB+1] = 0.01;
_taps_symbols[0] = 1;
_hist_symbol_index = 0;
}
void adaptive_dfe_impl::publish_frame_info()
{
pmt::pmt_t data = pmt::make_dict();
GR_LOG_DEBUG(d_logger, str(boost::format("publish_frame_info %d == %d") % _descrambled_symbols.size() % _symbols.size()));
data = pmt::dict_add(data, pmt::mp("symbols"), pmt::init_c32vector(_descrambled_symbols.size(), &_descrambled_symbols.front()));
message_port_pub(_msg_ports["frame_info"], data);
_descrambled_symbols.clear();
}
void adaptive_dfe_impl::publish_soft_dec()
{
if (_vec_soft_decisions.empty())
return;
message_port_pub(_msg_ports["soft_dec"],
pmt::cons(pmt::dict_add(_msg_metadata, pmt::mp("packet_len"), pmt::mp(_vec_soft_decisions.size())),
pmt::init_f32vector(_vec_soft_decisions.size(), _vec_soft_decisions)));
_vec_soft_decisions.clear();
}
void adaptive_dfe_impl::update_constellations(pmt::pmt_t data) {
int const n = pmt::length(data);
_constellations.resize(n);
_npwr.resize(n);
_npwr_counter.resize(n);
std::cout << "adaptive_dfe_impl::update_constellations " << data << std::endl;
std::cout << "adaptive_dfe_impl::update_constellations n=" << n << std::endl;
unsigned int const rotational_symmetry = 0;
unsigned int const dimensionality = 1;
for (int i=0; i<n; ++i) {
boost::python::numpy::ndarray const& array = boost::python::numpy::array(obj[i]);
char const* data = array.get_data();
int const m = array.shape(0);
std::vector<gr_complex> constell(m);
std::vector<int> pre_diff_code(m);
for (int j=0; j<m; ++j) {
std::memcpy(&constell[j], data+9*j, sizeof(gr_complex));
pre_diff_code[j] = (data+9*j)[8];
}
unsigned int const rotational_symmetry = 0;
unsigned int const dimensionality = 1;
_constellations[i] = gr::digital::constellation_calcdist::make(constell, pre_diff_code, rotational_symmetry, dimensionality);
_npwr[i] = 0.0f;
_npwr_counter[i] = 0;
pmt::pmt_t c = pmt::vector_ref(data, i);
int const idx = pmt::to_long(pmt::dict_ref(c, pmt::mp("idx"), pmt::from_long(-1)));
assert(idx>=0 && idx < n);
_constellations[idx] = gr::digital::constellation_calcdist::make
(pmt::c32vector_elements(pmt::dict_ref(c, pmt::mp("points"), pmt::PMT_NIL)),
pmt::s32vector_elements(pmt::dict_ref(c, pmt::mp("symbols"), pmt::PMT_NIL)),
rotational_symmetry, dimensionality);
_npwr[i].reset(_npwr_max_time_constant);
}
}
bool adaptive_dfe_impl::update_frame_information(boost::python::object obj)
{
int const n = boost::python::extract<int>(obj.attr("__len__")());
assert(n==4);
boost::python::numpy::ndarray array = boost::python::numpy::array(obj[0]);
char const* data = array.get_data();
int const m = array.shape(0);
_symbols.resize(m);
_scramble.resize(m);
_descrambled_symbols.resize(m);
_samples.clear();
for (int i=0; i<m; ++i) {
std::memcpy(&_symbols[i], data+16*i, sizeof(gr_complex));
std::memcpy(&_scramble[i], data+16*i+8, sizeof(gr_complex));
// std::cout << "get_frame " << i << " " << _symbols[i] << " " << _scramble[i] << std::endl;
}
_constellation_index = boost::python::extract<int> (obj[1]);
_need_samples = boost::python::extract<bool>(obj[2]);
_save_soft_decisions = boost::python::extract<bool>(obj[3]);
return true;
}
bool adaptive_dfe_impl::update_doppler_information(boost::python::object obj)
{
int const n = boost::python::extract<int>(obj.attr("__len__")());
assert(n==2);
bool const do_continue = boost::python::extract<bool>(obj[0]);
if (!do_continue) {
_phase = 0;
_df = 0;
std::fill_n(_hist_samples, 2*(_nB+_nF+1), gr_complex(0));
_hist_sample_index = 0;
_sample_counter = 0;
return false;
}
float const doppler = boost::python::extract<float>(obj[1]);
update_pll(doppler);
return true;
}
void adaptive_dfe_impl::update_pll(float doppler) {
if (doppler == 0)
return;
float const delta_f = doppler/_sps;
if (_df == 0) { // init
_ud = _df = delta_f;
} else {
float const ud_old = _ud;
_ud = delta_f;
_df +=_b[0]*_ud + _b[1]*ud_old;
}
GR_LOG_DEBUG(d_logger, str(boost::format("PLL: df=%f delta_f=%f (rad/sample)") % _df % delta_f));
}
void adaptive_dfe_impl::insert_sample(gr_complex z) {
// insert sample into the circular buffer
_hist_samples[_hist_sample_index] = _hist_samples[_hist_sample_index+_nB+_nF+1] = z * gr_expj(-_phase);
if (++_hist_sample_index == _nB+_nF+1)
_hist_sample_index = 0;
if (z != gr_complex(0))
update_local_oscillator();
}
void adaptive_dfe_impl:: update_local_oscillator() {
_phase += _df;
if (_phase > M_PI)
_phase -= 2*M_PI;
if (_phase < -M_PI)
_phase += 2*M_PI;
}
bool adaptive_dfe_impl::get_correlation_tag(uint64_t i, uint64_t& offset, float& phase_est) {
std::vector<tag_t> v;
get_tags_in_window(v, 0, i,i+1);
for (int j=0; j<v.size(); ++j) {
std::cout << "tag " << v[j].key << " " << v[j].offset-nitems_read(0) << " " << v[j].value << std::endl;
if (v[j].key == pmt::mp("phase_est")) {
phase_est = pmt::to_double(v[j].value);
std::cout << "phase_est " << v[j].offset <<" " << nitems_read(0) << " " << phase_est << std::endl;
offset = v[j].offset - nitems_read(0);
}
if (v[j].key == pmt::mp("corr_est")) {
double const corr_est = pmt::to_double(v[j].value);
if (v[j].offset - nitems_read(0) == offset)// && corr_est > 10e3)
return true;
}
}
return false;
void adaptive_dfe_impl::update_frame_info(pmt::pmt_t data)
{
//GR_LOG_DEBUG(d_logger,str(boost::format("adaptive_dfe_impl::update_frame_info() %s") % data));
_symbols = pmt::c32vector_elements(pmt::dict_ref(data, pmt::mp("symb"), pmt::PMT_NIL));
_scramble = pmt::c32vector_elements(pmt::dict_ref(data, pmt::mp("scramble"), pmt::PMT_NIL));
_constellation_index = pmt::to_long(pmt::dict_ref(data, pmt::mp("constellation_idx"), pmt::PMT_NIL));
_save_soft_decisions = pmt::to_bool(pmt::dict_ref(data, pmt::mp("save_soft_dec"), pmt::PMT_F));
bool const do_continue = pmt::to_bool(pmt::dict_ref(data, pmt::mp("do_continue"), pmt::PMT_F));
assert(_symbols.size() == _scramble.size());
_descrambled_symbols.resize(_symbols.size());
_vec_soft_decisions.clear();
_symbol_counter = 0;
_state = (do_continue ? DO_FILTER : WAIT_FOR_PREAMBLE);
}
} /* namespace digitalhf */

View File

@ -21,18 +21,42 @@
#ifndef INCLUDED_DIGITALHF_ADAPTIVE_DFE_IMPL_H
#define INCLUDED_DIGITALHF_ADAPTIVE_DFE_IMPL_H
#include <boost/python.hpp>
#include <boost/python/numpy.hpp>
#include <gnuradio/digital/constellation.h>
#include <digitalhf/adaptive_dfe.h>
namespace gr {
namespace digitalhf {
class constellation_distance_filter {
public:
constellation_distance_filter(int max_time_constant=10)
: _max_time_constant(max_time_constant)
, _counter(0)
, _pwr(0) {}
void reset(int max_time_constant) {
_max_time_constant = max_time_constant;
_counter = 0;
_pwr = 0;
}
float filter(float x) {
_counter += (_counter < _max_time_constant);
float const alpha = 1.0f/_counter;
_pwr = (1-alpha)*_pwr + alpha*x;
return _pwr;
}
protected:
private:
int _max_time_constant;
int _counter;
float _pwr; // filtered distance to constellation point
} ;
class adaptive_dfe_impl : public adaptive_dfe {
private:
int _sps;
int _nB, _nF, _nW;
int _nGuard;
float _mu;
float _alpha;
@ -40,64 +64,45 @@ private:
bool _use_symbol_taps;
// module name w.r.t. digitalhf.physical_layer containing a PhysicalLayer class
std::string _py_module_name;
boost::python::object _physicalLayer; // class instance of physical layer description
// std::string _py_module_name;
// boost::python::object _physicalLayer; // class instance of physical layer description
gr_complex* _taps_samples;
gr_complex* _taps_symbols;
gr_complex* _hist_samples;
gr_complex* _hist_symbols;
int _hist_sample_index;
int _hist_symbol_index;
int _ignore_filter_updates;
std::vector<gr_complex> _saved_samples;
uint64_t _sample_counter;
std::vector<gr::digital::constellation_sptr> _constellations;
std::vector<float> _npwr;
std::vector<int> _npwr_counter;
std::vector<constellation_distance_filter> _npwr;
int _npwr_max_time_constant;
int _constellation_index;
std::vector<gr_complex> _samples;
std::vector<gr_complex> _symbols;
std::vector<gr_complex> _scramble;
std::vector<gr_complex> _descrambled_symbols;
int _symbol_counter;
bool _need_samples;
bool _save_soft_decisions;
std::vector<float> _vec_soft_decisions;
pmt::pmt_t _msg_port_name;
pmt::pmt_t _msg_metadata;
// PLL for doppler tracking
float _df; // frequency offset in radians per sample
float _phase; // accumulated phase for frequency correction
const float _b[2];
float _ud;
std::map<std::string, pmt::pmt_t> _msg_ports;
pmt::pmt_t _msg_metadata;
enum state {
WAIT_FOR_PREAMBLE,
INITIAL_DOPPLER_ESTIMATE,
INITIAL_DOPPLER_ESTIMATE_CONTINUE,
WAIT_FOR_FRAME_INFO,
DO_FILTER
} _state;
void update_constellations(boost::python::object obj);
bool update_frame_information(boost::python::object obj);
bool update_doppler_information(boost::python::object obj);
// void update_constellations(boost::python::object obj);
void update_constellations(pmt::pmt_t );
void update_frame_info(pmt::pmt_t );
void update_local_oscillator();
gr_complex filter();
void recenter_filter_taps();
gr_complex filter(gr_complex const* start, gr_complex const* end);
int recenter_filter_taps();
void reset_filter();
void insert_sample(gr_complex z);
void update_pll(float doppler);
bool get_correlation_tag(uint64_t i, uint64_t& offset, float& phase_est);
void publish_frame_info();
void publish_soft_dec();
public:
adaptive_dfe_impl(int sps, // samples per symbol
@ -105,8 +110,7 @@ public:
int nF, // number of backward FIR taps
int nW, // number of symbol taps
float mu,
float alpha,
std::string physical_layer_description);
float alpha);
virtual ~adaptive_dfe_impl();
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
@ -120,8 +124,7 @@ public:
gr_vector_void_star &output_items);
virtual void set_mu(float mu) { _mu = mu; }
virtual void set_mode(std::string);
virtual void set_alpha(float alpha) { _alpha = alpha; }
} ;
} // namespace digitalhf

View File

@ -0,0 +1,153 @@
/* -*- c++ -*- */
/*
* Copyright 2018 hcab14@gmail.com.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include <gnuradio/expj.h>
#include <gnuradio/logger.h>
#include "doppler_correction_cc_impl.h"
namespace gr {
namespace digitalhf {
doppler_correction_cc::sptr
doppler_correction_cc::make(unsigned int preamble_length, unsigned int preamble_length_cc)
{
return gnuradio::get_initial_sptr
(new doppler_correction_cc_impl(preamble_length, preamble_length_cc));
}
/*
* The private constructor
*/
doppler_correction_cc_impl::doppler_correction_cc_impl(unsigned int preamble_length,
unsigned int preamble_length_cc)
: gr::sync_block("doppler_correction_cc",
gr::io_signature::make(1, 1, sizeof(gr_complex)),
gr::io_signature::make(1, 1, sizeof(gr_complex)))
, _preamble_length(preamble_length)
, _preamble_length_cc(preamble_length_cc)
, _rotator()
, _state(WAIT_FOR_PHASE_EST_TAG)
, _msg_metadata(pmt::make_dict())
, _port_name(pmt::mp("doppler"))
, _phase_est(0)
{
GR_LOG_DECLARE_LOGPTR(d_logger);
GR_LOG_ASSIGN_LOGPTR(d_logger, "doppler_correction_cc");
message_port_register_out(_port_name);
message_port_register_in (_port_name);
// set_msg_handler(_port_name, boost::bind(&doppler_correction_cc_impl::handle_message, this, _1));
set_tag_propagation_policy(TPP_DONT);
set_output_multiple(2*_preamble_length); // without this the CPU usage goes up to 100%
}
doppler_correction_cc_impl::~doppler_correction_cc_impl()
{
}
void
doppler_correction_cc_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required)
{
ninput_items_required[0] = noutput_items + _preamble_length;
}
void
doppler_correction_cc_impl::handle_message(pmt::pmt_t msg)
{
bool const success = pmt::to_bool(pmt::dict_ref(msg, pmt::mp("success"), pmt::get_PMT_F()));
if (!success) {
// GR_LOG_DEBUG(d_logger, "next state > CONSUME_AND_SKIP success=false");
_state = CONSUME_AND_SKIP;
return;
}
float const doppler = pmt::to_float(pmt::dict_ref(msg, pmt::mp("doppler"), pmt::from_float(0)));
_rotator.set_phase(gr_expj(-_phase_est + 0.5*doppler*_preamble_length_cc));
_rotator.set_phase_incr(gr_expj(-doppler));
// GR_LOG_DEBUG(d_logger, str(boost::format("next state > CONSUME_AND_INSERT_PREAMBLE_TAG phase_est=%f doppler=%f")
// % (_phase_est - 0.5*doppler*_preamble_length_cc)
// % doppler));
_state = CONSUME_AND_INSERT_PREAMBLE_TAG;
}
int
doppler_correction_cc_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
gr_complex const* in = (gr_complex const*)input_items[0];
gr_complex *out = (gr_complex *) output_items[0];
// assert(noutput_items >= _preamble_length);
noutput_items -= _preamble_length;
if (noutput_items < 0)
return 0;
int nout = 0;
switch (_state) {
case WAIT_FOR_PHASE_EST_TAG: {
std::vector<tag_t> v;
get_tags_in_window(v, 0, 0, noutput_items, pmt::mp("phase_est"));
if (v.empty()) {
nout = noutput_items;
} else {
tag_t const& tag = v.front();
uint64_t const offset = tag.offset - nitems_read(0);
nout = offset;
_phase_est = pmt::to_double(tag.value);
_msg_metadata = pmt::dict_add(_msg_metadata, pmt::mp("packet_len"), pmt::from_long(_preamble_length));
message_port_pub(_port_name,
pmt::cons(_msg_metadata,
pmt::init_c32vector(_preamble_length, in+nout)));
// GR_LOG_DEBUG(d_logger, str(boost::format("next state > WAIT_FOR_MSG %lld phase_est=%f") % tag.offset % _phase_est));
_state = WAIT_FOR_MSG;
}
break;
} // WAIT_FOR_PHASE_EST_TAG
case WAIT_FOR_MSG: {
// GR_LOG_DEBUG(d_logger, "WAIT_FOR_MSG");
handle_message(delete_head_blocking(_port_name));
break;
} // WAIT_FOR_MSG
case CONSUME_AND_INSERT_PREAMBLE_TAG: {
add_item_tag(0, nitems_read(0), pmt::mp("preamble_start"), pmt::from_long(0));
nout = _preamble_length;
// GR_LOG_DEBUG(d_logger, str(boost::format("next state > WAIT_FOR_PHASE_EST_TAG %lld") % nitems_read(0)));
_state = WAIT_FOR_PHASE_EST_TAG;
break;
} // CONSUME_AND_INSERT_PREAMBLE_TAG
case CONSUME_AND_SKIP: {
nout = _preamble_length;
// GR_LOG_DEBUG(d_logger, str(boost::format("next state > WAIT_FOR_PHASE_EST_TAG %lld") % nitems_read(0)));
_state = WAIT_FOR_PHASE_EST_TAG;
break;
} // CONSUME_AND_SKIP
}
// apply current doppler correction to all produced samples
_rotator.rotateN(out, in, nout);
// Tell runtime system how many output items we produced.
return nout;
}
} /* namespace digitalhf */
} /* namespace gr */

View File

@ -0,0 +1,65 @@
/* -*- c++ -*- */
/*
* Copyright 2018 hcab14@gmail.com.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DIGITALHF_DOPPLER_CORRECTION_CC_IMPL_H
#define INCLUDED_DIGITALHF_DOPPLER_CORRECTION_CC_IMPL_H
#include <gnuradio/blocks/rotator.h>
#include <digitalhf/doppler_correction_cc.h>
namespace gr {
namespace digitalhf {
class doppler_correction_cc_impl : public doppler_correction_cc
{
private:
unsigned int _preamble_length; // length of preamble (in samples)
unsigned int _preamble_length_cc; // length of the part of the preamble used for cross correlation (in samples)
blocks::rotator _rotator;
enum {
WAIT_FOR_PHASE_EST_TAG, // wait for a tag from corr_est_cc
WAIT_FOR_MSG, // wait for response from msg_proxy
CONSUME_AND_INSERT_PREAMBLE_TAG, // insert a preamble tag (=doppler calculation was successful)
CONSUME_AND_SKIP // do not intsert a tag and skip the samples (=doppler calculation was not successful)
} _state;
pmt::pmt_t _msg_metadata;
pmt::pmt_t _port_name;
float _phase_est;
public:
doppler_correction_cc_impl(unsigned int preamble_length, unsigned int preamble_length_cc);
virtual ~doppler_correction_cc_impl();
void forecast(int noutput_items, gr_vector_int &ninput_items_required);
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
protected:
void handle_message(pmt::pmt_t msg);
};
} // namespace digitalhf
} // namespace gr
#endif /* INCLUDED_DIGITALHF_DOPPLER_CORRECTION_CC_IMPL_H */

View File

@ -28,12 +28,14 @@
#include "qa_digitalhf.h"
#include "qa_adaptive_dfe.h"
#include "qa_doppler_correction_cc.h"
CppUnit::TestSuite *
qa_digitalhf::suite()
{
CppUnit::TestSuite *s = new CppUnit::TestSuite("digitalhf");
s->addTest(gr::digitalhf::qa_adaptive_dfe::suite());
s->addTest(gr::digitalhf::qa_doppler_correction_cc::suite());
return s;
}

View File

@ -0,0 +1,37 @@
/* -*- c++ -*- */
/*
* Copyright 2018 hcab14@gmail.com.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <gnuradio/attributes.h>
#include <cppunit/TestAssert.h>
#include "qa_doppler_correction_cc.h"
#include <digitalhf/doppler_correction_cc.h>
namespace gr {
namespace digitalhf {
void
qa_doppler_correction_cc::t1()
{
// Put test here
}
} /* namespace digitalhf */
} /* namespace gr */

View File

@ -0,0 +1,46 @@
/* -*- c++ -*- */
/*
* Copyright 2018 hcab14@gmail.com.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef _QA_DOPPLER_CORRECTION_CC_H_
#define _QA_DOPPLER_CORRECTION_CC_H_
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
namespace gr {
namespace digitalhf {
class qa_doppler_correction_cc : public CppUnit::TestCase
{
public:
CPPUNIT_TEST_SUITE(qa_doppler_correction_cc);
CPPUNIT_TEST(t1);
CPPUNIT_TEST_SUITE_END();
private:
void t1();
};
} /* namespace digitalhf */
} /* namespace gr */
#endif /* _QA_DOPPLER_CORRECTION_CC_H_ */

View File

@ -32,7 +32,8 @@ endif()
GR_PYTHON_INSTALL(
FILES
__init__.py
DESTINATION ${GR_PYTHON_DIR}/digitalhf
physical_layer_driver.py
msg_proxy.py DESTINATION ${GR_PYTHON_DIR}/digitalhf
)
########################################################################
@ -45,3 +46,6 @@ set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig)
GR_ADD_TEST(qa_adaptive_dfe ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_adaptive_dfe.py)
add_subdirectory(physical_layer)
GR_ADD_TEST(qa_physical_layer_driver_driver ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_physical_layer_driver_driver.py)
GR_ADD_TEST(qa_doppler_correction_cc ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_doppler_correction_cc.py)
GR_ADD_TEST(qa_msg_proxy ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_msg_proxy.py)

View File

@ -31,4 +31,6 @@ except ImportError:
pass
# import any pure python here
from physical_layer_driver import physical_layer_driver
from msg_proxy import msg_proxy
#

70
python/msg_proxy.py Normal file
View File

@ -0,0 +1,70 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2018 hcab14@gmail.com.
#
# This is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this software; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
import numpy as np
from gnuradio import gr
import pmt
class msg_proxy(gr.basic_block):
"""
docstring for block msg_proxy
"""
def __init__(self, physical_layer_object):
gr.basic_block.__init__(self,
name="msg_proxy",
in_sig=[],
out_sig=[])
self._obj = physical_layer_object
self._port_doppler = pmt.intern("doppler")
self.message_port_register_in(self._port_doppler)
self.message_port_register_out(self._port_doppler)
self.set_msg_handler(self._port_doppler, self.msg_handler_doppler)
self._port_frame_info = pmt.intern("frame_info")
self.message_port_register_in(self._port_frame_info)
self.message_port_register_out(self._port_frame_info)
self.set_msg_handler(self._port_frame_info, self.msg_handler_frame)
def msg_handler_doppler(self, msg_in):
## print('-------------------- msg_handler_doppler --------------------')
iq_samples = pmt.to_python(pmt.cdr(msg_in))
success,doppler = self._obj.get_doppler(iq_samples)
msg_out = pmt.make_dict()
msg_out = pmt.dict_add(msg_out, pmt.intern('success'), pmt.to_pmt(success))
msg_out = pmt.dict_add(msg_out, pmt.intern('doppler'), pmt.to_pmt(doppler))
## print(msg_out)
self.message_port_pub(self._port_doppler, msg_out)
def msg_handler_frame(self, msg_in):
## print('-------------------- msg_handler_frame --------------------')
## print(msg_in)
symbols = pmt.to_python(pmt.dict_ref(msg_in, pmt.intern('symbols'), pmt.PMT_NIL))
symb,constellation_idx,do_continue,save_soft_dec = self._obj.get_next_frame(symbols)
##print('symb=', symb, symb['symb'], symb['scramble'])
msg_out = pmt.make_dict()
msg_out = pmt.dict_add(msg_out, pmt.intern('symb'), pmt.to_pmt(symb['symb']))
msg_out = pmt.dict_add(msg_out, pmt.intern('scramble'), pmt.to_pmt(symb['scramble']))
msg_out = pmt.dict_add(msg_out, pmt.intern('constellation_idx'), pmt.to_pmt(constellation_idx))
msg_out = pmt.dict_add(msg_out, pmt.intern('do_continue'), pmt.to_pmt(do_continue))
msg_out = pmt.dict_add(msg_out, pmt.intern('save_soft_dec'), pmt.to_pmt(save_soft_dec))
## print(msg_out)
self.message_port_pub(self._port_frame_info, msg_out)

View File

@ -114,20 +114,35 @@ class PhysicalLayer(object):
def get_constellations(self):
return self._constellations
def get_frame(self):
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 whethere or not raw IQ samples needed
[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._pre_counter, self._frame_counter)
## --- preamble frame ----
if self._pre_counter != 0:
self._scr_data.reset()
return [self._preamble,MODE_BPSK,True,False]
## ----- data frame ------
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)
if self._pre_counter != 0:
return [self._preamble,MODE_BPSK,success,False]
else:
self._frame_counter = 0
self._scr_data.reset()
return [self.get_next_data_frame(success),self._mode['ci'],success,success]
else: ## data mode
self._frame_counter += 1
print('test:', symbols[self._mode['unknown']:], np.mean(np.real(symbols[self._mode['unknown']:])))
if self._frame_counter < self._num_frames_per_block-2:
success = np.bool(np.mean(np.real(symbols[self._mode['unknown']:])) > 0.7)
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 = n_psk(8, np.array([self._scr_data.next()
@ -142,34 +157,12 @@ class PhysicalLayer(object):
idx_d1d2 = self._frame_counter - self._num_frames_per_block + 2;
a['symb'][n_unknown :n_unknown+ 8] *= n_psk(2, WALSH[self._d1d2[idx_d1d2]][:])
a['symb'][n_unknown+8:n_unknown+16] *= n_psk(2, WALSH[self._d1d2[idx_d1d2]][:])
if not success:
self._frame_counter = -1
self._pre_counter = -1
return a
self._frame_counter += 1
return [a, self._mode['ci'],False,True]
def get_doppler(self, symbols, iq_samples):
"""returns a tuple
[0] ... quality flag
[1] ... doppler estimate (rad/symbol) if available"""
print('-------------------- get_doppler --------------------',
self._frame_counter,len(symbols),len(iq_samples))
success,doppler = False,0
if self._frame_counter == -1: ## -- preamble ----
success,doppler = self.get_doppler_from_preamble(symbols, iq_samples)
if len(symbols) != 0:
success = self.decode_preamble(symbols)
if self._pre_counter == 0:
self._frame_counter = 0
print('pre_counter', self._pre_counter,
'mode', self._mode)
else: ## ------------------------ data frame ----
print(self._frame_counter,symbols, np.mean(np.abs(symbols)))
success = np.mean(np.abs(symbols[0:20])) > 0.5
if not success:
self._frame_counter = -1
self._pre_counter = -1
return success,doppler
def get_doppler_from_preamble(self, symbols, iq_samples):
def get_doppler(self, iq_samples):
"""quality check and doppler estimation for preamble"""
success,doppler = True,0
if len(iq_samples) != 0:
@ -177,21 +170,25 @@ class PhysicalLayer(object):
zp = np.array([z for z in PhysicalLayer.get_preamble()['symb']
for _ in range(sps)], dtype=np.complex64)
## find starting point
cc = np.correlate(iq_samples, zp[0:3*32*sps])
_,_zp = self.get_preamble_z()
cc = np.correlate(iq_samples, _zp) ##zp[0:3*32*sps])
imax = np.argmax(np.abs(cc[0:2*32*sps]))
pks = cc[(imax, imax+3*32*sps),]
tpks = cc[imax+3*16*sps:imax+5*16*sps]
print('imax=', imax, 'apks=',np.abs(pks),
np.mean(np.abs(pks)), np.mean(np.abs(tpks)), np.abs(tpks))
success = np.mean(np.abs(pks)) > 2*np.mean(np.abs(tpks))
doppler = np.diff(np.unwrap(np.angle(pks)))[0]/(3*32) if success else 0
apks = np.abs(cc[(imax, imax+3*32*sps),])
tpks = np.abs(cc[imax+3*16*sps:imax+5*16*sps])
print('imax=', imax, 'apks=',apks,
np.mean(apks), np.mean(tpks))
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 success:
idx = np.arange(32*sps)
pks = [np.correlate(iq_samples[imax+i*32*sps+idx],
zp[i*32*sps+idx])[0]
zp[ i*32*sps+idx])[0]
for i in range(9)]
doppler = freq_est(pks)/32
print('success=', success, 'doppler=', doppler)
doppler = freq_est(pks)/(32*sps)
print('success=', success, 'doppler=', doppler,
np.abs(np.array(pks)),
np.angle(np.array(pks)))
return success,doppler
def decode_preamble(self, symbols):
@ -209,6 +206,9 @@ class PhysicalLayer(object):
self._num_frames_per_block = self._block_len/self._frame_len;
return True
def set_mode(self, _):
pass
@staticmethod
def get_preamble():
"""preamble symbols + scrambler"""
@ -217,12 +217,11 @@ class PhysicalLayer(object):
dtype=[('symb', np.complex64),
('scramble', np.complex64)])
@staticmethod
def get_preamble_z(sps):
def get_preamble_z(self):
"""preamble symbols for preamble correlation"""
a = PhysicalLayer.get_preamble()
return np.array([z for z in a['symb'][0:32*3]
for _ in range(sps)])
return 0,np.array([z for z in a['symb'][0:3*32]
for _ in range(self._sps)])
if __name__ == '__main__':
def gen_data_scramble():
@ -238,20 +237,23 @@ if __name__ == '__main__':
a[i] = s&7;
return a
p=PhysicalLayer(5)
z1=np.array([x for x in PRE_SYMBOLS for _ in range(5)])
z2=np.array([x for x in PRE_SCRAMBLE for _ in range(5)])
z=z1*z2
sps = 5;
p=PhysicalLayer(sps)
z1=np.array([x for x in PRE_SYMBOLS for _ in range(sps)])
z2=np.array([x for x in PRE_SCRAMBLE for _ in range(sps)])
z=z1*z2;
_,_z=p.get_preamble_z()
print(all(z[0:3*32*sps]==_z[0:3*32*sps]))
for i in range(3):
print(i, all(z[32*5*i:32*5*(i+1)] == z[32*5*(3+i):32*5*(3+i+1)]))
print(i, all(z[32*sps*i:32*sps*(i+1)] == z[32*sps*(3+i):32*sps*(3+i+1)]))
print(np.sum(np.sum(z[0:32*5] * np.conj(z[32*5*3:32*5*4]))))
print(WALSH[1][:])
print(sum(WALSH[1][:]*(1<<np.array(range(7,-1,-1)))))
print(FROM_WALSH)
print(gen_data_scramble())
#print(np.sum(np.sum(z[0:32*5] * np.conj(z[32*5*3:32*5*4]))))
#print(WALSH[1][:])
#print(sum(WALSH[1][:]*(1<<np.array(range(7,-1,-1)))))
#print(FROM_WALSH)
#print(gen_data_scramble())
s=ScrambleData()
print([s.next() for _ in range(160)])
print([s.next() for _ in range(160)])
#print([s.next() for _ in range(160)])
#print([s.next() for _ in range(160)])
#print(np.round(np.angle(PRE_SYMBOLS*PRE_SCRAMBLE)/np.pi*4))

View File

@ -44,8 +44,8 @@ QAM64=np.array(
range(64)), CONST_DTYPE)
## for test
QAM64 = QAM64[(7,3,24,56,35,39,60,28),]
QAM64['symbols'] = [1, 0, 2, 6, 4, 5, 7, 3]
#QAM64 = QAM64[(7,3,24,56,35,39,60,28),]
#QAM64['symbols'] = [1, 0, 2, 6, 4, 5, 7, 3]
## ---- constellation indices ---------------------------------------------------
MODE_BPSK = 0
@ -142,118 +142,111 @@ class PhysicalLayer(object):
def get_constellations(self):
return self._constellations
def get_frame(self):
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 whethere or not raw IQ samples needed
[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)
## --- preamble frame ----
if self._frame_counter == -1:
print('-------------------- get_frame --------------------', self._frame_counter)
success = True
if self._frame_counter == -1: ## ---- preamble
self._preamble_offset = 0
return [self._preamble,MODE_BPSK,True,False]
## ----- (re)inserted preamble ------
if self._frame_counter == 0:
self.a = self.make_reinserted_preamble(self._preamble_offset)
return [self.a, MODE_QPSK,False,False]
if self._frame_counter >= 1:
self.a = self.make_data_frame()
return [self.a, self._constellation_index,False,True]
def get_doppler(self, symbols, iq_samples):
"""returns a tuple
[0] ... quality flag
[1] ... doppler estimate (rad/symbol) if available"""
print('-------------------- get_doppler --------------------',
self._frame_counter,len(symbols),len(iq_samples))
#if len(symbols)!=0:
# print('symb=', symbols)
success,doppler = False,0
if self._frame_counter == -1: ## -- preamble ----
success,doppler = self.get_doppler_from_preamble(symbols, iq_samples)
if len(symbols) != 0:
for s in symbols:
print(s)
self._frame_counter = 0
elif self._frame_counter == 0: ## -- reinserted preamble ----
## decode D0,D1,D2
idx = np.arange(13)
z = np.array([np.mean(symbols[32+13*i+idx]) for i in range(3)])
d0d1d2 = map(np.uint8, np.mod(np.round(np.angle(z)/np.pi*2),4))
dibits = [TO_DIBIT[idx] for idx in d0d1d2]
self._mode = {'rate': tuple([x[0] for x in dibits]),
'interleaver': tuple([x[1] for x in dibits])}
print('======== rate,interleaver:',
TO_RATE[self._mode['rate']],
TO_INTERLEAVER[self._mode['interleaver']])
rate_info = TO_RATE[self._mode['rate']]
self._constellation_index = rate_info['ci']
print('constellation index', self._constellation_index)
scr = ScrambleData()
iscr = [scr.next(rate_info['bits_per_symbol']) for _ in range(256)]
if rate_info['ci'] > MODE_8PSK:
self._data_scramble = np.ones(256, dtype=np.complex64)
else:
constell = self._constellations[rate_info['ci']]
self._data_scramble = constell[iscr]
self._frame_counter += 1
success = True
elif self._frame_counter <=72: ## -- data -------------------
print(np.abs(symbols[:16]), symbols[-31:], np.mean(symbols[-31:]))
success = np.abs(np.mean(symbols[-31:])) > 0.5
if success:
self._frame_counter += 1
else:
self._frame_counter = -1
else: ## ------------------------ re-inserted preamble -------
## TODO
for s in symbols:
print(s)
success = False
self._frame_counter = -1
return success,doppler
return [self._preamble,MODE_BPSK,success,False]
def get_doppler_from_preamble(self, symbols, iq_samples):
frame_counter_mod = self._frame_counter%72
if frame_counter_mod == 0: ## --- re-inserted preamble
self._frame_counter += 1
success = self.get_preamble_quality(symbols)
return [self.make_reinserted_preamble(self._preamble_offset,success),MODE_QPSK,success,False]
if frame_counter_mod >= 1: ## ---- data frames
got_reinserted_preamble = frame_counter_mod == 1
self._frame_counter += 1
if got_reinserted_preamble:
success = self.decode_reinserted_preamble(symbols)
else:
success = self.get_data_frame_quality(symbols)
return [self.make_data_frame(success),self._constellation_index,success,not got_reinserted_preamble]
def get_doppler(self, iq_samples):
"""quality check and doppler estimation for preamble"""
success,doppler = True,0
if len(iq_samples) != 0:
sps = self._sps
idx = np.arange(23*sps)
zp = self.get_preamble_z(self._sps)
_,zp = self.get_preamble_z()
cc = np.correlate(iq_samples, zp[idx])
imax = np.argmax(np.abs(cc[0:23*sps]))
pks = [np.correlate(iq_samples[imax+i*23*sps+idx],
zp[i*23*sps+idx])[0]
for i in range(7)]
success = np.mean(np.abs(pks)) > 2*np.mean(np.abs(cc[imax+11*sps+range(-sps,sps)]))
for i in range(8)]
success = np.bool(np.mean(np.abs(pks)) > 2*np.mean(np.abs(cc[imax+11*sps+range(-sps,sps)])))
print('test:',imax, np.mean(np.abs(pks)), np.mean(np.abs(cc[imax+11*sps+range(-sps,sps)])))
if success:
print('doppler apks', np.abs(pks))
print('doppler ppks', np.angle(pks),
np.diff(np.unwrap(np.angle(pks)))/23,
np.mean(np.diff(np.unwrap(np.angle(pks)))/23))
doppler = freq_est(pks[1:])/23;
doppler = freq_est(pks)/(23*sps);
print('success=', success, 'doppler=', doppler)
return success,doppler
def make_reinserted_preamble(self, offset):
def set_mode(self, mode):
pass
def get_preamble_quality(self, symbols):
return np.bool(np.abs(np.mean(symbols[-40:])) > 0.5)
def get_data_frame_quality(self, symbols):
return np.bool(np.abs(np.mean(symbols[-31:])) > 0.5)
def decode_reinserted_preamble(self, symbols):
## decode D0,D1,D2
idx = np.arange(13)
z = np.array([np.mean(symbols[32+13*i+idx]) for i in range(3)])
d0d1d2 = map(np.uint8, np.mod(np.round(np.angle(z)/np.pi*2),4))
dibits = [TO_DIBIT[idx] for idx in d0d1d2]
self._mode = {'rate': tuple([x[0] for x in dibits]),
'interleaver': tuple([x[1] for x in dibits])}
print('======== rate,interleaver:',
TO_RATE[self._mode['rate']],
TO_INTERLEAVER[self._mode['interleaver']])
rate_info = TO_RATE[self._mode['rate']]
print('rate_info', rate_info)
self._constellation_index = rate_info['ci']
print('constellation index', self._constellation_index)
scr = ScrambleData()
iscr = [scr.next(rate_info['bits_per_symbol']) for _ in range(256)]
if rate_info['ci'] > MODE_8PSK:
self._data_scramble = np.ones(256, dtype=np.complex64)
else:
constell = self._constellations[rate_info['ci']]
self._data_scramble = constell[iscr]['points']
success = True ## TODO
return success
def make_reinserted_preamble(self, offset, success):
""" offset= 0 -> 1st reinserted preamble
offset=-72 -> all following reinserted preambles"""
print('make_reinserted_preamble', offset, success)
a=np.array(zip(REINSERTED_PREAMBLE[offset:],
REINSERTED_PREAMBLE[offset:]),
dtype=[('symb', np.complex64),
('scramble', np.complex64)])
a['symb'][-72:-72+3*13] = 0 ## D0,D1,D2
if not success:
sefl._frame_counter = -1
return a
def make_data_frame(self):
def make_data_frame(self, success):
self._preamble_offset = -72 ## all following reinserted preambles start at index -72
a=np.zeros(256+31, dtype=[('symb', np.complex64),
('scramble', np.complex64)])
a['scramble'][:256] = self._data_scramble
n = self._frame_counter -1
n = (self._frame_counter-2)%72
m = n%18
if m == 0:
cnt = n//18
@ -261,6 +254,8 @@ class PhysicalLayer(object):
print('new mini-probe signs n=',n,'m=',m,self._mp)
a['symb'][256:] = MINI_PROBE[self._mp[m]]
a['scramble'][256:] = MINI_PROBE[self._mp[m]]
if not success:
self._frame_counter = -1
return a
@staticmethod
@ -270,10 +265,10 @@ class PhysicalLayer(object):
PREAMBLE),
dtype=[('symb', np.complex64),
('scramble', np.complex64)])
@staticmethod
def get_preamble_z(sps):
def get_preamble_z(self):
"""preamble symbols for preamble correlation"""
return np.array([z for z in PREAMBLE for _ in range(sps)])
return 2,np.array([z for z in PREAMBLE for _ in range(self._sps)])
if __name__ == '__main__':
print(PREAMBLE)

View File

@ -12,7 +12,7 @@ class PhysicalLayer(object):
def __init__(self, sps):
"""intialization"""
self._sps = sps
self._mode = self.MODE_BPSK
self._mode = self.MODE_QPSK
self._frame_counter = 0
self._is_first_frame = True
self._constellations = [self.make_psk(2, [0,1]),
@ -29,50 +29,53 @@ class PhysicalLayer(object):
def get_constellations(self):
return self._constellations
def get_frame(self):
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 whethere or not raw IQ samples needed
[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)
return [self._preamble,self.MODE_BPSK,True,False] if self.is_preamble() else [self._data,self._mode,False,True]
## print('-------------------- get_frame --------------------', self._frame_counter, len(symbols))
if len(symbols) == 0: ## 1st preamble
self._frame_counter = 0
def get_doppler(self, symbols, iq_samples):
success,frame_description = True,[]
if (self._frame_counter%2) == 0:
frame_description = [self._preamble,self.MODE_BPSK,success,False]
else:
idx = range(30,80)
z = symbols[idx]*np.conj(self._preamble['symb'][idx])
## print('quality_preamble',np.sum(np.real(z)<0), symbols[idx])
success = np.bool(np.sum(np.real(z)<0) < 30)
frame_description = [self._data,self._mode,success,True]
self._frame_counter += 1
return frame_description
def get_doppler(self, iq_samples):
"""returns a tuple
[0] ... quality flag
[1] ... doppler estimate (rad/symbol) if available"""
print('-------------------- get_doppler --------------------', self._frame_counter,len(symbols),len(iq_samples))
success,doppler = self.quality_preamble(symbols,iq_samples) if self.is_preamble() else self.quality_data(symbols)
if len(symbols) != 0:
self._frame_counter = (self._frame_counter+1)&1 if success else 0
self._is_first_frame = not success
## print('-------------------- get_doppler --------------------', self._frame_counter,len(iq_samples))
success,doppler = False,0
if len(iq_samples) == 0:
return success,doppler
sps = self._sps
zp = np.array([x for x in self._preamble['symb'][9:40]
for _ in range(sps)], dtype=np.complex64)
cc = np.correlate(iq_samples, zp)
imax = np.argmax(np.abs(cc[0:18*sps]))
pks = cc[(imax,imax+31*sps),]
tpks = cc[imax+15*sps:imax+16*sps]
## print('doppler: ', np.abs(pks), np.abs(tpks))
success = np.bool(np.mean(np.abs(pks)) > 5*np.mean(np.abs(tpks)))
doppler = np.diff(np.unwrap(np.angle(pks)))[0]/31/self._sps if success else 0
return success,doppler
def is_preamble(self):
return self._frame_counter == 0
def quality_preamble(self, symbols, iq_samples):
"""quality check and doppler estimation for preamble"""
success = True
doppler = 0
if len(iq_samples) != 0:
sps = self._sps
zp = np.array([x for x in self._preamble['symb'][9:40]
for _ in range(sps)], dtype=np.complex64)
cc = np.correlate(iq_samples, zp)
imax = np.argmax(np.abs(cc[0:18*sps]))
pks = cc[(imax,imax+31*sps),]
tpks = cc[imax+15*sps:imax+16*sps]
success = np.mean(np.abs(pks)) > 2*np.mean(np.abs(tpks))
doppler = np.diff(np.unwrap(np.angle(pks)))[0]/31 if success else 0
if len(symbols) != 0:
idx = range(30,80) if self._is_first_frame else range(80)
z = symbols[idx]*np.conj(self._preamble['symb'][idx])
print('quality_preamble',np.sum(np.real(z)<0))
success = np.sum(np.real(z)<0) < 30
return success,doppler
def quality_data(self, s):
"""quality check for the data frame"""
known_symbols = np.mod(range(176),48)>=32
@ -80,6 +83,11 @@ class PhysicalLayer(object):
success = np.sum(np.real(s[known_symbols])<0) < 20
return success,0 ## no doppler estimate for data frames
def get_preamble_z(self):
"""preamble symbols for preamble correlation"""
a = PhysicalLayer.get_preamble()
return 2,np.array([z for z in a['symb'][0:31] for _ in range(self._sps)])
@staticmethod
def get_preamble():
"""preamble symbols + scrambler(=1)"""
@ -117,7 +125,7 @@ class PhysicalLayer(object):
@staticmethod
def make_psk(n, gray_code):
"""generates n-PSK constellation data"""
c = np.zeros(n, dtype=[('points', np.complex64), ('symbols', np.uint8)])
c = np.zeros(n, dtype=[('points', np.complex64), ('symbols', np.int32)])
c['points'] = np.exp(2*np.pi*1j*np.arange(n)/n)
c['symbols'] = gray_code
return c

View File

@ -3,7 +3,7 @@
import numpy as np
CONST_DTYPE=np.dtype([('points', np.complex64),
('symbols', np.uint8)])
('symbols', np.int32)])
def n_psk(n,x):
"""n-ary PSK constellation"""

View File

@ -0,0 +1,91 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2018 hcab14@gmail.com.
#
# This is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this software; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
import importlib
from gnuradio import blocks
from gnuradio import digital
from gnuradio import filter
from gnuradio import gr
import pmt
import digitalhf
import digitalhf.physical_layer
class physical_layer_driver(gr.hier_block2):
"""
docstring for block physical_layer_driver
"""
def __init__(self, samp_rate,sps,alpha,mu,nB,nF,nW,description_name,mode):
gr.hier_block2.__init__(self,
"physical_layer_driver",
gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
gr.io_signature(2, 2, gr.sizeof_gr_complex)) # Output signature
self._sps = sps
self._alpha = alpha
self._mu = mu
self._nB = nB
self._nF = nF
self._nW = nW
m = importlib.import_module('digitalhf.physical_layer.'+description_name)
self._physical_layer_driver_description = m.PhysicalLayer(sps)
self._physical_layer_driver_description.set_mode(mode)
## TODO: get rrc tap information from physical layer description
self._rrc_taps = filter.firdes.root_raised_cosine(1.0, samp_rate, samp_rate/sps, 0.35, 11*sps)
preamble_offset,preamble_samples = self._physical_layer_driver_description.get_preamble_z()
preamble_length = sps*len(self._physical_layer_driver_description.get_preamble())
self._rrc_filter = filter.fir_filter_ccc(1, (self._rrc_taps))
self._corr_est = digital.corr_est_cc((preamble_samples.tolist()), sps, preamble_offset, 0.5)
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)
self.connect((self, 0),
(self._rrc_filter, 0),
(self._corr_est, 0),
(self._doppler_correction, 0),
(self._adaptive_filter, 0),
(self, 0))
self.connect((self._corr_est, 1), ## correlation
(self, 1))
self.msg_connect((self._doppler_correction, 'doppler'), (self._msg_proxy, 'doppler'))
self.msg_connect((self._msg_proxy, 'doppler'), (self._doppler_correction, 'doppler'))
self.msg_connect((self._adaptive_filter, 'frame_info'), (self._msg_proxy, 'frame_info'))
self.msg_connect((self._msg_proxy, 'frame_info'), (self._adaptive_filter, 'frame_info'))
constellations_data = self._physical_layer_driver_description.get_constellations()
constellations_msg = pmt.to_pmt([{'idx': idx, 'points': c['points'], 'symbols': c['symbols']}
for (idx,c) in enumerate(constellations_data)])
self._adaptive_filter.to_basic_block()._post(pmt.intern('constellations'), constellations_msg)
self.message_port_register_hier_out('soft_dec')
self.msg_connect((self._adaptive_filter, 'soft_dec'), (self, 'soft_dec'))
def set_mu(self, mu):
self._adaptive_filter.set_mu(mu)
def set_alpha(self, alpha):
self._adaptive_filter.set_alpha(alpha)
def set_mode(self, mode):
self._physical_layer_driver_description.set_mode(mode)

View File

@ -0,0 +1,41 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2018 hcab14@gmail.com.
#
# This is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this software; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
from gnuradio import gr, gr_unittest
from gnuradio import blocks
import digitalhf.digitalhf_swig as digitalhf
class qa_doppler_correction_cc(gr_unittest.TestCase):
def setUp(self):
self.tb = gr.top_block()
def tearDown(self):
self.tb = None
def test_001_t(self):
# set up fg
self.tb.run()
# check data
if __name__ == '__main__':
gr_unittest.run(qa_doppler_correction_cc, "qa_doppler_correction_cc.xml")

41
python/qa_msg_proxy.py Executable file
View File

@ -0,0 +1,41 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2018 hcab14@gmail.com.
#
# This is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this software; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
from gnuradio import gr, gr_unittest
from gnuradio import blocks
from physical_layer_driver import physical_layer_driver
class qa_msg_proxy(gr_unittest.TestCase):
def setUp(self):
self.tb = gr.top_block()
def tearDown(self):
self.tb = None
def test_001_t(self):
# set up fg
self.tb.run()
# check data
if __name__ == '__main__':
gr_unittest.run(qa_msg_proxy, "qa_msg_proxy.xml")

View File

@ -0,0 +1,41 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2018 hcab14@gmail.com.
#
# This is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this software; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
from gnuradio import gr, gr_unittest
from gnuradio import blocks
from physical_layer import physical_layer
class qa_physical_layer_driver(gr_unittest.TestCase):
def setUp(self):
self.tb = gr.top_block()
def tearDown(self):
self.tb = None
def test_001_t(self):
# set up fg
self.tb.run()
# check data
if __name__ == '__main__':
gr_unittest.run(qa_physical_layer_driver, "qa_physical_layer_driver.xml")

View File

@ -9,7 +9,10 @@
%{
#include "digitalhf/adaptive_dfe.h"
#include "digitalhf/doppler_correction_cc.h"
%}
%include "digitalhf/adaptive_dfe.h"
GR_SWIG_BLOCK_MAGIC2(digitalhf, adaptive_dfe);
%include "digitalhf/doppler_correction_cc.h"
GR_SWIG_BLOCK_MAGIC2(digitalhf, doppler_correction_cc);