diff --git a/CMakeLists.txt b/CMakeLists.txt index 38f2fd2..558852f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ # Project setup ######################################################################## cmake_minimum_required(VERSION 2.6) +set(CMAKE_CXX_STANDARD 11) project(gr-digitalhf CXX C) enable_testing() @@ -148,7 +149,7 @@ find_package(Doxygen) # components required to the list of GR_REQUIRED_COMPONENTS (in all # caps such as FILTER or FFT) and change the version to the minimum # API compatible version required. -set(GR_REQUIRED_COMPONENTS RUNTIME DIGITAL) +set(GR_REQUIRED_COMPONENTS RUNTIME DIGITAL VOLK) find_package(Gnuradio "3.7.2" REQUIRED) list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules) include(GrVersion) diff --git a/examples/1st.grc b/examples/1st.grc index 50a7750..31b039f 100644 --- a/examples/1st.grc +++ b/examples/1st.grc @@ -117,7 +117,7 @@ value - 10*sps + 12*sps @@ -144,7 +144,7 @@ value - 5*sps + 12*sps @@ -395,6 +395,14 @@ id digitalhf_adaptive_dfe_0 + + maxoutbuf + 0 + + + minoutbuf + 0 + sps sps @@ -416,6 +424,373 @@ STANAG_4285 + + qtgui_time_sink_x + + autoscale + False + + + axislabels + True + + + alias + + + + comment + + + + ctrlpanel + False + + + affinity + + + + entags + True + + + _enabled + True + + + _coordinate + (874, 176) + + + gui_hint + + + + _rotation + 0 + + + grid + False + + + id + qtgui_time_sink_x_0 + + + legend + True + + + alpha1 + 1.0 + + + color1 + "blue" + + + label1 + + + + marker1 + -1 + + + style1 + 1 + + + width1 + 1 + + + alpha10 + 1.0 + + + color10 + "blue" + + + label10 + + + + marker10 + -1 + + + style10 + 1 + + + width10 + 1 + + + alpha2 + 1.0 + + + color2 + "red" + + + label2 + + + + marker2 + -1 + + + style2 + 1 + + + width2 + 1 + + + alpha3 + 1.0 + + + color3 + "green" + + + label3 + + + + marker3 + -1 + + + style3 + 1 + + + width3 + 1 + + + alpha4 + 1.0 + + + color4 + "black" + + + label4 + + + + marker4 + -1 + + + style4 + 1 + + + width4 + 1 + + + alpha5 + 1.0 + + + color5 + "cyan" + + + label5 + + + + marker5 + -1 + + + style5 + 1 + + + width5 + 1 + + + alpha6 + 1.0 + + + color6 + "magenta" + + + label6 + + + + marker6 + -1 + + + style6 + 1 + + + width6 + 1 + + + alpha7 + 1.0 + + + color7 + "yellow" + + + label7 + + + + marker7 + -1 + + + style7 + 1 + + + width7 + 1 + + + alpha8 + 1.0 + + + color8 + "dark red" + + + label8 + + + + marker8 + -1 + + + style8 + 1 + + + width8 + 1 + + + alpha9 + 1.0 + + + color9 + "dark green" + + + label9 + + + + marker9 + -1 + + + style9 + 1 + + + width9 + 1 + + + name + "" + + + nconnections + 1 + + + size + 1024 + + + srate + samp_rate + + + stemplot + False + + + tr_chan + 0 + + + tr_delay + 0 + + + tr_level + 0.0 + + + tr_mode + qtgui.TRIG_MODE_FREE + + + tr_slope + qtgui.TRIG_SLOPE_POS + + + tr_tag + "" + + + type + complex + + + update_time + 0.10 + + + ylabel + Amplitude + + + yunit + "" + + + ymax + 1 + + + ymin + -1 + + analog_noise_source_x_0 blocks_throttle_0 @@ -428,4 +803,10 @@ 0 0 + + digitalhf_adaptive_dfe_0 + qtgui_time_sink_x_0 + 0 + 0 + diff --git a/examples/test_cc.grc b/examples/test_cc.grc new file mode 100644 index 0000000..86267c2 --- /dev/null +++ b/examples/test_cc.grc @@ -0,0 +1,2202 @@ + + + + Fri Oct 19 14:08:05 2018 + + options + + author + + + + window_size + + + + category + [GRC Hier Blocks] + + + comment + + + + copyright + + + + description + + + + _enabled + True + + + _coordinate + (8, 8) + + + _rotation + 0 + + + generate_options + qt_gui + + + hier_block_src_path + .: + + + id + top_block + + + max_nouts + 0 + + + qt_qss_theme + + + + realtime_scheduling + + + + run_command + {python} -u {filename} + + + run_options + prompt + + + run + True + + + sizing_mode + fixed + + + thread_safe_setters + + + + title + + + + placement + (0,0) + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (266, 570) + + + _rotation + 0 + + + id + dummy + + + value + [lpz[0].extend(x) for x in lpz[1:]] + + + + variable_qtgui_range + + comment + + + + value + 4932 + + + _enabled + True + + + _coordinate + (1130, 5) + + + gui_hint + + + + _rotation + 0 + + + id + freq + + + label + frequency + + + min_len + 200 + + + orient + Qt.Horizontal + + + start + 0 + + + step + 0.0001 + + + stop + 30e3 + + + rangeType + float + + + widget + counter_slider + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (320, 5) + + + _rotation + 0 + + + id + lpz + + + value + [[x,x,x,x,x] for x in STANAG_4285.PhysicalLayer.get_preamble()['symb'].tolist()] + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (554, 5) + + + _rotation + 0 + + + id + nB + + + value + 10*sps + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (629, 5) + + + _rotation + 0 + + + id + nF + + + value + 10*sps + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (704, 5) + + + _rotation + 0 + + + id + nW + + + value + 4 + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (224, 5) + + + _rotation + 0 + + + id + samp_rate + + + value + 12000 + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (480, 5) + + + _rotation + 0 + + + id + sps + + + value + 5 + + + + blocks_complex_to_mag + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (906, 421) + + + _rotation + 0 + + + id + blocks_complex_to_mag_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_float_to_complex + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (234, 133) + + + _rotation + 0 + + + id + blocks_float_to_complex_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_multiply_const_vxx + + alias + + + + comment + + + + const + 4 + + + affinity + + + + _enabled + True + + + _coordinate + (416, 154) + + + _rotation + 0 + + + id + blocks_multiply_const_vxx_0 + + + type + complex + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + vlen + 1 + + + + blocks_tag_debug + + alias + + + + comment + + + + affinity + + + + display + True + + + _enabled + 0 + + + _coordinate + (1034, 282) + + + _rotation + 0 + + + id + blocks_tag_debug_0 + + + type + complex + + + filter + "" + + + name + + + + num_inputs + 1 + + + vlen + 1 + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + 1 + + + _coordinate + (576, 154) + + + _rotation + 0 + + + id + blocks_throttle_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + complex + + + vlen + 1 + + + + blocks_wavfile_source + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + file + /Users/chm/Downloads/sielsdr.ddns.net_2018-10-26T11_30_27Z_6768.50_iq.wav + + + _coordinate + (10, 133) + + + _rotation + 0 + + + id + blocks_wavfile_source_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + nchan + 2 + + + repeat + False + + + + digitalhf_adaptive_dfe + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (85, 410) + + + _rotation + 0 + + + id + digitalhf_adaptive_dfe_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + sps + sps + + + nB + nB + + + nF + nF + + + nW + nW + + + py_obj_name + STANAG_4285 + + + + import + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (917, 10) + + + _rotation + 0 + + + id + import_0 + + + import + import digitalhf.physical_layer.STANAG_4285 as STANAG_4285 + + + + import + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (906, 64) + + + _rotation + 0 + + + id + import_0_0 + + + import + from gnuradio import gr + + + + digital_corr_est_cc + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (746, 133) + + + _rotation + 0 + + + id + preamble + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + sps + sps + + + symbols + lpz[0] + + + mark_delay + nF+2 + + + threshold_method + digital.corr_est_cc.THRESHOLD_DYNAMIC + + + threshold + 0.5 + + + + qtgui_const_sink_x + + autoscale + False + + + axislabels + True + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (469, 432) + + + gui_hint + + + + _rotation + 0 + + + grid + True + + + id + qtgui_const_sink_x_0 + + + legend + True + + + alpha1 + 1 + + + color1 + "blue" + + + label1 + + + + marker1 + 0 + + + style1 + 0 + + + width1 + 1 + + + alpha10 + 1.0 + + + color10 + "red" + + + label10 + + + + marker10 + 0 + + + style10 + 0 + + + width10 + 1 + + + alpha2 + 1.0 + + + color2 + "red" + + + label2 + + + + marker2 + 0 + + + style2 + 0 + + + width2 + 1 + + + alpha3 + 1.0 + + + color3 + "red" + + + label3 + + + + marker3 + 0 + + + style3 + 0 + + + width3 + 1 + + + alpha4 + 1.0 + + + color4 + "red" + + + label4 + + + + marker4 + 0 + + + style4 + 0 + + + width4 + 1 + + + alpha5 + 1.0 + + + color5 + "red" + + + label5 + + + + marker5 + 0 + + + style5 + 0 + + + width5 + 1 + + + alpha6 + 1.0 + + + color6 + "red" + + + label6 + + + + marker6 + 0 + + + style6 + 0 + + + width6 + 1 + + + alpha7 + 1.0 + + + color7 + "red" + + + label7 + + + + marker7 + 0 + + + style7 + 0 + + + width7 + 1 + + + alpha8 + 1.0 + + + color8 + "red" + + + label8 + + + + marker8 + 0 + + + style8 + 0 + + + width8 + 1 + + + alpha9 + 1.0 + + + color9 + "red" + + + label9 + + + + marker9 + 0 + + + style9 + 0 + + + width9 + 1 + + + name + "" + + + nconnections + 1 + + + size + 1024 + + + tr_chan + 0 + + + tr_level + 0.0 + + + tr_mode + qtgui.TRIG_MODE_FREE + + + tr_slope + qtgui.TRIG_SLOPE_POS + + + tr_tag + "" + + + type + complex + + + update_time + 0.1 + + + xmax + 2 + + + xmin + -2 + + + ymax + 2 + + + ymin + -2 + + + + qtgui_time_sink_x + + autoscale + True + + + axislabels + True + + + alias + + + + comment + + + + ctrlpanel + False + + + affinity + + + + entags + True + + + _enabled + True + + + _coordinate + (1098, 410) + + + gui_hint + + + + _rotation + 0 + + + grid + False + + + id + qtgui_time_sink_x_0 + + + legend + True + + + alpha1 + 1.0 + + + color1 + "blue" + + + label1 + err + + + marker1 + -1 + + + style1 + 1 + + + width1 + 1 + + + alpha10 + 1.0 + + + color10 + "blue" + + + label10 + + + + marker10 + -1 + + + style10 + 1 + + + width10 + 1 + + + alpha2 + 1.0 + + + color2 + "red" + + + label2 + rate + + + marker2 + -1 + + + style2 + 1 + + + width2 + 1 + + + alpha3 + 1.0 + + + color3 + "green" + + + label3 + phase + + + marker3 + -1 + + + style3 + 1 + + + width3 + 1 + + + alpha4 + 1.0 + + + color4 + "black" + + + label4 + + + + marker4 + -1 + + + style4 + 1 + + + width4 + 1 + + + alpha5 + 1.0 + + + color5 + "cyan" + + + label5 + + + + marker5 + -1 + + + style5 + 1 + + + width5 + 1 + + + alpha6 + 1.0 + + + color6 + "magenta" + + + label6 + + + + marker6 + -1 + + + style6 + 1 + + + width6 + 1 + + + alpha7 + 1.0 + + + color7 + "yellow" + + + label7 + + + + marker7 + -1 + + + style7 + 1 + + + width7 + 1 + + + alpha8 + 1.0 + + + color8 + "dark red" + + + label8 + + + + marker8 + -1 + + + style8 + 1 + + + width8 + 1 + + + alpha9 + 1.0 + + + color9 + "dark green" + + + label9 + + + + marker9 + -1 + + + style9 + 1 + + + width9 + 1 + + + name + "" + + + nconnections + 1 + + + size + 1024 + + + srate + samp_rate + + + stemplot + False + + + tr_chan + 0 + + + tr_delay + 0.02 + + + tr_level + 0.0 + + + tr_mode + qtgui.TRIG_MODE_TAG + + + tr_slope + qtgui.TRIG_SLOPE_POS + + + tr_tag + "time_est" + + + type + float + + + update_time + .1 + + + ylabel + preamble correlation + + + yunit + "" + + + ymax + 800 + + + ymin + 0 + + + + qtgui_time_sink_x + + autoscale + True + + + axislabels + True + + + alias + + + + comment + + + + ctrlpanel + False + + + affinity + + + + entags + True + + + _enabled + True + + + _coordinate + (1077, 197) + + + gui_hint + + + + _rotation + 0 + + + grid + False + + + id + qtgui_time_sink_x_0_0 + + + legend + True + + + alpha1 + 1.0 + + + color1 + "blue" + + + label1 + I + + + marker1 + -1 + + + style1 + 1 + + + width1 + 1 + + + alpha10 + 1.0 + + + color10 + "blue" + + + label10 + + + + marker10 + -1 + + + style10 + 1 + + + width10 + 1 + + + alpha2 + 1.0 + + + color2 + "red" + + + label2 + Q + + + marker2 + -1 + + + style2 + 1 + + + width2 + 1 + + + alpha3 + 1.0 + + + color3 + "green" + + + label3 + phase + + + marker3 + -1 + + + style3 + 1 + + + width3 + 1 + + + alpha4 + 1.0 + + + color4 + "black" + + + label4 + + + + marker4 + -1 + + + style4 + 1 + + + width4 + 1 + + + alpha5 + 1.0 + + + color5 + "cyan" + + + label5 + + + + marker5 + -1 + + + style5 + 1 + + + width5 + 1 + + + alpha6 + 1.0 + + + color6 + "magenta" + + + label6 + + + + marker6 + -1 + + + style6 + 1 + + + width6 + 1 + + + alpha7 + 1.0 + + + color7 + "yellow" + + + label7 + + + + marker7 + -1 + + + style7 + 1 + + + width7 + 1 + + + alpha8 + 1.0 + + + color8 + "dark red" + + + label8 + + + + marker8 + -1 + + + style8 + 1 + + + width8 + 1 + + + alpha9 + 1.0 + + + color9 + "dark green" + + + label9 + + + + marker9 + -1 + + + style9 + 1 + + + width9 + 1 + + + name + "" + + + nconnections + 1 + + + size + 1024 + + + srate + samp_rate + + + stemplot + False + + + tr_chan + 0 + + + tr_delay + 0.02 + + + tr_level + 0.0 + + + tr_mode + qtgui.TRIG_MODE_TAG + + + tr_slope + qtgui.TRIG_SLOPE_POS + + + tr_tag + "time_est" + + + type + complex + + + update_time + .1 + + + ylabel + preamble correlation + + + yunit + "" + + + ymax + 2 + + + ymin + -2 + + + + qtgui_waterfall_sink_x + + axislabels + True + + + bw + samp_rate + + + alias + + + + fc + 0 + + + comment + + + + affinity + + + + _enabled + True + + + fftsize + 128 + + + _coordinate + (1077, 112) + + + gui_hint + + + + _rotation + 0 + + + grid + False + + + id + qtgui_waterfall_sink_x_0 + + + int_max + 10 + + + int_min + -140 + + + legend + True + + + alpha1 + 1.0 + + + color1 + 0 + + + label1 + + + + alpha10 + 1.0 + + + color10 + 0 + + + label10 + + + + alpha2 + 1.0 + + + color2 + 0 + + + label2 + + + + alpha3 + 1.0 + + + color3 + 0 + + + label3 + + + + alpha4 + 1.0 + + + color4 + 0 + + + label4 + + + + alpha5 + 1.0 + + + color5 + 0 + + + label5 + + + + alpha6 + 1.0 + + + color6 + 0 + + + label6 + + + + alpha7 + 1.0 + + + color7 + 0 + + + label7 + + + + alpha8 + 1.0 + + + color8 + 0 + + + label8 + + + + alpha9 + 1.0 + + + color9 + 0 + + + label9 + + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + name + "" + + + nconnections + 1 + + + showports + True + + + freqhalf + True + + + type + complex + + + update_time + 0.10 + + + wintype + firdes.WIN_BLACKMAN_hARRIS + + + + blocks_complex_to_mag_0 + qtgui_time_sink_x_0 + 0 + 0 + + + blocks_float_to_complex_0 + blocks_multiply_const_vxx_0 + 0 + 0 + + + blocks_multiply_const_vxx_0 + blocks_throttle_0 + 0 + 0 + + + blocks_throttle_0 + preamble + 0 + 0 + + + blocks_wavfile_source_0 + blocks_float_to_complex_0 + 0 + 0 + + + blocks_wavfile_source_0 + blocks_float_to_complex_0 + 1 + 1 + + + digitalhf_adaptive_dfe_0 + qtgui_const_sink_x_0 + 0 + 0 + + + preamble + blocks_complex_to_mag_0 + 1 + 0 + + + preamble + blocks_tag_debug_0 + 0 + 0 + + + preamble + digitalhf_adaptive_dfe_0 + 0 + 0 + + + preamble + qtgui_time_sink_x_0_0 + 0 + 0 + + + preamble + qtgui_waterfall_sink_x_0 + 0 + 0 + + diff --git a/grc/digitalhf_adaptive_dfe.xml b/grc/digitalhf_adaptive_dfe.xml index 4d7a928..58b2cbd 100644 --- a/grc/digitalhf_adaptive_dfe.xml +++ b/grc/digitalhf_adaptive_dfe.xml @@ -51,8 +51,9 @@ * type * vlen * optional (set to 1 for optional inputs) --> - - - - + + out + complex + + diff --git a/lib/adaptive_dfe_impl.cc b/lib/adaptive_dfe_impl.cc index aaa714c..c0ec835 100644 --- a/lib/adaptive_dfe_impl.cc +++ b/lib/adaptive_dfe_impl.cc @@ -23,6 +23,7 @@ #endif #include +#include #include "adaptive_dfe_impl.h" namespace gr { @@ -31,7 +32,7 @@ namespace digitalhf { namespace { class GILLock { PyGILState_STATE _state; - public: +public: GILLock() :_state(PyGILState_Ensure()) {} ~GILLock() { @@ -39,6 +40,7 @@ class GILLock { } } ; } + adaptive_dfe::sptr adaptive_dfe::make(int sps, // samples per symbol int nB, // number of forward FIR taps @@ -60,29 +62,35 @@ adaptive_dfe_impl::adaptive_dfe_impl(int sps, // samples per symbol std::string python_module_name) : gr::block("adaptive_dfe", gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(0, 0, sizeof(gr_complex))) + gr::io_signature::make(1, 1, sizeof(gr_complex))) , _sps(sps) , _nB(nB) , _nF(nF) , _nW(nW) + , _mu(0.01) + , _alpha(0.0005) , _py_module_name(python_module_name) , _physicalLayer() - , _taps_samples(nB+nF+1) - , _taps_symbols(nW) + , _taps_samples(nullptr) + , _taps_symbols(nullptr) + , _hist_samples(nullptr) + , _hist_symbols(nullptr) + , _hist_sample_index(0) + , _hist_symbol_index(0) + , _sample_counter(0) , _constellations() , _constellation_index() , _symbols() , _scramble() + , _descrambled_symbols() + , _symbol_counter(0) + , _sum_phase_diff(0) + , _df(0) + , _phase(0) + , _b{0.338187046465954, -0.288839024460507} + , _ud(0) + , _state(WAIT_FOR_PREAMBLE) { - // make sure python is ready for threading - if( Py_IsInitialized() ){ - if(PyEval_ThreadsInitialized() != 1 ){ - PyEval_InitThreads(); - } - boost::python::numpy::initialize(); - } else { - throw std::runtime_error("dont use es_pyhandler without python!"); - } } /* @@ -95,7 +103,7 @@ adaptive_dfe_impl::~adaptive_dfe_impl() void adaptive_dfe_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) { - /* <+forecast+> e.g. ninput_items_required[0] = noutput_items */ + ninput_items_required[0] = _sps*noutput_items; } int @@ -104,21 +112,177 @@ adaptive_dfe_impl::general_work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { + gr::thread::scoped_lock lock(d_setlock); gr_complex const* in = (gr_complex const *)input_items[0]; + gr_complex *out = (gr_complex *)output_items[0]; - GILLock lock; - // TODO: wait for preamble correlation tag etc... - update_frame_information(_physicalLayer.attr("get_frame")()); - update_doppler_information(_physicalLayer.attr("get_doppler")()); // symbols + int nout = 0; + int i = 0; + for (; i M_PI) + _phase -= 2*M_PI; + if (_phase < -M_PI) + _phase += 2*M_PI; - consume_each (noutput_items); + _hist_samples[_hist_sample_index] = _hist_samples[_hist_sample_index+_nB+_nF+1] = in[i] * std::exp(gr_complex(0,_phase)); + if (++_hist_sample_index == _nB+_nF+1) + _hist_sample_index = 0; + + if (_state == WAIT_FOR_PREAMBLE) { + std::vector v; + get_tags_in_window(v, 0, i,i+1); + float phase_est = 0; + float corr_est = 0; + uint64_t offset = 0; + for (int j=0; j 130e3) { + offset = v[j].offset - nitems_read(0); + break; + } + } + } + if (corr_est > 130e3) { + _state = DO_FILTER; + _sample_counter = 0; + _symbol_counter = 0; + // _symbols.clear(); + // _scramble.clear(); + _descrambled_symbols.clear(); + // _hist_sample_index = 0; + _hist_symbol_index = 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)); + //_phase = -phase_est; + _taps_samples[_nB+1] = std::exp(gr_complex(0, -phase_est)); + _taps_symbols[0] = 1; + GILLock lock; + try { + update_frame_information(_physicalLayer.attr("get_frame")()); + } catch (boost::python::error_already_set const&) { + PyErr_Print(); + } + } + } + if (_state == DO_FILTER) { + gr_complex dot_samples = 0; + // volk_32fc_x2_dot_prod_32fc(&dot_samples, + // &_hist_samples.front()+_hist_sample_index, + // &_taps_samples.front(), + // _taps_samples.size()); + gr_complex filter_output = dot_samples; + // if (_sample_counter < 80*5) + // std::cout << "SAMPLE " << _sample_counter << " " << dot_samples << std::endl; + if ((_sample_counter%_sps) == 0) { + if (_symbol_counter == _symbols.size()) { + _symbol_counter = 0; + GILLock lock; + try { + boost::python::numpy::ndarray s = boost::python::numpy::from_data(&_descrambled_symbols.front(), + boost::python::numpy::dtype::get_builtin(), + boost::python::make_tuple(_descrambled_symbols.size()), + boost::python::make_tuple(sizeof(gr_complex)), + boost::python::object()); + update_doppler_information(_physicalLayer.attr("get_doppler")(s)); + update_frame_information(_physicalLayer.attr("get_frame")()); + } catch (boost::python::error_already_set const&) { + PyErr_Print(); + } + } + gr_complex known_symbol = _symbols[_symbol_counter]; + bool is_known = true; + for (int k=0; k<1; ++k) { + filter_output = 0; +#if 1 + volk_32fc_x2_dot_prod_32fc(&filter_output, + _hist_samples+_hist_sample_index, + _taps_samples, + _nB+_nF+1); +#else + for (int l=0; l<_nB+_nF+1; ++l) { + assert(_hist_sample_index+l < 2*(_nB+_nF+1)); + filter_output += _hist_samples[_hist_sample_index+l]*_taps_samples[l]; + } +#endif + gr_complex dot_symbols=0; + for (int l=0; l<_nW; ++l) { + assert(_hist_symbol_index+l < 2*_nW); + dot_symbols += _hist_symbols[_hist_symbol_index+l]*_taps_symbols[l]; + } + filter_output += dot_symbols; + if (std::abs(known_symbol) < 1e-5) { // not known + is_known = false; + gr_complex descrambled_filter_output = std::conj(_scramble[_symbol_counter]) * filter_output; + gr::digital::constellation_sptr constell = _constellations[_constellation_index]; + unsigned int jc = constell->decision_maker(&descrambled_filter_output); + constell->map_to_points(jc, &descrambled_filter_output); + known_symbol = _scramble[_symbol_counter] * descrambled_filter_output; + } + gr_complex err = filter_output - known_symbol; + if (_symbol_counter >= 0) { + for (int j=0; j<_nB+_nF+1; ++j) { + _taps_samples[j] -= _mu*err*std::conj(_hist_samples[_hist_sample_index+j]); + } + for (int j=0; j<_nW; ++j) { + assert(_hist_symbol_index+j < 2*_nW); + _taps_symbols[j] -= _mu*err*std::conj(_hist_symbols[_hist_symbol_index+j]) + _alpha*_taps_symbols[j]; + } + } + // std::cout << "filter: " << _symbol_counter << " " << _sample_counter << " " << filter_output << " " << known_symbol << " " << std::abs(err) << std::endl; + } + if (is_known) { + _taps_symbols[_hist_symbol_index] = _taps_symbols[_hist_symbol_index + _nW] = known_symbol; + if (++_hist_symbol_index == _nW) + _hist_symbol_index = 0; + } + _descrambled_symbols[_symbol_counter] = filter_output*std::conj(_scramble[_symbol_counter]); + out[nout++] = filter_output; + ++_symbol_counter; + } + _sample_counter += 1; + } + } + + consume(0, i); // Tell runtime system how many output items we produced. - return noutput_items; + return nout; } bool adaptive_dfe_impl::start() { + // make sure python is ready for threading + if( Py_IsInitialized() ){ + GILLock lock; + if(PyEval_ThreadsInitialized() != 1 ){ + PyEval_InitThreads(); + } + boost::python::numpy::initialize(); + } else { + throw std::runtime_error("dont use es_pyhandler 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())); + _taps_samples[_nB+1] = 1; + _taps_symbols[0] = 1; + std::cout << "adaptive_dfe_impl::start()" << std::endl; GILLock lock; try { @@ -137,6 +301,10 @@ bool adaptive_dfe_impl::stop() std::cout << "adaptive_dfe_impl::stop()" << std::endl; GILLock lock; _physicalLayer = boost::python::object(); + volk_free(_taps_samples); + volk_free(_taps_symbols); + volk_free(_hist_samples); + volk_free(_hist_symbols); return true; } @@ -168,9 +336,11 @@ void adaptive_dfe_impl::update_frame_information(boost::python::object obj) int const m = array.shape(0); _symbols.resize(m); _scramble.resize(m); + _descrambled_symbols.resize(m); for (int i=0; i(obj[1]); } @@ -180,7 +350,17 @@ void adaptive_dfe_impl::update_doppler_information(boost::python::object obj) assert(n==2); double const do_continue = boost::python::extract(obj[0]); double const doppler = boost::python::extract(obj[1]); - // TODO + + float delta_f = doppler/_sps; + if (_df == 0) { // init + _ud = _df = -delta_f; + } else { + const float ud_old = _ud; + _ud = -delta_f; + _df +=_b[0]*_ud + _b[1]*ud_old; + } + std::cout << "PLL: " << _df << " " << delta_f << std::endl; + _sum_phase_diff = 0; } } /* namespace digitalhf */ diff --git a/lib/adaptive_dfe_impl.h b/lib/adaptive_dfe_impl.h index 69b7bf0..28061ac 100644 --- a/lib/adaptive_dfe_impl.h +++ b/lib/adaptive_dfe_impl.h @@ -34,19 +34,42 @@ private: int _sps; int _nB, _nF, _nW; + float _mu; + float _alpha; + // module name w.r.t. digitalhf.physical_layer containing a PhysicalLayer class std::string _py_module_name; boost::python::object _physicalLayer; // class instance of physical layer description - std::vector _taps_samples; - std::vector _taps_symbols; + gr_complex* _taps_samples; + gr_complex* _taps_symbols; + + gr_complex* _hist_samples; + gr_complex* _hist_symbols; + + int _hist_sample_index; + int _hist_symbol_index; + + std::size_t _sample_counter; std::vector _constellations; int _constellation_index; std::vector _symbols; std::vector _scramble; + std::vector _descrambled_symbols; + int _symbol_counter; - int _sample_counter; + // PLL for doppler tracking + float _sum_phase_diff; + float _df; // frequency offset in radians per sample + float _phase; // accumulated phase for frequency correction + const float _b[2]; + float _ud; + + enum state { + WAIT_FOR_PREAMBLE, + DO_FILTER + } _state; void update_constellations(boost::python::object obj); void update_frame_information(boost::python::object obj); diff --git a/python/physical_layer/STANAG_4285.py b/python/physical_layer/STANAG_4285.py index 5dbc4c4..8bf4cb2 100644 --- a/python/physical_layer/STANAG_4285.py +++ b/python/physical_layer/STANAG_4285.py @@ -14,8 +14,9 @@ class PhysicalLayer(object): self._preamble = [PhysicalLayer.get_preamble(), 0] ## BPSK self._data = [PhysicalLayer.get_data(), mode] ## according to the mode self._counter = 0 + self._preamble_phases = [] - def set_mode(self): + def set_mode(self, mode): """For STANAG 4258 the mode has to be set manually: mode=0 -> BPSK, mode=1 -> QPSK, mode=2 -> 8PSK""" self._data[1] = mode @@ -24,17 +25,32 @@ class PhysicalLayer(object): def get_frame(self): """returns the known+unknown symbols and scrambling""" + print('-------------------- get_frame --------------------',self._counter) if self._counter == 0: - return self._preamble + x= self._preamble else: - return self._data + x=self._data + print('get_frame end\n') + return x; - def get_doppler(self): ## symbols + def get_doppler(self, s): """used for doppler shift update, for determining which frame to provide next, and for stopping at end of data/when the signal quality is too low""" + print('-------------------- get_doppler --------------------',self._counter) + doppler = 0 + if self._counter == 0: ## preamble + corr = s*np.conj(self._preamble[0]['symb']) + self._preamble_phases.extend([np.angle(np.sum(corr))]) + if len(self._preamble_phases) == 2 and False: + doppler = 2*(self._preamble_phases[1] - self._preamble_phases[0])/256 + print('preamble_phases', self._preamble_phases, 'doppler', doppler) + self._preamble_phases = self._preamble_phases[1:] + else: + phases = np.unwrap(np.angle(corr)) + doppler = 2*(np.median(phases[-20:]) - np.median(phases[:20]))/80 + print('doppler', doppler,self._preamble_phases) + self._counter = (self._counter+1)&1 - ## TODO: doppler calculations - doppler = 0.1234 return [True, doppler] @staticmethod @@ -67,9 +83,9 @@ class PhysicalLayer(object): ## PSK-8 modulation constellation = PhysicalLayer.make_psk(8,range(8))['points'] a['scramble'] = constellation[p,] - a['symb'][ 32: 48] = 1 ## mini-probe 1 - a['symb'][ 80: 96] = 1 ## mini-probe 2 - a['symb'][128:144] = 1 ## mini-probe 3 + a['symb'][ 32: 48] = a['scramble'][ 32: 48] ## mini-probe 1 + a['symb'][ 80: 96] = a['scramble'][ 80: 96] ## mini-probe 2 + a['symb'][128:144] = a['scramble'][128:144] ## mini-probe 3 return a @staticmethod