1
0
Fork 0
mirror of https://github.com/hb9fxq/gr-digitalhf synced 2024-12-22 15:10:00 +00:00

doppler correction using unequalized samples

This commit is contained in:
cmayer 2018-10-28 16:28:36 +01:00
parent c34a2b3975
commit 56ae39c0ed
6 changed files with 358 additions and 81 deletions

View file

@ -136,7 +136,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1120, 101)</value> <value>(1141, 80)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -210,6 +210,168 @@
<value>[[x,x,x,x,x] for x in STANAG_4285.PhysicalLayer.get_preamble()['symb'][9:40].tolist()]</value> <value>[[x,x,x,x,x] for x in STANAG_4285.PhysicalLayer.get_preamble()['symb'][9:40].tolist()]</value>
</param> </param>
</block> </block>
<block>
<key>variable_qtgui_chooser</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>value</key>
<value>0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(42, 384)</value>
</param>
<param>
<key>gui_hint</key>
<value></value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>mode</value>
</param>
<param>
<key>label0</key>
<value>PSK</value>
</param>
<param>
<key>label1</key>
<value>QPSK</value>
</param>
<param>
<key>label2</key>
<value>8PSK</value>
</param>
<param>
<key>label3</key>
<value></value>
</param>
<param>
<key>label4</key>
<value></value>
</param>
<param>
<key>label</key>
<value>mode</value>
</param>
<param>
<key>labels</key>
<value>[]</value>
</param>
<param>
<key>num_opts</key>
<value>3</value>
</param>
<param>
<key>option0</key>
<value>'0'</value>
</param>
<param>
<key>option1</key>
<value>'1'</value>
</param>
<param>
<key>option2</key>
<value>'1'</value>
</param>
<param>
<key>option3</key>
<value>3</value>
</param>
<param>
<key>option4</key>
<value>4</value>
</param>
<param>
<key>options</key>
<value>[0, 1, 2]</value>
</param>
<param>
<key>orient</key>
<value>Qt.QVBoxLayout</value>
</param>
<param>
<key>type</key>
<value>string</value>
</param>
<param>
<key>widget</key>
<value>combo_box</value>
</param>
</block>
<block>
<key>variable_qtgui_range</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>value</key>
<value>0.002</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(1024, 80)</value>
</param>
<param>
<key>gui_hint</key>
<value>(3,0,1,2)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>mu</value>
</param>
<param>
<key>label</key>
<value>mu</value>
</param>
<param>
<key>min_len</key>
<value>200</value>
</param>
<param>
<key>orient</key>
<value>Qt.Horizontal</value>
</param>
<param>
<key>start</key>
<value>0</value>
</param>
<param>
<key>step</key>
<value>0.001</value>
</param>
<param>
<key>stop</key>
<value>0.02</value>
</param>
<param>
<key>rangeType</key>
<value>float</value>
</param>
<param>
<key>widget</key>
<value>counter_slider</value>
</param>
</block>
<block> <block>
<key>variable</key> <key>variable</key>
<param> <param>
@ -234,7 +396,7 @@
</param> </param>
<param> <param>
<key>value</key> <key>value</key>
<value>12*sps</value> <value>15</value>
</param> </param>
</block> </block>
<block> <block>
@ -261,7 +423,7 @@
</param> </param>
<param> <param>
<key>value</key> <key>value</key>
<value>9*sps</value> <value>15</value>
</param> </param>
</block> </block>
<block> <block>
@ -288,7 +450,7 @@
</param> </param>
<param> <param>
<key>value</key> <key>value</key>
<value>5</value> <value>4</value>
</param> </param>
</block> </block>
<block> <block>
@ -365,7 +527,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(906, 325)</value> <value>(928, 314)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -408,7 +570,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(245, 165)</value> <value>(256, 154)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -443,7 +605,7 @@
</param> </param>
<param> <param>
<key>const</key> <key>const</key>
<value>4</value> <value>5</value>
</param> </param>
<param> <param>
<key>affinity</key> <key>affinity</key>
@ -455,7 +617,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(416, 186)</value> <value>(426, 176)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -506,7 +668,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(949, 144)</value> <value>(917, 133)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -557,7 +719,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(576, 186)</value> <value>(586, 176)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -616,7 +778,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(10, 165)</value> <value>(32, 154)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -663,7 +825,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(864, 453)</value> <value>(874, 458)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -685,6 +847,18 @@
<key>sps</key> <key>sps</key>
<value>sps</value> <value>sps</value>
</param> </param>
<param>
<key>alpha</key>
<value>0.0005</value>
</param>
<param>
<key>mode</key>
<value>mode</value>
</param>
<param>
<key>mu</key>
<value>mu</value>
</param>
<param> <param>
<key>nB</key> <key>nB</key>
<value>nB</value> <value>nB</value>
@ -784,7 +958,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(629, 282)</value> <value>(640, 272)</value>
</param> </param>
<param> <param>
<key>_rotation</key> <key>_rotation</key>
@ -812,7 +986,7 @@
</param> </param>
<param> <param>
<key>mark_delay</key> <key>mark_delay</key>
<value>nF+2-9*sps</value> <value>(nF-9)*sps+2</value>
</param> </param>
<param> <param>
<key>threshold_method</key> <key>threshold_method</key>
@ -820,7 +994,7 @@
</param> </param>
<param> <param>
<key>threshold</key> <key>threshold</key>
<value>0.3</value> <value>0.5</value>
</param> </param>
</block> </block>
<block> <block>
@ -851,7 +1025,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1088, 474)</value> <value>(1120, 496)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -1206,7 +1380,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1098, 314)</value> <value>(1120, 304)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>
@ -1573,7 +1747,7 @@
</param> </param>
<param> <param>
<key>_coordinate</key> <key>_coordinate</key>
<value>(1098, 229)</value> <value>(1120, 218)</value>
</param> </param>
<param> <param>
<key>gui_hint</key> <key>gui_hint</key>

View file

@ -4,7 +4,9 @@
<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,$py_obj_name)</make> <make>digitalhf.adaptive_dfe($sps,$nB,$nF,$nW,$mu,$alpha,$py_obj_name)</make>
<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
@ -30,11 +32,26 @@
<key>nW</key> <key>nW</key>
<type>int</type> <type>int</type>
</param> </param>
<param>
<name>mu</name>
<key>mu</key>
<type>float</type>
</param>
<param>
<name>alpha</name>
<key>alpha</key>
<type>float</type>
</param>
<param> <param>
<name>py_obj_name</name> <name>py_obj_name</name>
<key>py_obj_name</key> <key>py_obj_name</key>
<type>string</type> <type>string</type>
</param> </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

@ -38,6 +38,7 @@ class DIGITALHF_API adaptive_dfe : virtual public gr::block
public: public:
typedef boost::shared_ptr<adaptive_dfe> sptr; typedef boost::shared_ptr<adaptive_dfe> sptr;
virtual ~adaptive_dfe() {}
/*! /*!
* \brief Return a shared_ptr to a new instance of digitalhf::adaptive_dfe. * \brief Return a shared_ptr to a new instance of digitalhf::adaptive_dfe.
* *
@ -50,8 +51,12 @@ class DIGITALHF_API adaptive_dfe : virtual public gr::block
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 alpha, //
std::string physical_layer_description); std::string physical_layer_description);
virtual void set_mu(float) = 0;
virtual void set_mode(std::string) = 0;
} ; } ;
} // namespace digitalhf } // namespace digitalhf

View file

@ -51,10 +51,12 @@ 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 alpha,
std::string python_module_name) std::string python_module_name)
{ {
return gnuradio::get_initial_sptr return gnuradio::get_initial_sptr
(new adaptive_dfe_impl(sps, nB, nF, nW, python_module_name)); (new adaptive_dfe_impl(sps, nB, nF, nW, mu, alpha, python_module_name));
} }
/* /*
@ -64,16 +66,18 @@ 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 alpha,
std::string python_module_name) 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)))
, _sps(sps) , _sps(sps)
, _nB(nB) , _nB(nB*sps)
, _nF(nF) , _nF(nF*sps)
, _nW(nW) , _nW(nW)
, _mu(0.01) , _mu(mu)
, _alpha(0.001) , _alpha(alpha)
, _py_module_name(python_module_name) , _py_module_name(python_module_name)
, _physicalLayer() , _physicalLayer()
, _taps_samples(nullptr) , _taps_samples(nullptr)
@ -84,7 +88,11 @@ adaptive_dfe_impl::adaptive_dfe_impl(int sps, // samples per symbol
, _hist_symbol_index(0) , _hist_symbol_index(0)
, _sample_counter(0) , _sample_counter(0)
, _constellations() , _constellations()
, _npwr()
, _npwr_counter()
, _npwr_max_time_constant(10)
, _constellation_index() , _constellation_index()
, _samples()
, _symbols() , _symbols()
, _scramble() , _scramble()
, _descrambled_symbols() , _descrambled_symbols()
@ -146,8 +154,9 @@ adaptive_dfe_impl::general_work(int noutput_items,
std::fill_n(_hist_symbols, 2*_nW, 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_samples, _nB+_nF+1, gr_complex(0));
std::fill_n(_taps_symbols, _nW, gr_complex(0)); std::fill_n(_taps_symbols, _nW, gr_complex(0));
_samples.clear();
_phase = -phase_est; _phase = -phase_est;
_taps_samples[_nB+1] = 1;//gr_expj(-phase_est); _taps_samples[_nB+1] = 1;
_taps_symbols[0] = 1; _taps_symbols[0] = 1;
GILLock gil_lock; GILLock gil_lock;
try { try {
@ -166,17 +175,26 @@ adaptive_dfe_impl::general_work(int noutput_items,
// if (_sample_counter < 80*5) // if (_sample_counter < 80*5)
// std::cout << "SAMPLE " << _sample_counter << " " << dot_samples << std::endl; // std::cout << "SAMPLE " << _sample_counter << " " << dot_samples << std::endl;
gr_complex filter_output = dot_samples; gr_complex filter_output = dot_samples;
_samples.push_back(_hist_samples[_hist_sample_index+_nB+1]);
if ((_sample_counter%_sps) == 0) { if ((_sample_counter%_sps) == 0) {
if (_symbol_counter == _symbols.size()) { if (_symbol_counter == _symbols.size()) {
_symbol_counter = 0; _symbol_counter = 0;
GILLock gil_lock; GILLock gil_lock;
try { try {
boost::python::numpy::ndarray s = boost::python::numpy::from_data(&_descrambled_symbols.front(), boost::python::numpy::ndarray sy =
boost::python::numpy::dtype::get_builtin<gr_complex>(), boost::python::numpy::from_data(&_descrambled_symbols.front(),
boost::python::make_tuple(_descrambled_symbols.size()), boost::python::numpy::dtype::get_builtin<gr_complex>(),
boost::python::make_tuple(sizeof(gr_complex)), boost::python::make_tuple(_descrambled_symbols.size()),
boost::python::object()); boost::python::make_tuple(sizeof(gr_complex)),
update_doppler_information(_physicalLayer.attr("get_doppler")(s)); boost::python::object());
boost::python::numpy::ndarray sa =
boost::python::numpy::from_data(&_samples.front(),
boost::python::numpy::dtype::get_builtin<gr_complex>(),
boost::python::make_tuple(_samples.size()),
boost::python::make_tuple(sizeof(gr_complex)),
boost::python::object());
_samples.clear();
update_doppler_information(_physicalLayer.attr("get_doppler")(sy, sa));
update_frame_information(_physicalLayer.attr("get_frame")()); update_frame_information(_physicalLayer.attr("get_frame")());
} catch (boost::python::error_already_set const&) { } catch (boost::python::error_already_set const&) {
PyErr_Print(); PyErr_Print();
@ -184,46 +202,66 @@ adaptive_dfe_impl::general_work(int noutput_items,
} }
gr_complex known_symbol = _symbols[_symbol_counter]; gr_complex known_symbol = _symbols[_symbol_counter];
bool is_known = true; bool is_known = true;
for (int k=0; k<1; ++k) { filter_output = 0;
filter_output = 0;
#if 1 #if 1
volk_32fc_x2_dot_prod_32fc(&filter_output, volk_32fc_x2_dot_prod_32fc(&filter_output,
_hist_samples+_hist_sample_index, _hist_samples+_hist_sample_index,
_taps_samples, _taps_samples,
_nB+_nF+1); _nB+_nF+1);
#else #else
for (int l=0; l<_nB+_nF+1; ++l) { for (int l=0; l<_nB+_nF+1; ++l) {
assert(_hist_sample_index+l < 2*(_nB+_nF+1)); assert(_hist_sample_index+l < 2*(_nB+_nF+1));
filter_output += _hist_samples[_hist_sample_index+l]*_taps_samples[l]; filter_output += _hist_samples[_hist_sample_index+l]*_taps_samples[l];
} }
#endif #endif
gr_complex dot_symbols=0; gr_complex dot_symbols=0;
for (int l=0; l<_nW; ++l) { for (int l=0; l<_nW; ++l) {
assert(_hist_symbol_index+l < 2*_nW); assert(_hist_symbol_index+l < 2*_nW);
dot_symbols += _hist_symbols[_hist_symbol_index+l]*_taps_symbols[l]; 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;
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];
}
// if (_sample_counter < 80*5)
// std::cout << "filter: " << _symbol_counter << " " << _sample_counter << " " << filter_output << " " << known_symbol << " " << std::abs(err) << std::endl;
} }
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);
gr_complex descrambled_symbol = 0;
constell->map_to_points(jc, &descrambled_symbol);
// make soft decisions
float const err = std::abs(descrambled_filter_output - descrambled_symbol);
_npwr_counter[_constellation_index] += (_npwr_counter[_constellation_index] < _npwr_max_time_constant);
float const alpha = 1.0f/_npwr_counter[_constellation_index];
_npwr[_constellation_index] = (1-alpha)*_npwr[_constellation_index] + alpha*err;
std::vector<float> soft_dec = constell->calc_soft_dec(descrambled_filter_output, _npwr[_constellation_index]);
// std::cout << "soft_dec " << _npwr[_constellation_index] << " : ";
// for (int k=0; k<soft_dec.size(); ++k) {
// std::cout << soft_dec[k] << " ";
// }
// std::cout << "\n";
known_symbol = _scramble[_symbol_counter] * descrambled_symbol;
}
gr_complex err = filter_output - known_symbol;
int jMax=0;
float tMax=0;
for (int j=0; j<_nB+_nF+1; ++j) {
assert(_hist_sample_index+j < 2*(_nB+_nF+1));
_taps_samples[j] -= _mu*err*std::conj(_hist_samples[_hist_sample_index+j]);
// if (std::abs(_taps_samples[j]) > tMax) {
// tMax = std::abs(_taps_samples[j]);
// jMax = j;
// }
}
// std::cout << "taps_max: " << jMax << " " << tMax << std::endl;
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];
}
// if (_sample_counter < 80*5)
// std::cout << "filter: " << _symbol_counter << " " << _sample_counter << " " << filter_output << " " << known_symbol << " " << std::abs(err) << std::endl;
if (is_known || true) { if (is_known || true) {
_taps_symbols[_hist_symbol_index] = _taps_symbols[_hist_symbol_index + _nW] = known_symbol; _hist_symbols[_hist_symbol_index] = _hist_symbols[_hist_symbol_index + _nW] = known_symbol;
if (++_hist_symbol_index == _nW) if (++_hist_symbol_index == _nW)
_hist_symbol_index = 0; _hist_symbol_index = 0;
} }
@ -258,10 +296,17 @@ bool adaptive_dfe_impl::start()
_taps_symbols = (gr_complex*)(volk_malloc( _nW*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_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())); _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] = 1; _taps_samples[_nB+1] = 1;
_taps_symbols[0] = 1; _taps_symbols[0] = 1;
std::cout << "adaptive_dfe_impl::start()" << std::endl; std::cout << "adaptive_dfe_impl::start() " << _nB << " " << _nF << " " << _mu << " " << _alpha << std::endl;
GILLock gil_lock; GILLock gil_lock;
try { try {
boost::python::object module = boost::python::import(boost::python::str("digitalhf.physical_layer." + _py_module_name)); boost::python::object module = boost::python::import(boost::python::str("digitalhf.physical_layer." + _py_module_name));
@ -287,10 +332,25 @@ bool adaptive_dfe_impl::stop()
return true; return true;
} }
void adaptive_dfe_impl::set_mode(std::string mode) {
gr::thread::scoped_lock lock(d_setlock);
std::cout << "adaptive_dfe_impl::stop()" << std::endl;
GILLock gil_lock;
try {
_physicalLayer.attr("set_mode")(mode);
} catch (boost::python::error_already_set const&) {
PyErr_Print();
return;
}
update_constellations(_physicalLayer.attr("get_constellations")());
}
void adaptive_dfe_impl::update_constellations(boost::python::object obj) void adaptive_dfe_impl::update_constellations(boost::python::object obj)
{ {
int const n = boost::python::extract<int>(obj.attr("__len__")()); int const n = boost::python::extract<int>(obj.attr("__len__")());
_constellations.resize(n); _constellations.resize(n);
_npwr.resize(n);
_npwr_counter.resize(n);
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]); boost::python::numpy::ndarray const& array = boost::python::numpy::array(obj[i]);
char const* data = array.get_data(); char const* data = array.get_data();
@ -304,6 +364,8 @@ void adaptive_dfe_impl::update_constellations(boost::python::object obj)
unsigned int const rotational_symmetry = 0; unsigned int const rotational_symmetry = 0;
unsigned int const dimensionality = 1; unsigned int const dimensionality = 1;
_constellations[i] = gr::digital::constellation_calcdist::make(constell, pre_diff_code, rotational_symmetry, dimensionality); _constellations[i] = gr::digital::constellation_calcdist::make(constell, pre_diff_code, rotational_symmetry, dimensionality);
_npwr[i] = 0.0f;
_npwr_counter[i] = 0;
} }
} }
void adaptive_dfe_impl::update_frame_information(boost::python::object obj) void adaptive_dfe_impl::update_frame_information(boost::python::object obj)
@ -316,6 +378,7 @@ void adaptive_dfe_impl::update_frame_information(boost::python::object obj)
_symbols.resize(m); _symbols.resize(m);
_scramble.resize(m); _scramble.resize(m);
_descrambled_symbols.resize(m); _descrambled_symbols.resize(m);
_samples.clear();
for (int i=0; i<m; ++i) { for (int i=0; i<m; ++i) {
std::memcpy(&_symbols[i], data+16*i, sizeof(gr_complex)); std::memcpy(&_symbols[i], data+16*i, sizeof(gr_complex));
std::memcpy(&_scramble[i], data+16*i+8, sizeof(gr_complex)); std::memcpy(&_scramble[i], data+16*i+8, sizeof(gr_complex));
@ -355,17 +418,17 @@ void adaptive_dfe_impl::update_pll(float doppler) {
std::cout << "PLL: " << _df << " " << delta_f << std::endl; std::cout << "PLL: " << _df << " " << delta_f << std::endl;
} }
void adaptive_dfe_impl::insert_sample(gr_complex z) { 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;
// local oscillator update // local oscillator update
_phase += _df; _phase += _df;
if (_phase > M_PI) if (_phase > M_PI)
_phase -= 2*M_PI; _phase -= 2*M_PI;
if (_phase < -M_PI) if (_phase < -M_PI)
_phase += 2*M_PI; _phase += 2*M_PI;
// 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;
} }
bool adaptive_dfe_impl::get_correlation_tag(uint64_t i, uint64_t& offset, float& phase_est) { bool adaptive_dfe_impl::get_correlation_tag(uint64_t i, uint64_t& offset, float& phase_est) {
std::vector<tag_t> v; std::vector<tag_t> v;

View file

@ -53,7 +53,11 @@ private:
std::size_t _sample_counter; std::size_t _sample_counter;
std::vector<gr::digital::constellation_sptr> _constellations; std::vector<gr::digital::constellation_sptr> _constellations;
std::vector<float> _npwr;
std::vector<int> _npwr_counter;
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;
@ -83,6 +87,8 @@ public:
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 symbol taps int nW, // number of symbol taps
float mu,
float alpha,
std::string physical_layer_description); std::string physical_layer_description);
virtual ~adaptive_dfe_impl(); virtual ~adaptive_dfe_impl();
@ -96,6 +102,9 @@ public:
gr_vector_const_void_star &input_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items); gr_vector_void_star &output_items);
virtual void set_mu(float mu) { _mu = mu; }
virtual void set_mode(std::string);
} ; } ;
} // namespace digitalhf } // namespace digitalhf

View file

@ -6,7 +6,7 @@ from gnuradio import digital
class PhysicalLayer(object): class PhysicalLayer(object):
"""Physical layer description for STANAG 4285""" """Physical layer description for STANAG 4285"""
def __init__(self, mode=1): def __init__(self, mode=0):
"""For STANAG 4258 the mode has to be set manually: mode=0 -> BPSK, mode=1 -> QPSK, mode=2 -> 8PSK""" """For STANAG 4258 the mode has to be set manually: mode=0 -> BPSK, mode=1 -> QPSK, mode=2 -> 8PSK"""
self._constellations = [PhysicalLayer.make_psk(2, [0,1]), self._constellations = [PhysicalLayer.make_psk(2, [0,1]),
PhysicalLayer.make_psk(4, [0,1,3,2]), PhysicalLayer.make_psk(4, [0,1,3,2]),
@ -18,7 +18,8 @@ class PhysicalLayer(object):
def set_mode(self, mode): def set_mode(self, mode):
"""For STANAG 4258 the mode has to be set manually: mode=0 -> BPSK, mode=1 -> QPSK, mode=2 -> 8PSK""" """For STANAG 4258 the mode has to be set manually: mode=0 -> BPSK, mode=1 -> QPSK, mode=2 -> 8PSK"""
self._data[1] = mode print('set_mode', mode)
self._data[1] = int(mode)
def get_constellations(self): def get_constellations(self):
return self._constellations return self._constellations
@ -28,22 +29,30 @@ class PhysicalLayer(object):
print('-------------------- get_frame --------------------',self._counter) print('-------------------- get_frame --------------------',self._counter)
return self._preamble if self._counter == 0 else self._data return self._preamble if self._counter == 0 else self._data
def get_doppler(self, s): def get_doppler(self, sy, sa):
"""used for doppler shift update, for determining which frame to provide next, """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""" and for stopping at end of data/when the signal quality is too low
print('-------------------- get_doppler --------------------',self._counter) sy ... equalized symbols; sa ... samples"""
success,doppler = self.quality_preamble(s) if self._counter == 0 else self.quality_data(s) print('-------------------- get_doppler --------------------',self._counter,len(sy),len(sa))
success,doppler = self.quality_preamble(sy,sa) if self._counter == 0 else self.quality_data(sy)
self._counter = (self._counter+1)&1 if success else 0 self._counter = (self._counter+1)&1 if success else 0
self._is_first_frame = not success self._is_first_frame = not success
return success,doppler return success,doppler
def quality_preamble(self, s): def quality_preamble(self, sy, sa):
sps = 5
zp = [x for x in self._preamble[0]['symb'][9:40] for i in range(sps)]
cc = np.array([np.sum(sa[ i*5:(31+i)*5]*zp) for i in range(49)])
imax = np.argmax(np.abs(cc[0:18]))
pks = cc[(imax,imax+15,imax+16,imax+31),]
apks = np.abs(pks)
test = np.mean(apks[(0,3),]) > 2*np.mean(apks[(1,2),])
doppler = np.diff(np.unwrap(np.angle(pks[(0,3),])))[0]/31 if test else 0
idx = range(80) idx = range(80)
if self._is_first_frame: if self._is_first_frame:
idx = range(30,80) idx = range(30,80)
z = s[idx]*np.conj(self._preamble[0]['symb'][idx]) z = sy[idx]*np.conj(self._preamble[0]['symb'][idx])
success = np.sum(np.real(z)<0) < 30 success = np.sum(np.real(z)<0) < 30
doppler = PhysicalLayer.data_aided_frequency_estimation(s[idx], self._preamble[0]['symb'][idx])
return success,doppler return success,doppler
def quality_data(self, s): def quality_data(self, s):