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.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" "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) if(NOT Boost_FOUND)
message(FATAL_ERROR "Boost required to compile digitalhf") message(FATAL_ERROR "Boost required to compile digitalhf")
@ -178,7 +178,6 @@ include_directories(
${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include
${CMAKE_BINARY_DIR}/lib ${CMAKE_BINARY_DIR}/lib
${CMAKE_BINARY_DIR}/include ${CMAKE_BINARY_DIR}/include
${PYTHON_INCLUDE_DIR}
${Boost_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
${CPPUNIT_INCLUDE_DIRS} ${CPPUNIT_INCLUDE_DIRS}
${GNURADIO_ALL_INCLUDE_DIRS} ${GNURADIO_ALL_INCLUDE_DIRS}

View File

@ -109,7 +109,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1141, 80)</value> <value>(810, 16)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -156,33 +156,6 @@
<value>counter_slider</value> <value>counter_slider</value>
</param> </param>
</block> </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> <block>
<key>variable_qtgui_range</key> <key>variable_qtgui_range</key>
<param> <param>
@ -199,7 +172,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1024, 80)</value> <value>(682, 16)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -258,7 +231,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(533, 16)</value> <value>(405, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -285,7 +258,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(608, 16)</value> <value>(480, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -312,7 +285,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(682, 16)</value> <value>(565, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -327,49 +300,6 @@
<value>4</value> <value>4</value>
</param> </param>
</block> </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> <block>
<key>variable</key> <key>variable</key>
<param> <param>
@ -409,7 +339,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(458, 16)</value> <value>(320, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -424,6 +354,69 @@
<value>5</value> <value>5</value>
</param> </param>
</block> </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> <block>
<key>blocks_complex_to_mag</key> <key>blocks_complex_to_mag</key>
<param> <param>
@ -444,11 +437,11 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(928, 314)</value> <value>(426, 368)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>id</key> <key>id</key>
@ -483,7 +476,7 @@
</param> </param>
<param> <param>
<key>_enabled</key> <key>_enabled</key>
<value>True</value> <value>1</value>
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
@ -510,57 +503,6 @@
<value>1</value> <value>1</value>
</param> </param>
</block> </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> <block>
<key>blocks_tag_debug</key> <key>blocks_tag_debug</key>
<param> <param>
@ -585,7 +527,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(917, 133)</value> <value>(1002, 282)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -636,7 +578,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(586, 176)</value> <value>(672, 176)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -687,7 +629,7 @@
</param> </param>
<param> <param>
<key>_enabled</key> <key>_enabled</key>
<value>True</value> <value>1</value>
</param> </param>
<param> <param>
<key>file</key> <key>file</key>
@ -719,11 +661,11 @@
</param> </param>
<param> <param>
<key>repeat</key> <key>repeat</key>
<value>False</value> <value>True</value>
</param> </param>
</block> </block>
<block> <block>
<key>digitalhf_adaptive_dfe</key> <key>digitalhf_physical_layer_driver</key>
<param> <param>
<key>alias</key> <key>alias</key>
<value></value> <value></value>
@ -736,21 +678,25 @@
<key>affinity</key> <key>affinity</key>
<value></value> <value></value>
</param> </param>
<param>
<key>description_name</key>
<value>MIL_STD_188_110A</value>
</param>
<param> <param>
<key>_enabled</key> <key>_enabled</key>
<value>True</value> <value>1</value>
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(874, 389)</value> <value>(661, 325)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>id</key> <key>id</key>
<value>digitalhf_adaptive_dfe_0</value> <value>digitalhf_physical_layer_driver_0</value>
</param> </param>
<param> <param>
<key>maxoutbuf</key> <key>maxoutbuf</key>
@ -766,11 +712,11 @@
</param> </param>
<param> <param>
<key>alpha</key> <key>alpha</key>
<value>0.0005</value> <value>0.005</value>
</param> </param>
<param> <param>
<key>mode</key> <key>mode</key>
<value>''</value> <value>""</value>
</param> </param>
<param> <param>
<key>mu</key> <key>mu</key>
@ -789,215 +735,8 @@
<value>nW</value> <value>nW</value>
</param> </param>
<param> <param>
<key>py_obj_name</key> <key>samp_rate</key>
<value>MIL_STD_188_110A</value> <value>samp_rate</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>
</param> </param>
</block> </block>
<block> <block>
@ -1028,7 +767,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1109, 410)</value> <value>(394, 464)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -1036,7 +775,7 @@
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>grid</key> <key>grid</key>
@ -1383,7 +1122,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1120, 304)</value> <value>(181, 357)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -1391,7 +1130,7 @@
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>grid</key> <key>grid</key>
@ -1746,11 +1485,11 @@
</param> </param>
<param> <param>
<key>_enabled</key> <key>_enabled</key>
<value>True</value> <value>1</value>
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1002, 602)</value> <value>(426, 293)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -1758,7 +1497,7 @@
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>grid</key> <key>grid</key>
@ -2117,7 +1856,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1120, 218)</value> <value>(938, 165)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -2304,6 +2043,12 @@
<value>firdes.WIN_BLACKMAN_hARRIS</value> <value>firdes.WIN_BLACKMAN_hARRIS</value>
</param> </param>
</block> </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> <connection>
<source_block_id>blocks_complex_to_mag_0</source_block_id> <source_block_id>blocks_complex_to_mag_0</source_block_id>
<sink_block_id>qtgui_time_sink_x_0</sink_block_id> <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
@ -2312,19 +2057,19 @@
</connection> </connection>
<connection> <connection>
<source_block_id>blocks_float_to_complex_0</source_block_id> <source_block_id>blocks_float_to_complex_0</source_block_id>
<sink_block_id>blocks_multiply_const_vxx_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_multiply_const_vxx_0</source_block_id>
<sink_block_id>blocks_throttle_0</sink_block_id>
<source_key>0</source_key> <source_key>0</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
<connection> <connection>
<source_block_id>blocks_throttle_0</source_block_id> <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> <source_key>0</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
@ -2341,45 +2086,21 @@
<sink_key>1</sink_key> <sink_key>1</sink_key>
</connection> </connection>
<connection> <connection>
<source_block_id>digitalhf_adaptive_dfe_0</source_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>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>
<sink_block_id>blocks_complex_to_mag_0</sink_block_id> <sink_block_id>blocks_complex_to_mag_0</sink_block_id>
<source_key>1</source_key> <source_key>1</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
<connection> <connection>
<source_block_id>preamble</source_block_id> <source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>blocks_tag_debug_0</sink_block_id> <sink_block_id>qtgui_const_sink_x_0</sink_block_id>
<source_key>0</source_key> <source_key>0</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
<connection> <connection>
<source_block_id>preamble</source_block_id> <source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>digitalhf_adaptive_dfe_0</sink_block_id> <sink_block_id>qtgui_time_sink_x_1</sink_block_id>
<source_key>0</source_key> <source_key>soft_dec</source_key>
<sink_key>0</sink_key> <sink_key>in</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>
</connection> </connection>
</flow_graph> </flow_graph>

View File

@ -109,7 +109,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1141, 80)</value> <value>(1141, 240)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -156,33 +156,6 @@
<value>counter_slider</value> <value>counter_slider</value>
</param> </param>
</block> </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> <block>
<key>variable_qtgui_range</key> <key>variable_qtgui_range</key>
<param> <param>
@ -199,7 +172,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1024, 80)</value> <value>(629, 16)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -258,7 +231,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(533, 16)</value> <value>(416, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -285,7 +258,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(608, 16)</value> <value>(480, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -312,7 +285,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(682, 16)</value> <value>(554, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -327,49 +300,6 @@
<value>4</value> <value>4</value>
</param> </param>
</block> </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> <block>
<key>variable</key> <key>variable</key>
<param> <param>
@ -409,7 +339,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(458, 16)</value> <value>(330, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -424,6 +354,69 @@
<value>5</value> <value>5</value>
</param> </param>
</block> </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> <block>
<key>blocks_complex_to_mag</key> <key>blocks_complex_to_mag</key>
<param> <param>
@ -444,11 +437,11 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(928, 314)</value> <value>(576, 453)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>id</key> <key>id</key>
@ -487,7 +480,7 @@
</param> </param>
<param> <param>
<key>_enabled</key> <key>_enabled</key>
<value>True</value> <value>1</value>
</param> </param>
<param> <param>
<key>file</key> <key>file</key>
@ -495,11 +488,11 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(693, 677)</value> <value>(277, 293)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>id</key> <key>id</key>
@ -534,11 +527,11 @@
</param> </param>
<param> <param>
<key>_enabled</key> <key>_enabled</key>
<value>True</value> <value>1</value>
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(256, 154)</value> <value>(256, 133)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -561,57 +554,6 @@
<value>1</value> <value>1</value>
</param> </param>
</block> </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> <block>
<key>blocks_pdu_to_tagged_stream</key> <key>blocks_pdu_to_tagged_stream</key>
<param> <param>
@ -628,15 +570,15 @@
</param> </param>
<param> <param>
<key>_enabled</key> <key>_enabled</key>
<value>True</value> <value>1</value>
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(458, 581)</value> <value>(544, 368)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>id</key> <key>id</key>
@ -683,7 +625,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(917, 133)</value> <value>(1162, 421)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -734,7 +676,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(586, 176)</value> <value>(661, 154)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -785,7 +727,7 @@
</param> </param>
<param> <param>
<key>_enabled</key> <key>_enabled</key>
<value>True</value> <value>1</value>
</param> </param>
<param> <param>
<key>file</key> <key>file</key>
@ -793,7 +735,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(10, 154)</value> <value>(10, 133)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -817,11 +759,11 @@
</param> </param>
<param> <param>
<key>repeat</key> <key>repeat</key>
<value>True</value> <value>False</value>
</param> </param>
</block> </block>
<block> <block>
<key>digitalhf_adaptive_dfe</key> <key>digitalhf_physical_layer_driver</key>
<param> <param>
<key>alias</key> <key>alias</key>
<value></value> <value></value>
@ -834,21 +776,25 @@
<key>affinity</key> <key>affinity</key>
<value></value> <value></value>
</param> </param>
<param>
<key>description_name</key>
<value>MIL_STD_188_110C</value>
</param>
<param> <param>
<key>_enabled</key> <key>_enabled</key>
<value>True</value> <value>True</value>
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(874, 389)</value> <value>(821, 400)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>id</key> <key>id</key>
<value>digitalhf_adaptive_dfe_0</value> <value>digitalhf_physical_layer_driver_0</value>
</param> </param>
<param> <param>
<key>maxoutbuf</key> <key>maxoutbuf</key>
@ -864,11 +810,11 @@
</param> </param>
<param> <param>
<key>alpha</key> <key>alpha</key>
<value>0.0001</value> <value>0.005</value>
</param> </param>
<param> <param>
<key>mode</key> <key>mode</key>
<value>''</value> <value>""</value>
</param> </param>
<param> <param>
<key>mu</key> <key>mu</key>
@ -887,215 +833,8 @@
<value>nW</value> <value>nW</value>
</param> </param>
<param> <param>
<key>py_obj_name</key> <key>samp_rate</key>
<value>MIL_STD_188_110C</value> <value>samp_rate</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>
</param> </param>
</block> </block>
<block> <block>
@ -1126,7 +865,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1109, 410)</value> <value>(554, 538)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -1134,7 +873,7 @@
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>grid</key> <key>grid</key>
@ -1481,7 +1220,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1120, 304)</value> <value>(288, 474)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -1489,7 +1228,7 @@
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>grid</key> <key>grid</key>
@ -1844,11 +1583,11 @@
</param> </param>
<param> <param>
<key>_enabled</key> <key>_enabled</key>
<value>True</value> <value>1</value>
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1002, 602)</value> <value>(298, 378)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -1856,7 +1595,7 @@
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>grid</key> <key>grid</key>
@ -2215,7 +1954,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1120, 218)</value> <value>(1066, 101)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -2402,6 +2141,12 @@
<value>firdes.WIN_BLACKMAN_hARRIS</value> <value>firdes.WIN_BLACKMAN_hARRIS</value>
</param> </param>
</block> </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> <connection>
<source_block_id>blocks_complex_to_mag_0</source_block_id> <source_block_id>blocks_complex_to_mag_0</source_block_id>
<sink_block_id>qtgui_time_sink_x_0</sink_block_id> <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
@ -2410,13 +2155,7 @@
</connection> </connection>
<connection> <connection>
<source_block_id>blocks_float_to_complex_0</source_block_id> <source_block_id>blocks_float_to_complex_0</source_block_id>
<sink_block_id>blocks_multiply_const_vxx_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_multiply_const_vxx_0</source_block_id>
<sink_block_id>blocks_throttle_0</sink_block_id>
<source_key>0</source_key> <source_key>0</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
@ -2434,7 +2173,13 @@
</connection> </connection>
<connection> <connection>
<source_block_id>blocks_throttle_0</source_block_id> <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> <source_key>0</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
@ -2451,45 +2196,21 @@
<sink_key>1</sink_key> <sink_key>1</sink_key>
</connection> </connection>
<connection> <connection>
<source_block_id>digitalhf_adaptive_dfe_0</source_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>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>
<sink_block_id>blocks_complex_to_mag_0</sink_block_id> <sink_block_id>blocks_complex_to_mag_0</sink_block_id>
<source_key>1</source_key> <source_key>1</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
<connection> <connection>
<source_block_id>preamble</source_block_id> <source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>blocks_tag_debug_0</sink_block_id> <sink_block_id>qtgui_const_sink_x_0</sink_block_id>
<source_key>0</source_key> <source_key>0</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
<connection> <connection>
<source_block_id>preamble</source_block_id> <source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>digitalhf_adaptive_dfe_0</sink_block_id> <sink_block_id>blocks_pdu_to_tagged_stream_0</sink_block_id>
<source_key>0</source_key> <source_key>soft_dec</source_key>
<sink_key>0</sink_key> <sink_key>pdus</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>
</connection> </connection>
</flow_graph> </flow_graph>

View File

@ -93,33 +93,6 @@
<value>(0,0)</value> <value>(0,0)</value>
</param> </param>
</block> </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> <block>
<key>variable_qtgui_range</key> <key>variable_qtgui_range</key>
<param> <param>
@ -136,7 +109,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1141, 80)</value> <value>(1141, 16)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -183,33 +156,6 @@
<value>counter_slider</value> <value>counter_slider</value>
</param> </param>
</block> </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> <block>
<key>variable_qtgui_chooser</key> <key>variable_qtgui_chooser</key>
<param> <param>
@ -226,7 +172,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1152, 490)</value> <value>(1152, 277)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -325,7 +271,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1024, 80)</value> <value>(1152, 144)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -384,7 +330,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(533, 16)</value> <value>(394, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -411,7 +357,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(608, 16)</value> <value>(469, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -438,7 +384,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(682, 16)</value> <value>(544, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -453,49 +399,6 @@
<value>4</value> <value>4</value>
</param> </param>
</block> </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> <block>
<key>variable</key> <key>variable</key>
<param> <param>
@ -535,7 +438,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(458, 16)</value> <value>(320, 16)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -550,6 +453,69 @@
<value>5</value> <value>5</value>
</param> </param>
</block> </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> <block>
<key>blocks_complex_to_mag</key> <key>blocks_complex_to_mag</key>
<param> <param>
@ -570,11 +536,11 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(928, 314)</value> <value>(533, 368)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>id</key> <key>id</key>
@ -613,7 +579,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(256, 154)</value> <value>(277, 154)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -636,57 +602,6 @@
<value>1</value> <value>1</value>
</param> </param>
</block> </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> <block>
<key>blocks_tag_debug</key> <key>blocks_tag_debug</key>
<param> <param>
@ -711,7 +626,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(917, 133)</value> <value>(1184, 464)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -762,7 +677,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(586, 176)</value> <value>(682, 176)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -817,7 +732,7 @@
</param> </param>
<param> <param>
<key>file</key> <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>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
@ -845,11 +760,11 @@
</param> </param>
<param> <param>
<key>repeat</key> <key>repeat</key>
<value>False</value> <value>True</value>
</param> </param>
</block> </block>
<block> <block>
<key>digitalhf_adaptive_dfe</key> <key>digitalhf_physical_layer_driver</key>
<param> <param>
<key>alias</key> <key>alias</key>
<value></value> <value></value>
@ -862,21 +777,25 @@
<key>affinity</key> <key>affinity</key>
<value></value> <value></value>
</param> </param>
<param>
<key>description_name</key>
<value>STANAG_4285</value>
</param>
<param> <param>
<key>_enabled</key> <key>_enabled</key>
<value>True</value> <value>True</value>
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(874, 389)</value> <value>(736, 314)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>id</key> <key>id</key>
<value>digitalhf_adaptive_dfe_0</value> <value>digitalhf_physical_layer_driver_0</value>
</param> </param>
<param> <param>
<key>maxoutbuf</key> <key>maxoutbuf</key>
@ -915,235 +834,8 @@
<value>nW</value> <value>nW</value>
</param> </param>
<param> <param>
<key>py_obj_name</key> <key>samp_rate</key>
<value>STANAG_4285</value> <value>samp_rate</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>
</param> </param>
</block> </block>
<block> <block>
@ -1174,7 +866,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1109, 410)</value> <value>(320, 442)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -1182,7 +874,7 @@
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>grid</key> <key>grid</key>
@ -1529,7 +1221,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1120, 304)</value> <value>(320, 357)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -1537,7 +1229,7 @@
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>grid</key> <key>grid</key>
@ -1801,7 +1493,7 @@
</param> </param>
<param> <param>
<key>size</key> <key>size</key>
<value>1024/2</value> <value>80*sps</value>
</param> </param>
<param> <param>
<key>srate</key> <key>srate</key>
@ -1817,7 +1509,7 @@
</param> </param>
<param> <param>
<key>tr_delay</key> <key>tr_delay</key>
<value>0.01</value> <value>0.007</value>
</param> </param>
<param> <param>
<key>tr_level</key> <key>tr_level</key>
@ -1896,7 +1588,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1002, 602)</value> <value>(320, 293)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -1904,7 +1596,7 @@
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
<value>0</value> <value>180</value>
</param> </param>
<param> <param>
<key>grid</key> <key>grid</key>
@ -2263,7 +1955,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1120, 218)</value> <value>(896, 101)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -2450,6 +2142,12 @@
<value>firdes.WIN_BLACKMAN_hARRIS</value> <value>firdes.WIN_BLACKMAN_hARRIS</value>
</param> </param>
</block> </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> <connection>
<source_block_id>blocks_complex_to_mag_0</source_block_id> <source_block_id>blocks_complex_to_mag_0</source_block_id>
<sink_block_id>qtgui_time_sink_x_0</sink_block_id> <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
@ -2458,19 +2156,19 @@
</connection> </connection>
<connection> <connection>
<source_block_id>blocks_float_to_complex_0</source_block_id> <source_block_id>blocks_float_to_complex_0</source_block_id>
<sink_block_id>blocks_multiply_const_vxx_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_multiply_const_vxx_0</source_block_id>
<sink_block_id>fractional_resampler_xx_0</sink_block_id>
<source_key>0</source_key> <source_key>0</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
<connection> <connection>
<source_block_id>blocks_throttle_0</source_block_id> <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> <source_key>0</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
@ -2487,51 +2185,21 @@
<sink_key>1</sink_key> <sink_key>1</sink_key>
</connection> </connection>
<connection> <connection>
<source_block_id>digitalhf_adaptive_dfe_0</source_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>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>
<sink_block_id>blocks_complex_to_mag_0</sink_block_id> <sink_block_id>blocks_complex_to_mag_0</sink_block_id>
<source_key>1</source_key> <source_key>1</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
<connection> <connection>
<source_block_id>preamble</source_block_id> <source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>blocks_tag_debug_0</sink_block_id> <sink_block_id>qtgui_const_sink_x_0</sink_block_id>
<source_key>0</source_key> <source_key>0</source_key>
<sink_key>0</sink_key> <sink_key>0</sink_key>
</connection> </connection>
<connection> <connection>
<source_block_id>preamble</source_block_id> <source_block_id>digitalhf_physical_layer_driver_0</source_block_id>
<sink_block_id>digitalhf_adaptive_dfe_0</sink_block_id> <sink_block_id>qtgui_time_sink_x_1</sink_block_id>
<source_key>0</source_key> <source_key>soft_dec</source_key>
<sink_key>0</sink_key> <sink_key>in</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>
</connection> </connection>
</flow_graph> </flow_graph>

View File

@ -18,5 +18,8 @@
# the Free Software Foundation, Inc., 51 Franklin Street, # the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA. # Boston, MA 02110-1301, USA.
install(FILES 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> <key>digitalhf_adaptive_dfe</key>
<category>[digitalhf]</category> <category>[digitalhf]</category>
<import>import digitalhf</import> <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_mu($mu)</callback>
<callback>set_mode($mode)</callback>
<!-- Make one 'param' node for every Parameter you want settable from the GUI. <!-- Make one 'param' node for every Parameter you want settable from the GUI.
Sub-nodes: Sub-nodes:
* name * name
@ -42,16 +41,6 @@
<key>alpha</key> <key>alpha</key>
<type>float</type> <type>float</type>
</param> </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: <!-- Make one 'sink' node per input. Sub-nodes:
* name (an identifier for the GUI) * 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 install(FILES
api.h 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 static sptr make(int sps, // samples per symbol
int nB, // number of forward FIR taps int nB, // number of forward FIR taps
int nF, // number of backward FIR taps int nF, // number of backward FIR taps
int nW, // number of feedback taps int nW, // number of feedback symbol taps
float mu, // float mu, // mu - decision-feedback equalizer
float alpha, // float alpha); // alpha - decision-feedback equalizer
std::string physical_layer_description);
virtual void set_mu(float) = 0; virtual void set_mu(float) = 0;
virtual void set_mode(std::string) = 0; virtual void set_alpha(float) = 0;
} ; } ;
} // namespace digitalhf } // 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}) include_directories(${Boost_INCLUDE_DIR})
link_directories(${Boost_LIBRARY_DIRS}) link_directories(${Boost_LIBRARY_DIRS})
list(APPEND digitalhf_sources list(APPEND digitalhf_sources
adaptive_dfe_impl.cc ) adaptive_dfe_impl.cc
doppler_correction_cc_impl.cc )
set(digitalhf_sources "${digitalhf_sources}" PARENT_SCOPE) set(digitalhf_sources "${digitalhf_sources}" PARENT_SCOPE)
if(NOT digitalhf_sources) if(NOT digitalhf_sources)
@ -59,6 +60,7 @@ include_directories(${CPPUNIT_INCLUDE_DIRS})
list(APPEND test_digitalhf_sources list(APPEND test_digitalhf_sources
${CMAKE_CURRENT_SOURCE_DIR}/test_digitalhf.cc ${CMAKE_CURRENT_SOURCE_DIR}/test_digitalhf.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_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 ${CMAKE_CURRENT_SOURCE_DIR}/qa_adaptive_dfe.cc
) )
@ -66,13 +68,11 @@ add_executable(test-digitalhf ${test_digitalhf_sources})
target_link_libraries( target_link_libraries(
test-digitalhf test-digitalhf
${PYTHON_LIBRARIES}
${GNURADIO_RUNTIME_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES}
${Boost_LIBRARIES} ${Boost_LIBRARIES}
${CPPUNIT_LIBRARIES} ${CPPUNIT_LIBRARIES}
gnuradio-digitalhf gnuradio-digitalhf
) )
MESSAGE("XXX ${PYTHON_LIBRARIES}")
GR_ADD_TEST(test_digitalhf test-digitalhf) GR_ADD_TEST(test_digitalhf test-digitalhf)
######################################################################## ########################################################################

View File

@ -39,51 +39,24 @@
namespace gr { namespace gr {
namespace digitalhf { 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::sptr
adaptive_dfe::make(int sps, // samples per symbol adaptive_dfe::make(int sps, // samples per symbol
int nB, // number of forward FIR taps int nB, // number of forward FIR taps
int nF, // number of backward FIR taps int nF, // number of backward FIR taps
int nW, // number of feedback taps int nW, // number of feedback taps
float mu, float mu,
float alpha, float alpha)
std::string python_module_name)
{ {
return gnuradio::get_initial_sptr 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 adaptive_dfe_impl::adaptive_dfe_impl(int sps, // samples per symbol
int nB, // number of forward FIR taps int nB, // number of forward FIR taps
int nF, // number of backward FIR taps int nF, // number of backward FIR taps
int nW, // number of feedback taps int nW, // number of feedback taps
float mu, float mu,
float alpha, float alpha)
std::string python_module_name)
: gr::block("adaptive_dfe", : gr::block("adaptive_dfe",
gr::io_signature::make(1, 1, sizeof(gr_complex)), gr::io_signature::make(1, 1, sizeof(gr_complex)),
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) , _nB(nB*sps)
, _nF(nF*sps) , _nF(nF*sps)
, _nW(nW) , _nW(nW)
, _nGuard(2*sps)
, _mu(mu) , _mu(mu)
, _alpha(alpha) , _alpha(alpha)
, _use_symbol_taps(true) , _use_symbol_taps(true)
, _py_module_name(python_module_name) // , _py_module_name(python_module_name)
, _physicalLayer() // , _physicalLayer()
, _taps_samples(nullptr) , _taps_samples(nullptr)
, _taps_symbols(nullptr) , _taps_symbols(nullptr)
, _hist_samples(nullptr)
, _hist_symbols(nullptr) , _hist_symbols(nullptr)
, _hist_sample_index(0)
, _hist_symbol_index(0) , _hist_symbol_index(0)
, _ignore_filter_updates(0)
, _saved_samples()
, _sample_counter(0)
, _constellations() , _constellations()
, _npwr() , _npwr()
, _npwr_counter()
, _npwr_max_time_constant(10) , _npwr_max_time_constant(10)
, _constellation_index() , _constellation_index()
, _samples()
, _symbols() , _symbols()
, _scramble() , _scramble()
, _descrambled_symbols() , _descrambled_symbols()
, _symbol_counter(0) , _symbol_counter(0)
, _need_samples(false)
, _save_soft_decisions(false) , _save_soft_decisions(false)
, _vec_soft_decisions() , _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()) , _msg_metadata(pmt::make_dict())
, _df(0)
, _phase(0)
, _b{0.338187046465954, -0.288839024460507}
, _ud(0)
, _state(WAIT_FOR_PREAMBLE) , _state(WAIT_FOR_PREAMBLE)
{ {
GR_LOG_DECLARE_LOGPTR(d_logger); GR_LOG_DECLARE_LOGPTR(d_logger);
GR_LOG_ASSIGN_LOGPTR(d_logger, "adaptive_dfe"); 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() 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_samples);
VOLK_SAFE_DELETE(_taps_symbols); VOLK_SAFE_DELETE(_taps_symbols);
VOLK_SAFE_DELETE(_hist_samples);
VOLK_SAFE_DELETE(_hist_symbols); VOLK_SAFE_DELETE(_hist_symbols);
} }
void 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 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 const* in = (gr_complex const *)input_items[0];
gr_complex *out = (gr_complex *)output_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 nout = 0; // counter for produced output items
int i = 0; // counter for consumed input items switch (_state) {
for (; i<ninput_items[0] && nout < noutput_items;) { case WAIT_FOR_PREAMBLE: {
assert(nout < noutput_items); std::vector<tag_t> v;
switch (_state) { get_tags_in_window(v, 0, history()-1, ninput, pmt::mp("preamble_start"));
case WAIT_FOR_PREAMBLE: { if (v.empty()) {
insert_sample(in[i++]); consume(0, ninput - history()+1);
uint64_t offset = 0; } else {
float phase_est = 0; tag_t const& tag = v.front();
if (get_correlation_tag(i, offset, phase_est)) { // uint64_t const offset = tag.offset - nitems_read(0) + history() - 1;
GR_LOG_DEBUG(d_logger, "next state > INITIAL_DOPPLER_ESTIMATE"); // std::cout << "========= offset= " << offset
_state = INITIAL_DOPPLER_ESTIMATE; // << " tag.offset= " << tag.offset
_sample_counter = 0; // << " 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; _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: { int const shift = recenter_filter_taps();
_samples.push_back(in[i++]); if (shift != 0)
// buffer samples and replay them later once the initial doppler estimate is there ninput_processed += shift;
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
case INITIAL_DOPPLER_ESTIMATE_CONTINUE: { _state = WAIT_FOR_FRAME_INFO;
GR_LOG_DEBUG(d_logger, "INITIAL_DOPPLER_ESTIMATE_CONTINUE"); break;
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()) { // std::cout << "FILTER_CHECK: " << i << " " << i-1-_nB << " " << i+_nF << " " << in[i] << std::endl;
GR_LOG_DEBUG(d_logger, "next state > DO_FILTER"); assert(i+_nF < nin && i-1-_nB >= 0);
_state = DO_FILTER; out[nout++] = filter(in + i - _nB, in + i + _nF+1);
} else { } // next sample
GR_LOG_DEBUG(d_logger, "next state > INITIAL_DOPPLER_ESTIMATE_CONTINUE"); consume(0, ninput_processed);
_state = INITIAL_DOPPLER_ESTIMATE_CONTINUE; break;
} } // DO_FILTER
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.
return nout; return nout;
} }
bool adaptive_dfe_impl::start() bool adaptive_dfe_impl::start()
{ {
gr::thread::scoped_lock lock(d_setlock); gr::thread::scoped_lock lock(d_setlock);
// make sure python is ready for threading _taps_samples = (gr_complex*)(volk_malloc((_nB+_nF+1)*sizeof(gr_complex), volk_get_alignment()));
if( Py_IsInitialized() ){ _taps_symbols = (gr_complex*)(volk_malloc( _nW*sizeof(gr_complex), volk_get_alignment()));
GILLock gil_lock; _hist_symbols = (gr_complex*)(volk_malloc( 2*_nW*sizeof(gr_complex), volk_get_alignment()));
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;
reset_filter();
GR_LOG_DEBUG(d_logger,str(boost::format("adaptive_dfe_impl::start() nB=%d nF=%d mu=%f alpha=%f") GR_LOG_DEBUG(d_logger,str(boost::format("adaptive_dfe_impl::start() nB=%d nF=%d mu=%f alpha=%f")
% _nB % _nF % _mu % _alpha)); % _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; return true;
} }
bool adaptive_dfe_impl::stop() bool adaptive_dfe_impl::stop()
{ {
gr::thread::scoped_lock lock(d_setlock); gr::thread::scoped_lock lock(d_setlock);
GR_LOG_DEBUG(d_logger, "adaptive_dfe_impl::stop()"); 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_samples);
VOLK_SAFE_DELETE(_taps_symbols); VOLK_SAFE_DELETE(_taps_symbols);
VOLK_SAFE_DELETE(_hist_samples);
VOLK_SAFE_DELETE(_hist_symbols); VOLK_SAFE_DELETE(_hist_symbols);
return true; 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; gr_complex filter_output = 0;
volk_32fc_x2_dot_prod_32fc(&filter_output, volk_32fc_x2_dot_prod_32fc(&filter_output,
_hist_samples+_hist_sample_index, start,
_taps_samples, _taps_samples,
_nB+_nF+1); _nB+_nF+1);
gr_complex dot_symbols=0; gr_complex dot_symbols=0;
gr::digital::constellation_sptr constell = _constellations[_constellation_index]; 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) if (constell->bits_per_symbol() > 3)
_use_symbol_taps = false; _use_symbol_taps = false;
if (_use_symbol_taps) { if (_use_symbol_taps) {
@ -397,30 +236,28 @@ gr_complex adaptive_dfe_impl::filter() {
} }
filter_output += dot_symbols; filter_output += dot_symbols;
} }
assert(_symbol_counter < _symbols.size());
gr_complex known_symbol = _symbols[_symbol_counter]; gr_complex known_symbol = _symbols[_symbol_counter];
bool const is_known = std::abs(known_symbol) > 1e-5; 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; 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; gr_complex descrambled_symbol = 0;
constell->map_to_points(jc, &descrambled_symbol); constell->map_to_points(jc, &descrambled_symbol);
if (_save_soft_decisions) { if (_save_soft_decisions) {
float const err = std::abs(descrambled_filter_output - descrambled_symbol); float const err = std::abs(descrambled_filter_output - descrambled_symbol);
_npwr_counter[_constellation_index] += (_npwr_counter[_constellation_index] < _npwr_max_time_constant); std::vector<float> const soft_dec = constell->calc_soft_dec
float const alpha = 1.0f/_npwr_counter[_constellation_index]; (descrambled_filter_output, _npwr[_constellation_index].filter(err));
_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::copy(soft_dec.begin(), soft_dec.end(), std::back_inserter<std::vector<float> >(_vec_soft_decisions)); std::copy(soft_dec.begin(), soft_dec.end(), std::back_inserter<std::vector<float> >(_vec_soft_decisions));
} }
known_symbol = _scramble[_symbol_counter] * descrambled_symbol; known_symbol = _scramble[_symbol_counter] * descrambled_symbol;
} }
// std::cout << "FILTER: " << filter_output <<" " << known_symbol << " " << start[_nB+1] << std::endl;
if (is_known || update_taps) { if (is_known || update_taps) {
gr_complex const err = filter_output - known_symbol; gr_complex const err = filter_output - known_symbol;
for (int j=0; j<_nB+_nF+1; ++j) { 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(start[j]);
_taps_samples[j] -= _mu*err*std::conj(_hist_samples[_hist_sample_index+j]);
}
if (_use_symbol_taps) { if (_use_symbol_taps) {
for (int j=0; j<_nW; ++j) { for (int j=0; j<_nW; ++j) {
assert(_hist_symbol_index+j < 2*_nW); 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++]); 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)) // get max(abs(taps))
ssize_t const idx_max = std::distance(_taps_samples, ssize_t const idx_max = std::distance(_taps_samples,
std::max_element(_taps_samples+_nB+1-3*_sps, _taps_samples+_nB+1+3*_sps, std::max_element(_taps_samples+_nB+1-3*_sps, _taps_samples+_nB+1+3*_sps,
[](gr_complex a, gr_complex b) { [](gr_complex a, gr_complex b) {
return std::norm(a) < std::norm(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]))); // 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) {
if (idx_max-_nB-1 >= 2*_sps && _saved_samples.empty() && _ignore_filter_updates==0) {
// maximum is right of the center tap // maximum is right of the center tap
// -> shift taps to the left left // -> shift taps to the left left
GR_LOG_DEBUG(d_logger, "shift left"); GR_LOG_DEBUG(d_logger, "shift left");
std::copy(_taps_samples+2*_sps, _taps_samples+_nB+_nF+1, _taps_samples); 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)); 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 return +2*_sps;
_ignore_filter_updates = 2; }
if (idx_max-_nB-1 < -2*_sps) {
} else if (idx_max-_nB-1 <= -2*_sps && _saved_samples.empty() && _ignore_filter_updates==0) {
// maximum is left of the center tap // maximum is left of the center tap
// -> shift taps to the right // -> shift taps to the right
GR_LOG_DEBUG(d_logger, "shift right"); GR_LOG_DEBUG(d_logger, "shift right");
std::copy_backward(_taps_samples, _taps_samples+_nB+_nF+1-2*_sps, std::copy_backward(_taps_samples, _taps_samples+_nB+_nF+1-2*_sps,
_taps_samples+_nB+_nF+1); _taps_samples+_nB+_nF+1);
std::fill_n(_taps_samples, 2*_sps, gr_complex(0)); std::fill_n(_taps_samples, 2*_sps, gr_complex(0));
// save the last 2*_sps samples (will be reinserted) return -2*_sps;
_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 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); _constellations.resize(n);
_npwr.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) { for (int i=0; i<n; ++i) {
boost::python::numpy::ndarray const& array = boost::python::numpy::array(obj[i]); pmt::pmt_t c = pmt::vector_ref(data, i);
char const* data = array.get_data(); int const idx = pmt::to_long(pmt::dict_ref(c, pmt::mp("idx"), pmt::from_long(-1)));
int const m = array.shape(0); assert(idx>=0 && idx < n);
std::vector<gr_complex> constell(m); _constellations[idx] = gr::digital::constellation_calcdist::make
std::vector<int> pre_diff_code(m); (pmt::c32vector_elements(pmt::dict_ref(c, pmt::mp("points"), pmt::PMT_NIL)),
for (int j=0; j<m; ++j) { pmt::s32vector_elements(pmt::dict_ref(c, pmt::mp("symbols"), pmt::PMT_NIL)),
std::memcpy(&constell[j], data+9*j, sizeof(gr_complex)); rotational_symmetry, dimensionality);
pre_diff_code[j] = (data+9*j)[8]; _npwr[i].reset(_npwr_max_time_constant);
}
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;
} }
} }
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) { void adaptive_dfe_impl::update_frame_info(pmt::pmt_t data)
if (doppler == 0) {
return; //GR_LOG_DEBUG(d_logger,str(boost::format("adaptive_dfe_impl::update_frame_info() %s") % data));
float const delta_f = doppler/_sps; _symbols = pmt::c32vector_elements(pmt::dict_ref(data, pmt::mp("symb"), pmt::PMT_NIL));
if (_df == 0) { // init _scramble = pmt::c32vector_elements(pmt::dict_ref(data, pmt::mp("scramble"), pmt::PMT_NIL));
_ud = _df = delta_f; _constellation_index = pmt::to_long(pmt::dict_ref(data, pmt::mp("constellation_idx"), pmt::PMT_NIL));
} else { _save_soft_decisions = pmt::to_bool(pmt::dict_ref(data, pmt::mp("save_soft_dec"), pmt::PMT_F));
float const ud_old = _ud; bool const do_continue = pmt::to_bool(pmt::dict_ref(data, pmt::mp("do_continue"), pmt::PMT_F));
_ud = delta_f; assert(_symbols.size() == _scramble.size());
_df +=_b[0]*_ud + _b[1]*ud_old; _descrambled_symbols.resize(_symbols.size());
} _vec_soft_decisions.clear();
GR_LOG_DEBUG(d_logger, str(boost::format("PLL: df=%f delta_f=%f (rad/sample)") % _df % delta_f)); _symbol_counter = 0;
} _state = (do_continue ? DO_FILTER : WAIT_FOR_PREAMBLE);
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;
} }
} /* namespace digitalhf */ } /* namespace digitalhf */

View File

@ -21,18 +21,42 @@
#ifndef INCLUDED_DIGITALHF_ADAPTIVE_DFE_IMPL_H #ifndef INCLUDED_DIGITALHF_ADAPTIVE_DFE_IMPL_H
#define 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 <gnuradio/digital/constellation.h>
#include <digitalhf/adaptive_dfe.h> #include <digitalhf/adaptive_dfe.h>
namespace gr { namespace gr {
namespace digitalhf { 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 { class adaptive_dfe_impl : public adaptive_dfe {
private: private:
int _sps; int _sps;
int _nB, _nF, _nW; int _nB, _nF, _nW;
int _nGuard;
float _mu; float _mu;
float _alpha; float _alpha;
@ -40,64 +64,45 @@ private:
bool _use_symbol_taps; bool _use_symbol_taps;
// module name w.r.t. digitalhf.physical_layer containing a PhysicalLayer class // module name w.r.t. digitalhf.physical_layer containing a PhysicalLayer class
std::string _py_module_name; // std::string _py_module_name;
boost::python::object _physicalLayer; // class instance of physical layer description // boost::python::object _physicalLayer; // class instance of physical layer description
gr_complex* _taps_samples; gr_complex* _taps_samples;
gr_complex* _taps_symbols; gr_complex* _taps_symbols;
gr_complex* _hist_samples;
gr_complex* _hist_symbols; gr_complex* _hist_symbols;
int _hist_sample_index;
int _hist_symbol_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<gr::digital::constellation_sptr> _constellations;
std::vector<float> _npwr; std::vector<constellation_distance_filter> _npwr;
std::vector<int> _npwr_counter;
int _npwr_max_time_constant; int _npwr_max_time_constant;
int _constellation_index; int _constellation_index;
std::vector<gr_complex> _samples;
std::vector<gr_complex> _symbols; std::vector<gr_complex> _symbols;
std::vector<gr_complex> _scramble; std::vector<gr_complex> _scramble;
std::vector<gr_complex> _descrambled_symbols; std::vector<gr_complex> _descrambled_symbols;
int _symbol_counter; int _symbol_counter;
bool _need_samples;
bool _save_soft_decisions; bool _save_soft_decisions;
std::vector<float> _vec_soft_decisions; std::vector<float> _vec_soft_decisions;
pmt::pmt_t _msg_port_name; std::map<std::string, pmt::pmt_t> _msg_ports;
pmt::pmt_t _msg_metadata; 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;
enum state { enum state {
WAIT_FOR_PREAMBLE, WAIT_FOR_PREAMBLE,
INITIAL_DOPPLER_ESTIMATE, WAIT_FOR_FRAME_INFO,
INITIAL_DOPPLER_ESTIMATE_CONTINUE,
DO_FILTER DO_FILTER
} _state; } _state;
void update_constellations(boost::python::object obj); // void update_constellations(boost::python::object obj);
bool update_frame_information(boost::python::object obj); void update_constellations(pmt::pmt_t );
bool update_doppler_information(boost::python::object obj); void update_frame_info(pmt::pmt_t );
void update_local_oscillator(); gr_complex filter(gr_complex const* start, gr_complex const* end);
gr_complex filter(); int recenter_filter_taps();
void recenter_filter_taps(); void reset_filter();
void insert_sample(gr_complex z); void publish_frame_info();
void update_pll(float doppler); void publish_soft_dec();
bool get_correlation_tag(uint64_t i, uint64_t& offset, float& phase_est);
public: public:
adaptive_dfe_impl(int sps, // samples per symbol adaptive_dfe_impl(int sps, // samples per symbol
@ -105,8 +110,7 @@ public:
int nF, // number of backward FIR taps int nF, // number of backward FIR taps
int nW, // number of symbol taps int nW, // number of symbol taps
float mu, float mu,
float alpha, float alpha);
std::string physical_layer_description);
virtual ~adaptive_dfe_impl(); virtual ~adaptive_dfe_impl();
void forecast (int noutput_items, gr_vector_int &ninput_items_required); void forecast (int noutput_items, gr_vector_int &ninput_items_required);
@ -120,8 +124,7 @@ public:
gr_vector_void_star &output_items); gr_vector_void_star &output_items);
virtual void set_mu(float mu) { _mu = mu; } virtual void set_mu(float mu) { _mu = mu; }
virtual void set_mode(std::string); virtual void set_alpha(float alpha) { _alpha = alpha; }
} ; } ;
} // namespace digitalhf } // 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_digitalhf.h"
#include "qa_adaptive_dfe.h" #include "qa_adaptive_dfe.h"
#include "qa_doppler_correction_cc.h"
CppUnit::TestSuite * CppUnit::TestSuite *
qa_digitalhf::suite() qa_digitalhf::suite()
{ {
CppUnit::TestSuite *s = new CppUnit::TestSuite("digitalhf"); CppUnit::TestSuite *s = new CppUnit::TestSuite("digitalhf");
s->addTest(gr::digitalhf::qa_adaptive_dfe::suite()); s->addTest(gr::digitalhf::qa_adaptive_dfe::suite());
s->addTest(gr::digitalhf::qa_doppler_correction_cc::suite());
return s; 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( GR_PYTHON_INSTALL(
FILES FILES
__init__.py __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) GR_ADD_TEST(qa_adaptive_dfe ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_adaptive_dfe.py)
add_subdirectory(physical_layer) 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 pass
# import any pure python here # 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): def get_constellations(self):
return self._constellations return self._constellations
def get_frame(self): def get_next_frame(self, symbols):
"""returns a tuple describing the frame: """returns a tuple describing the frame:
[0] ... known+unknown symbols and scrambling [0] ... known+unknown symbols and scrambling
[1] ... modulation type after descrambling [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 [3] ... a boolean indicating if the soft decision for the unknown
symbols are saved""" symbols are saved"""
print('-------------------- get_frame --------------------', print('-------------------- get_frame --------------------',
self._pre_counter, self._frame_counter) self._pre_counter, self._frame_counter)
## --- preamble frame ---- success = True
if self._pre_counter != 0: if self._frame_counter == -1: ## preamble mode
self._scr_data.reset() if len(symbols) == 0:
return [self._preamble,MODE_BPSK,True,False] return [self._preamble,MODE_BPSK,success,False]
## ----- data frame ------ 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: if self._frame_counter == self._num_frames_per_block:
self._frame_counter = 0 self._frame_counter = 0
scramble_for_frame = n_psk(8, np.array([self._scr_data.next() 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; 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 :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]][:]) 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 def get_doppler(self, iq_samples):
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):
"""quality check and doppler estimation for preamble""" """quality check and doppler estimation for preamble"""
success,doppler = True,0 success,doppler = True,0
if len(iq_samples) != 0: if len(iq_samples) != 0:
@ -177,21 +170,25 @@ class PhysicalLayer(object):
zp = np.array([z for z in PhysicalLayer.get_preamble()['symb'] zp = np.array([z for z in PhysicalLayer.get_preamble()['symb']
for _ in range(sps)], dtype=np.complex64) for _ in range(sps)], dtype=np.complex64)
## find starting point ## 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])) imax = np.argmax(np.abs(cc[0:2*32*sps]))
pks = cc[(imax, imax+3*32*sps),] apks = np.abs(cc[(imax, imax+3*32*sps),])
tpks = cc[imax+3*16*sps:imax+5*16*sps] tpks = np.abs(cc[imax+3*16*sps:imax+5*16*sps])
print('imax=', imax, 'apks=',np.abs(pks), print('imax=', imax, 'apks=',apks,
np.mean(np.abs(pks)), np.mean(np.abs(tpks)), np.abs(tpks)) np.mean(apks), np.mean(tpks))
success = np.mean(np.abs(pks)) > 2*np.mean(np.abs(tpks)) success = np.bool(np.mean(apks) > 5*np.mean(tpks) and
doppler = np.diff(np.unwrap(np.angle(pks)))[0]/(3*32) if success else 0 apks[0]/apks[1] > 0.5 and
apks[0]/apks[1] < 2.0)
if success: if success:
idx = np.arange(32*sps) idx = np.arange(32*sps)
pks = [np.correlate(iq_samples[imax+i*32*sps+idx], 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)] for i in range(9)]
doppler = freq_est(pks)/32 doppler = freq_est(pks)/(32*sps)
print('success=', success, 'doppler=', doppler) print('success=', success, 'doppler=', doppler,
np.abs(np.array(pks)),
np.angle(np.array(pks)))
return success,doppler return success,doppler
def decode_preamble(self, symbols): def decode_preamble(self, symbols):
@ -209,6 +206,9 @@ class PhysicalLayer(object):
self._num_frames_per_block = self._block_len/self._frame_len; self._num_frames_per_block = self._block_len/self._frame_len;
return True return True
def set_mode(self, _):
pass
@staticmethod @staticmethod
def get_preamble(): def get_preamble():
"""preamble symbols + scrambler""" """preamble symbols + scrambler"""
@ -217,12 +217,11 @@ class PhysicalLayer(object):
dtype=[('symb', np.complex64), dtype=[('symb', np.complex64),
('scramble', np.complex64)]) ('scramble', np.complex64)])
@staticmethod def get_preamble_z(self):
def get_preamble_z(sps):
"""preamble symbols for preamble correlation""" """preamble symbols for preamble correlation"""
a = PhysicalLayer.get_preamble() a = PhysicalLayer.get_preamble()
return np.array([z for z in a['symb'][0:32*3] return 0,np.array([z for z in a['symb'][0:3*32]
for _ in range(sps)]) for _ in range(self._sps)])
if __name__ == '__main__': if __name__ == '__main__':
def gen_data_scramble(): def gen_data_scramble():
@ -238,20 +237,23 @@ if __name__ == '__main__':
a[i] = s&7; a[i] = s&7;
return a return a
p=PhysicalLayer(5) sps = 5;
z1=np.array([x for x in PRE_SYMBOLS for _ in range(5)]) p=PhysicalLayer(sps)
z2=np.array([x for x in PRE_SCRAMBLE for _ in range(5)]) z1=np.array([x for x in PRE_SYMBOLS for _ in range(sps)])
z=z1*z2 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): 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(np.sum(np.sum(z[0:32*5] * np.conj(z[32*5*3:32*5*4]))))
print(WALSH[1][:]) #print(WALSH[1][:])
print(sum(WALSH[1][:]*(1<<np.array(range(7,-1,-1))))) #print(sum(WALSH[1][:]*(1<<np.array(range(7,-1,-1)))))
print(FROM_WALSH) #print(FROM_WALSH)
print(gen_data_scramble()) #print(gen_data_scramble())
s=ScrambleData() 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) range(64)), CONST_DTYPE)
## for test ## for test
QAM64 = QAM64[(7,3,24,56,35,39,60,28),] #QAM64 = QAM64[(7,3,24,56,35,39,60,28),]
QAM64['symbols'] = [1, 0, 2, 6, 4, 5, 7, 3] #QAM64['symbols'] = [1, 0, 2, 6, 4, 5, 7, 3]
## ---- constellation indices --------------------------------------------------- ## ---- constellation indices ---------------------------------------------------
MODE_BPSK = 0 MODE_BPSK = 0
@ -142,118 +142,111 @@ class PhysicalLayer(object):
def get_constellations(self): def get_constellations(self):
return self._constellations return self._constellations
def get_frame(self): def get_next_frame(self, symbols):
"""returns a tuple describing the frame: """returns a tuple describing the frame:
[0] ... known+unknown symbols and scrambling [0] ... known+unknown symbols and scrambling
[1] ... modulation type after descrambling [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 [3] ... a boolean indicating if the soft decision for the unknown
symbols are saved""" symbols are saved"""
print('-------------------- get_frame --------------------', print('-------------------- get_frame --------------------', self._frame_counter)
self._frame_counter) success = True
## --- preamble frame ---- if self._frame_counter == -1: ## ---- preamble
if self._frame_counter == -1:
self._preamble_offset = 0 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 self._frame_counter += 1
success = True return [self._preamble,MODE_BPSK,success,False]
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
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""" """quality check and doppler estimation for preamble"""
success,doppler = True,0 success,doppler = True,0
if len(iq_samples) != 0: if len(iq_samples) != 0:
sps = self._sps sps = self._sps
idx = np.arange(23*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]) cc = np.correlate(iq_samples, zp[idx])
imax = np.argmax(np.abs(cc[0:23*sps])) imax = np.argmax(np.abs(cc[0:23*sps]))
pks = [np.correlate(iq_samples[imax+i*23*sps+idx], pks = [np.correlate(iq_samples[imax+i*23*sps+idx],
zp[i*23*sps+idx])[0] zp[i*23*sps+idx])[0]
for i in range(7)] for i in range(8)]
success = np.mean(np.abs(pks)) > 2*np.mean(np.abs(cc[imax+11*sps+range(-sps,sps)])) 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)]))) print('test:',imax, np.mean(np.abs(pks)), np.mean(np.abs(cc[imax+11*sps+range(-sps,sps)])))
if success: if success:
print('doppler apks', np.abs(pks)) print('doppler apks', np.abs(pks))
print('doppler ppks', np.angle(pks), print('doppler ppks', np.angle(pks),
np.diff(np.unwrap(np.angle(pks)))/23, np.diff(np.unwrap(np.angle(pks)))/23,
np.mean(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) print('success=', success, 'doppler=', doppler)
return success,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= 0 -> 1st reinserted preamble
offset=-72 -> all following reinserted preambles""" offset=-72 -> all following reinserted preambles"""
print('make_reinserted_preamble', offset, success)
a=np.array(zip(REINSERTED_PREAMBLE[offset:], a=np.array(zip(REINSERTED_PREAMBLE[offset:],
REINSERTED_PREAMBLE[offset:]), REINSERTED_PREAMBLE[offset:]),
dtype=[('symb', np.complex64), dtype=[('symb', np.complex64),
('scramble', np.complex64)]) ('scramble', np.complex64)])
a['symb'][-72:-72+3*13] = 0 ## D0,D1,D2 a['symb'][-72:-72+3*13] = 0 ## D0,D1,D2
if not success:
sefl._frame_counter = -1
return a 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 self._preamble_offset = -72 ## all following reinserted preambles start at index -72
a=np.zeros(256+31, dtype=[('symb', np.complex64), a=np.zeros(256+31, dtype=[('symb', np.complex64),
('scramble', np.complex64)]) ('scramble', np.complex64)])
a['scramble'][:256] = self._data_scramble a['scramble'][:256] = self._data_scramble
n = self._frame_counter -1 n = (self._frame_counter-2)%72
m = n%18 m = n%18
if m == 0: if m == 0:
cnt = n//18 cnt = n//18
@ -261,6 +254,8 @@ class PhysicalLayer(object):
print('new mini-probe signs n=',n,'m=',m,self._mp) print('new mini-probe signs n=',n,'m=',m,self._mp)
a['symb'][256:] = MINI_PROBE[self._mp[m]] a['symb'][256:] = MINI_PROBE[self._mp[m]]
a['scramble'][256:] = MINI_PROBE[self._mp[m]] a['scramble'][256:] = MINI_PROBE[self._mp[m]]
if not success:
self._frame_counter = -1
return a return a
@staticmethod @staticmethod
@ -270,10 +265,10 @@ class PhysicalLayer(object):
PREAMBLE), PREAMBLE),
dtype=[('symb', np.complex64), dtype=[('symb', np.complex64),
('scramble', np.complex64)]) ('scramble', np.complex64)])
@staticmethod
def get_preamble_z(sps): def get_preamble_z(self):
"""preamble symbols for preamble correlation""" """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__': if __name__ == '__main__':
print(PREAMBLE) print(PREAMBLE)

View File

@ -12,7 +12,7 @@ class PhysicalLayer(object):
def __init__(self, sps): def __init__(self, sps):
"""intialization""" """intialization"""
self._sps = sps self._sps = sps
self._mode = self.MODE_BPSK self._mode = self.MODE_QPSK
self._frame_counter = 0 self._frame_counter = 0
self._is_first_frame = True self._is_first_frame = True
self._constellations = [self.make_psk(2, [0,1]), self._constellations = [self.make_psk(2, [0,1]),
@ -29,50 +29,53 @@ class PhysicalLayer(object):
def get_constellations(self): def get_constellations(self):
return self._constellations return self._constellations
def get_frame(self): def get_next_frame(self, symbols):
"""returns a tuple describing the frame: """returns a tuple describing the frame:
[0] ... known+unknown symbols and scrambling [0] ... known+unknown symbols and scrambling
[1] ... modulation type after descrambling [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""" [3] ... a boolean indicating if the soft decision for the unknown symbols are saved"""
print('-------------------- get_frame --------------------', self._frame_counter) ## print('-------------------- get_frame --------------------', self._frame_counter, len(symbols))
return [self._preamble,self.MODE_BPSK,True,False] if self.is_preamble() else [self._data,self._mode,False,True] 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 """returns a tuple
[0] ... quality flag [0] ... quality flag
[1] ... doppler estimate (rad/symbol) if available""" [1] ... doppler estimate (rad/symbol) if available"""
print('-------------------- get_doppler --------------------', self._frame_counter,len(symbols),len(iq_samples)) ## print('-------------------- get_doppler --------------------', self._frame_counter,len(iq_samples))
success,doppler = self.quality_preamble(symbols,iq_samples) if self.is_preamble() else self.quality_data(symbols) success,doppler = False,0
if len(symbols) != 0: if len(iq_samples) == 0:
self._frame_counter = (self._frame_counter+1)&1 if success else 0 return success,doppler
self._is_first_frame = not success
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 return success,doppler
def is_preamble(self): def is_preamble(self):
return self._frame_counter == 0 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): def quality_data(self, s):
"""quality check for the data frame""" """quality check for the data frame"""
known_symbols = np.mod(range(176),48)>=32 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 success = np.sum(np.real(s[known_symbols])<0) < 20
return success,0 ## no doppler estimate for data frames 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 @staticmethod
def get_preamble(): def get_preamble():
"""preamble symbols + scrambler(=1)""" """preamble symbols + scrambler(=1)"""
@ -117,7 +125,7 @@ class PhysicalLayer(object):
@staticmethod @staticmethod
def make_psk(n, gray_code): def make_psk(n, gray_code):
"""generates n-PSK constellation data""" """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['points'] = np.exp(2*np.pi*1j*np.arange(n)/n)
c['symbols'] = gray_code c['symbols'] = gray_code
return c return c

View File

@ -3,7 +3,7 @@
import numpy as np import numpy as np
CONST_DTYPE=np.dtype([('points', np.complex64), CONST_DTYPE=np.dtype([('points', np.complex64),
('symbols', np.uint8)]) ('symbols', np.int32)])
def n_psk(n,x): def n_psk(n,x):
"""n-ary PSK constellation""" """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/adaptive_dfe.h"
#include "digitalhf/doppler_correction_cc.h"
%} %}
%include "digitalhf/adaptive_dfe.h" %include "digitalhf/adaptive_dfe.h"
GR_SWIG_BLOCK_MAGIC2(digitalhf, adaptive_dfe); GR_SWIG_BLOCK_MAGIC2(digitalhf, adaptive_dfe);
%include "digitalhf/doppler_correction_cc.h"
GR_SWIG_BLOCK_MAGIC2(digitalhf, doppler_correction_cc);