mirror of
https://github.com/hb9fxq/gr-digitalhf
synced 2024-12-22 15:10:00 +00:00
bug fixed
* the big switch statement in lib/adaptive_dfe_impl.cc needs to be improved
This commit is contained in:
parent
64096f2d97
commit
1cc5e64256
2
examples/.gitignore
vendored
Normal file
2
examples/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
top_block.py
|
||||||
|
*.wav
|
2385
examples/test_188-110A.grc
Normal file
2385
examples/test_188-110A.grc
Normal file
File diff suppressed because it is too large
Load diff
2385
examples/test_188-110C.grc
Normal file
2385
examples/test_188-110C.grc
Normal file
File diff suppressed because it is too large
Load diff
|
@ -159,68 +159,93 @@ 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];
|
||||||
|
|
||||||
int nout = 0;
|
int nout = 0; // counter for produced output items
|
||||||
int i = 0;
|
int i = 0; // counter for consumed input items
|
||||||
for (; i<ninput_items[0] && nout < noutput_items;) {
|
for (; i<ninput_items[0] && nout < noutput_items;) {
|
||||||
assert(nout < noutput_items);
|
assert(nout < noutput_items);
|
||||||
|
switch (_state) {
|
||||||
if (_state == WAIT_FOR_PREAMBLE) {
|
case WAIT_FOR_PREAMBLE: {
|
||||||
insert_sample(in[i++]);
|
insert_sample(in[i++]);
|
||||||
uint64_t offset = 0;
|
uint64_t offset = 0;
|
||||||
float phase_est = 0;
|
float phase_est = 0;
|
||||||
if (get_correlation_tag(i, offset, phase_est)) {
|
if (get_correlation_tag(i, offset, phase_est)) {
|
||||||
_state = INITIAL_DOPPLER_ESTIMATE;
|
GR_LOG_DEBUG(d_logger, "next state > INITIAL_DOPPLER_ESTIMATE");
|
||||||
_sample_counter = 0;
|
_state = INITIAL_DOPPLER_ESTIMATE;
|
||||||
_symbol_counter = 0;
|
_sample_counter = 0;
|
||||||
// _symbols.clear();
|
_symbol_counter = 0;
|
||||||
// _scramble.clear();
|
// _symbols.clear();
|
||||||
_descrambled_symbols.clear();
|
// _scramble.clear();
|
||||||
// _hist_sample_index = 0;
|
_descrambled_symbols.clear();
|
||||||
_hist_symbol_index = 0;
|
// _hist_sample_index = 0;
|
||||||
_ignore_filter_updates = 0;
|
_hist_symbol_index = 0;
|
||||||
_saved_samples.clear();
|
_ignore_filter_updates = 0;
|
||||||
std::fill_n(_hist_symbols, 2*_nW, gr_complex(0));
|
_saved_samples.clear();
|
||||||
std::fill_n(_taps_samples, _nB+_nF+1, gr_complex(0));
|
std::fill_n(_hist_symbols, 2*_nW, gr_complex(0));
|
||||||
std::fill_n(_taps_symbols, _nW, gr_complex(0));
|
std::fill_n(_taps_samples, _nB+_nF+1, gr_complex(0));
|
||||||
_samples.clear();
|
std::fill_n(_taps_symbols, _nW, gr_complex(0));
|
||||||
_phase = -phase_est;
|
_samples.clear();
|
||||||
_taps_samples[_nB+1] = 0.01;
|
_phase = -phase_est;
|
||||||
_taps_symbols[0] = 1;
|
_taps_samples[_nB+1] = 0.01;
|
||||||
GILLock gil_lock;
|
_taps_symbols[0] = 1;
|
||||||
try {
|
GILLock gil_lock;
|
||||||
update_frame_information(_physicalLayer.attr("get_frame")());
|
try {
|
||||||
} catch (boost::python::error_already_set const&) {
|
update_frame_information(_physicalLayer.attr("get_frame")());
|
||||||
PyErr_Print();
|
} catch (boost::python::error_already_set const&) {
|
||||||
}
|
PyErr_Print();
|
||||||
}
|
|
||||||
} // WAIT_FOR_PREAMBLE
|
|
||||||
|
|
||||||
if (_state == INITIAL_DOPPLER_ESTIMATE) {
|
|
||||||
// buffer samples and replay them later once the initial doppler estimate is there
|
|
||||||
if (_samples.size() == _sps * _symbols.size()) {
|
|
||||||
GILLock gil_lock;
|
|
||||||
try {
|
|
||||||
std::vector<gr_complex> const empty_vec;
|
|
||||||
// initial doppler estimate
|
|
||||||
if (!update_doppler_information(_physicalLayer.attr("get_doppler")
|
|
||||||
(complex_vector_to_ndarray(empty_vec),
|
|
||||||
complex_vector_to_ndarray(_samples)))) {
|
|
||||||
_state = WAIT_FOR_PREAMBLE;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
} catch (boost::python::error_already_set const&) {
|
|
||||||
PyErr_Print();
|
|
||||||
}
|
}
|
||||||
// (1) correct all samples in the circular buffer with the inital doppler estimate
|
break;
|
||||||
for (int j=_nB+1; j<_nB+_nF+1; ++j) {
|
} // WAIT_FOR_PREAMBLE
|
||||||
assert(_hist_sample_index+j < 2*(_nB+_nF+1));
|
|
||||||
_hist_samples[_hist_sample_index+j] *= gr_expj(-_phase);
|
case INITIAL_DOPPLER_ESTIMATE: {
|
||||||
update_local_oscillator();
|
_samples.push_back(in[i++]);
|
||||||
|
// buffer samples and replay them later once the initial doppler estimate is there
|
||||||
|
if (_samples.size() == _sps * _symbols.size()) {
|
||||||
|
GILLock gil_lock;
|
||||||
|
try {
|
||||||
|
std::vector<gr_complex> const empty_vec;
|
||||||
|
// initial doppler estimate
|
||||||
|
if (!update_doppler_information(_physicalLayer.attr("get_doppler")
|
||||||
|
(complex_vector_to_ndarray(empty_vec),
|
||||||
|
complex_vector_to_ndarray(_samples)))) {
|
||||||
|
GR_LOG_DEBUG(d_logger, "next state > WAIT_FOR_PREAMBLE");
|
||||||
|
_state = WAIT_FOR_PREAMBLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (boost::python::error_already_set const&) {
|
||||||
|
PyErr_Print();
|
||||||
|
}
|
||||||
|
// (1) correct all samples in the circular buffer with the inital doppler estimate
|
||||||
|
for (int j=_nB+1; j<_nB+_nF+1; ++j) {
|
||||||
|
assert(_hist_sample_index+j < 2*(_nB+_nF+1));
|
||||||
|
_hist_samples[_hist_sample_index+j] *= gr_expj(-_phase);
|
||||||
|
update_local_oscillator();
|
||||||
|
}
|
||||||
|
// (2) insert all buffered samples and run the adaptive filter for them
|
||||||
|
// instead of pop_front() we first reverse _samples and then insert back() + pop_back()
|
||||||
|
// O(N) instead of O(N^2)
|
||||||
|
std::reverse(_samples.begin(), _samples.end());
|
||||||
|
while (!_samples.empty() && nout < noutput_items) {
|
||||||
|
insert_sample(_samples.back());
|
||||||
|
_sample_counter += 1;
|
||||||
|
_samples.pop_back();
|
||||||
|
if ((_sample_counter%_sps) == 0)
|
||||||
|
out[nout++] = filter();
|
||||||
|
}
|
||||||
|
if (_samples.empty()) {
|
||||||
|
GR_LOG_DEBUG(d_logger,"next state > DO_FILTER");
|
||||||
|
_state = DO_FILTER;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
GR_LOG_DEBUG(d_logger, "next state > INITIAL_DOPPLER_ESTIMATE_CONTINUE");
|
||||||
|
_state = INITIAL_DOPPLER_ESTIMATE_CONTINUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// (2) insert all buffered samples and run the adaptive filter for them
|
} // INITIAL_DOPPLER_ESTIMATE_CONTINUE
|
||||||
// instead of pop_front() we first reverse _samples and then insert back() + pop_back()
|
|
||||||
// O(N) instead of O(N^2)
|
case INITIAL_DOPPLER_ESTIMATE_CONTINUE: {
|
||||||
std::reverse(_samples.begin(), _samples.end());
|
GR_LOG_DEBUG(d_logger, "INITIAL_DOPPLER_ESTIMATE_CONTINUE");
|
||||||
while (!_samples.empty() && nout < noutput_items) {
|
while (!_samples.empty() && nout < noutput_items) {
|
||||||
insert_sample(_samples.back());
|
insert_sample(_samples.back());
|
||||||
_sample_counter += 1;
|
_sample_counter += 1;
|
||||||
|
@ -229,79 +254,65 @@ adaptive_dfe_impl::general_work(int noutput_items,
|
||||||
out[nout++] = filter();
|
out[nout++] = filter();
|
||||||
}
|
}
|
||||||
if (_samples.empty()) {
|
if (_samples.empty()) {
|
||||||
|
GR_LOG_DEBUG(d_logger, "next state > DO_FILTER");
|
||||||
_state = DO_FILTER;
|
_state = DO_FILTER;
|
||||||
} else {
|
} else {
|
||||||
|
GR_LOG_DEBUG(d_logger, "next state > INITIAL_DOPPLER_ESTIMATE_CONTINUE");
|
||||||
_state = INITIAL_DOPPLER_ESTIMATE_CONTINUE;
|
_state = INITIAL_DOPPLER_ESTIMATE_CONTINUE;
|
||||||
}
|
}
|
||||||
continue;
|
break;
|
||||||
}
|
} // INITIAL_DOPPLER_ESTIMATE_CONTINUE
|
||||||
_samples.push_back(in[i++]);
|
|
||||||
} // INITIAL_DOPPLER_ESTIMATE_CONTINUE
|
|
||||||
|
|
||||||
if (_state == INITIAL_DOPPLER_ESTIMATE_CONTINUE) {
|
case DO_FILTER: {
|
||||||
GR_LOG_DEBUG(d_logger, "INITIAL_DOPPLER_ESTIMATE_CONTINUE");
|
if ((_sample_counter%_sps) == 0) {
|
||||||
while (!_samples.empty() && nout < noutput_items) {
|
if (_symbol_counter == _symbols.size()) { // frame is ready
|
||||||
insert_sample(_samples.back());
|
_symbol_counter = 0;
|
||||||
_sample_counter += 1;
|
GILLock gil_lock;
|
||||||
_samples.pop_back();
|
try {
|
||||||
if ((_sample_counter%_sps) == 0)
|
// update doppler estimate
|
||||||
out[nout++] = filter();
|
if (!update_doppler_information(_physicalLayer.attr("get_doppler")
|
||||||
}
|
(complex_vector_to_ndarray(_descrambled_symbols),
|
||||||
if (_samples.empty()) {
|
complex_vector_to_ndarray(_samples)))) {
|
||||||
_state = DO_FILTER;
|
GR_LOG_DEBUG(d_logger, "next state > WAIT_FOR_PREAMBLE");
|
||||||
} else {
|
_state = WAIT_FOR_PREAMBLE;
|
||||||
_state = INITIAL_DOPPLER_ESTIMATE_CONTINUE;
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
// publish soft decisions
|
||||||
} // INITIAL_DOPPLER_ESTIMATE_CONTINUE
|
if (!_vec_soft_decisions.empty()) {
|
||||||
|
unsigned int const bits_per_symbol = _constellations[_constellation_index]->bits_per_symbol();
|
||||||
if (_state == DO_FILTER) {
|
_msg_metadata = pmt::dict_add(_msg_metadata, pmt::mp("bits_per_symbol"), pmt::from_long(bits_per_symbol));
|
||||||
if ((_sample_counter%_sps) == 0) {
|
message_port_pub(_msg_port_name,
|
||||||
if (_symbol_counter == _symbols.size()) { // frame is ready
|
pmt::cons(_msg_metadata,
|
||||||
_symbol_counter = 0;
|
pmt::init_f32vector(_vec_soft_decisions.size(), _vec_soft_decisions)));
|
||||||
GILLock gil_lock;
|
_vec_soft_decisions.clear();
|
||||||
try {
|
}
|
||||||
// update doppler estimate
|
_samples.clear();
|
||||||
update_doppler_information(_physicalLayer.attr("get_doppler")
|
// get information about the following frame
|
||||||
(complex_vector_to_ndarray(_descrambled_symbols),
|
update_frame_information(_physicalLayer.attr("get_frame")());
|
||||||
complex_vector_to_ndarray(_samples)));
|
} catch (boost::python::error_already_set const&) {
|
||||||
// publish soft decisions
|
PyErr_Print();
|
||||||
if (!_vec_soft_decisions.empty()) {
|
|
||||||
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));
|
|
||||||
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();
|
} // frame is ready
|
||||||
// get information about the following frame
|
if (_ignore_filter_updates == 0) {
|
||||||
update_frame_information(_physicalLayer.attr("get_frame")());
|
out[nout++] = filter();
|
||||||
} catch (boost::python::error_already_set const&) {
|
if (_symbol_counter+1 == _symbols.size())
|
||||||
PyErr_Print();
|
recenter_filter_taps();
|
||||||
|
} else {
|
||||||
|
_ignore_filter_updates -= 1;
|
||||||
}
|
}
|
||||||
} // frame is ready
|
} // (_sample_counter%_sps) == 0
|
||||||
if (_ignore_filter_updates == 0) {
|
if (_need_samples) {
|
||||||
out[nout++] = filter();
|
_samples.push_back(_hist_samples[_hist_sample_index+_nB+1]);
|
||||||
if (_symbol_counter+1 == _symbols.size())
|
|
||||||
recenter_filter_taps();
|
|
||||||
} else {
|
|
||||||
_ignore_filter_updates -= 1;
|
|
||||||
}
|
}
|
||||||
} // (_sample_counter%_sps) == 0
|
if (_saved_samples.empty()) {
|
||||||
|
insert_sample(in[i++]);
|
||||||
|
} else {
|
||||||
if (_need_samples) {
|
insert_sample(_saved_samples.back());
|
||||||
_samples.push_back(_hist_samples[_hist_sample_index+_nB+1]);
|
_saved_samples.pop_back();
|
||||||
}
|
}
|
||||||
if (_saved_samples.empty()) {
|
_sample_counter += 1;
|
||||||
insert_sample(in[i++]);
|
} // DO_FILTER
|
||||||
} else {
|
} // switch _state
|
||||||
insert_sample(_saved_samples.back());
|
|
||||||
_saved_samples.pop_back();
|
|
||||||
}
|
|
||||||
_sample_counter += 1;
|
|
||||||
} // DO_FILTER
|
|
||||||
} // next input sample
|
} // next input sample
|
||||||
|
|
||||||
consume(0, i);
|
consume(0, i);
|
||||||
|
@ -522,7 +533,6 @@ bool adaptive_dfe_impl::update_doppler_information(boost::python::object obj)
|
||||||
assert(n==2);
|
assert(n==2);
|
||||||
bool const do_continue = boost::python::extract<bool>(obj[0]);
|
bool const do_continue = boost::python::extract<bool>(obj[0]);
|
||||||
if (!do_continue) {
|
if (!do_continue) {
|
||||||
_state = WAIT_FOR_PREAMBLE;
|
|
||||||
_phase = 0;
|
_phase = 0;
|
||||||
_df = 0;
|
_df = 0;
|
||||||
std::fill_n(_hist_samples, 2*(_nB+_nF+1), gr_complex(0));
|
std::fill_n(_hist_samples, 2*(_nB+_nF+1), gr_complex(0));
|
||||||
|
|
232
python/physical_layer/MIL_STD_188_110C.py
Normal file
232
python/physical_layer/MIL_STD_188_110C.py
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
## -*- python -*-
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
def n_psk(n,x):
|
||||||
|
return np.complex64(np.exp(2j*np.pi*x/n))
|
||||||
|
|
||||||
|
## ---- constellations -----------------------------------------------------------
|
||||||
|
CONST_DTYPE=np.dtype([('points', np.complex64),
|
||||||
|
('symbols', np.uint8)])
|
||||||
|
BPSK=np.array(zip(np.exp(2j*np.pi*np.arange(2)/2), range(2)), CONST_DTYPE)
|
||||||
|
QPSK=np.array(zip(np.exp(2j*np.pi*np.arange(4)/4), [0,1,3,2]), CONST_DTYPE)
|
||||||
|
PSK8=np.array(zip(np.exp(2j*np.pi*np.arange(8)/8), [0,1,3,2,7,6,4,5]), CONST_DTYPE)
|
||||||
|
QAM16=np.array(
|
||||||
|
zip([+0.866025+0.500000j, 0.500000+0.866025j, 1.000000+0.000000j, 0.258819+0.258819j,
|
||||||
|
-0.500000+0.866025j, 0.000000+1.000000j, -0.866025+0.500000j, -0.258819+0.258819j,
|
||||||
|
+0.500000-0.866025j, 0.000000-1.000000j, 0.866025-0.500000j, 0.258819-0.258819j,
|
||||||
|
-0.866025-0.500000j, -0.500000-0.866025j, -1.000000+0.000000j, -0.258819-0.258819j],
|
||||||
|
range(16)), CONST_DTYPE)
|
||||||
|
QAM32=np.array(
|
||||||
|
zip([+0.866380+0.499386j, 0.984849+0.173415j, 0.499386+0.866380j, 0.173415+0.984849j,
|
||||||
|
+0.520246+0.520246j, 0.520246+0.173415j, 0.173415+0.520246j, 0.173415+0.173415j,
|
||||||
|
-0.866380+0.499386j, -0.984849+0.173415j, -0.499386+0.866380j, -0.173415+0.984849j,
|
||||||
|
-0.520246+0.520246j, -0.520246+0.173415j, -0.173415+0.520246j, -0.173415+0.173415j,
|
||||||
|
+0.866380-0.499386j, 0.984849-0.173415j, 0.499386-0.866380j, 0.173415-0.984849j,
|
||||||
|
+0.520246-0.520246j, 0.520246-0.173415j, 0.173415-0.520246j, 0.173415-0.173415j,
|
||||||
|
-0.866380-0.499386j, -0.984849-0.173415j, -0.499386-0.866380j, -0.173415-0.984849j,
|
||||||
|
-0.520246-0.520246j, -0.520246-0.173415j, -0.173415-0.520246j, -0.173415-0.173415j],
|
||||||
|
range(32)), CONST_DTYPE)
|
||||||
|
QAM64=np.array(
|
||||||
|
zip([+1.000000+0.000000j, 0.822878+0.568218j, 0.821137+0.152996j, 0.932897+0.360142j,
|
||||||
|
+0.000000-1.000000j, 0.822878-0.568218j, 0.821137-0.152996j, 0.932897-0.360142j,
|
||||||
|
+0.568218+0.822878j, 0.588429+0.588429j, 0.588429+0.117686j, 0.588429+0.353057j,
|
||||||
|
+0.568218-0.822878j, 0.588429-0.588429j, 0.588429-0.117686j, 0.588429-0.353057j,
|
||||||
|
+0.152996+0.821137j, 0.117686+0.588429j, 0.117686+0.117686j, 0.117686+0.353057j,
|
||||||
|
+0.152996-0.821137j, 0.117686-0.588429j, 0.117686-0.117686j, 0.117686-0.353057j,
|
||||||
|
+0.360142+0.932897j, 0.353057+0.588429j, 0.353057+0.117686j, 0.353057+0.353057j,
|
||||||
|
+0.360142-0.932897j, 0.353057-0.588429j, 0.353057-0.117686j, 0.353057-0.353057j,
|
||||||
|
+0.000000+1.000000j, -0.822878+0.568218j, -0.821137+0.152996j, -0.932897+0.360142j,
|
||||||
|
-1.000000+0.000000j, -0.822878-0.568218j, -0.821137-0.152996j, -0.932897-0.360142j,
|
||||||
|
-0.568218+0.822878j, -0.588429+0.588429j, -0.588429+0.117686j, -0.588429+0.353057j,
|
||||||
|
-0.568218-0.822878j, -0.588429-0.588429j, -0.588429-0.117686j, -0.588429-0.353057j,
|
||||||
|
-0.152996+0.821137j, -0.117686+0.588429j, -0.117686+0.117686j, -0.117686+0.353057j,
|
||||||
|
-0.152996-0.821137j, -0.117686-0.588429j, -0.117686-0.117686j, -0.117686-0.353057j,
|
||||||
|
-0.360142+0.932897j, -0.353057+0.588429j, -0.353057+0.117686j, -0.353057+0.353057j,
|
||||||
|
-0.360142-0.932897j, -0.353057-0.588429j, -0.353057-0.117686j, -0.353057-0.353057j],
|
||||||
|
range(64)), CONST_DTYPE)
|
||||||
|
|
||||||
|
## ---- constellation indices ---------------------------------------------------
|
||||||
|
MODE_BPSK = 0
|
||||||
|
MODE_QPSK = 1
|
||||||
|
MODE_8PSK = 2
|
||||||
|
MODE_16QAM = 3
|
||||||
|
MODE_32QAM = 4
|
||||||
|
MODE_64QAM = 5
|
||||||
|
|
||||||
|
## ---- data scrambler -----------------------------------------------------------
|
||||||
|
class ScrambleData(object):
|
||||||
|
"""data scrambling sequence generator"""
|
||||||
|
def __init__(self):
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self._state = 1
|
||||||
|
|
||||||
|
def next(self, num_bits):
|
||||||
|
r = self._state & ((1<<num_bits)-1)
|
||||||
|
for i in range(num_bits):
|
||||||
|
self._advance()
|
||||||
|
return r
|
||||||
|
|
||||||
|
def _advance(self):
|
||||||
|
lsb = self._state&1
|
||||||
|
self._state = (self._state>>1)&511
|
||||||
|
if lsb:
|
||||||
|
self._state ^= 0x10B
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
## ---- preamble definitions ---------------------------------------------------
|
||||||
|
## 184 = 8*23
|
||||||
|
PREAMBLE=np.array(
|
||||||
|
[1,5,1,3,6,1,3,1,1,6,3,7,7,3,5,4,3,6,6,4,5,4,0,
|
||||||
|
2,2,2,6,0,7,5,7,4,0,7,5,7,1,6,1,0,5,2,2,6,2,3,
|
||||||
|
6,0,0,5,1,4,2,2,2,3,4,0,6,2,7,4,3,3,7,2,0,2,6,
|
||||||
|
4,4,1,7,6,2,0,6,2,3,6,7,4,3,6,1,3,7,4,6,5,7,2,
|
||||||
|
0,1,1,1,4,4,0,0,5,7,7,4,7,3,5,4,1,6,5,6,6,4,6,
|
||||||
|
3,4,3,0,7,1,3,4,7,0,1,4,3,3,3,5,1,1,1,4,6,1,0,
|
||||||
|
6,0,1,3,1,4,1,7,7,6,3,0,0,7,2,7,2,0,2,6,1,1,1,
|
||||||
|
2,7,7,5,3,3,6,0,5,3,3,1,0,7,1,1,0,3,0,4,0,7,3],
|
||||||
|
dtype=np.uint8)
|
||||||
|
|
||||||
|
## 103 = 31 + 1 + 3*13 + 1 + 31
|
||||||
|
REINSERTED_PREAMBLE=np.array(
|
||||||
|
[0,0,0,0,0,2,4,6,0,4,0,4,0,6,4,2,0,0,0,0,0,2,4,6,0,4,0,4,0,6,4, ## MP+
|
||||||
|
2,
|
||||||
|
0,4,0,4,0,0,4,4,0,0,0,0,0, # + D0
|
||||||
|
0,4,0,4,0,0,4,4,0,0,0,0,0, # + D1
|
||||||
|
0,4,0,4,0,0,4,4,0,0,0,0,0, # + D2
|
||||||
|
6,
|
||||||
|
4,4,4,4,4,6,0,2,4,0,4,0,4,2,0,6,4,4,4,4,4,6,0,2,4,0,4,0,4,2,0], ## MP-
|
||||||
|
dtype=np.uint8)
|
||||||
|
|
||||||
|
## ---- physcal layer class -----------------------------------------------------
|
||||||
|
class PhysicalLayer(object):
|
||||||
|
"""Physical layer description for MIL-STD-188-110 Appendix D = STANAG 4539"""
|
||||||
|
|
||||||
|
def __init__(self, sps):
|
||||||
|
"""intialization"""
|
||||||
|
self._sps = sps
|
||||||
|
self._frame_counter = -1
|
||||||
|
self._constellations = [BPSK, QPSK, PSK8, QAM16, QAM32, QAM64]
|
||||||
|
self._preamble = self.get_preamble()
|
||||||
|
self._scr_data = ScrambleData()
|
||||||
|
|
||||||
|
def get_constellations(self):
|
||||||
|
return self._constellations
|
||||||
|
|
||||||
|
def get_frame(self):
|
||||||
|
"""returns a tuple describing the frame:
|
||||||
|
[0] ... known+unknown symbols and scrambling
|
||||||
|
[1] ... modulation type after descrambling
|
||||||
|
[2] ... a boolean indicating whethere or not raw IQ samples needed
|
||||||
|
[3] ... a boolean indicating if the soft decision for the unknown
|
||||||
|
symbols are saved"""
|
||||||
|
print('-------------------- get_frame --------------------',
|
||||||
|
self._frame_counter)
|
||||||
|
## --- preamble frame ----
|
||||||
|
if self._frame_counter == -1:
|
||||||
|
return [self._preamble,MODE_BPSK,True,False]
|
||||||
|
## ----- data frame ------
|
||||||
|
if self._frame_counter == 0:
|
||||||
|
self.a = self.make_reinserted_preamble()
|
||||||
|
return [self.a, MODE_QPSK,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 = False
|
||||||
|
doppler = 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
|
||||||
|
else: ## ------------------------ data frame ----
|
||||||
|
if len(symbols) != 0:
|
||||||
|
for s in symbols:
|
||||||
|
print(s)
|
||||||
|
success = False
|
||||||
|
self._frame_counter = -1
|
||||||
|
return success,doppler
|
||||||
|
|
||||||
|
def get_doppler_from_preamble(self, symbols, iq_samples):
|
||||||
|
"""quality check and doppler estimation for preamble"""
|
||||||
|
success = True
|
||||||
|
doppler = 0
|
||||||
|
shift=9
|
||||||
|
if len(iq_samples) != 0:
|
||||||
|
zp = np.conj(self.get_preamble_z(self._sps)[shift*self._sps:])
|
||||||
|
cc = np.array([np.sum(iq_samples[i:i+23*self._sps] *
|
||||||
|
zp[0:23*self._sps])
|
||||||
|
for i in range(23*3*self._sps)])
|
||||||
|
acc = np.abs(cc)
|
||||||
|
for i in range(0,len(cc),23*self._sps):
|
||||||
|
print('i=%3d: '%i,end='')
|
||||||
|
for j in range(23*self._sps):
|
||||||
|
print('%3.0f ' % acc[i+j], end='')
|
||||||
|
print()
|
||||||
|
|
||||||
|
imax = np.argmax(np.abs(cc[0:3*23*self._sps]))
|
||||||
|
print(imax)
|
||||||
|
pks = np.array([np.sum(iq_samples[(imax+23*i*self._sps):
|
||||||
|
(imax+23*i*self._sps+23*self._sps)] *
|
||||||
|
zp[(23*i*self._sps):
|
||||||
|
(23*i*self._sps+23*self._sps)])
|
||||||
|
for i in range(1,5)])
|
||||||
|
print('doppler apks', np.abs(pks))
|
||||||
|
print('doppler ppks', np.angle(pks), np.diff(np.unwrap(np.angle(pks)))/23)
|
||||||
|
doppler = np.mean(np.diff(np.unwrap(np.angle(pks))))/23
|
||||||
|
success = True
|
||||||
|
print('success=', success, 'doppler=', doppler)
|
||||||
|
return success,doppler
|
||||||
|
|
||||||
|
def make_reinserted_preamble(self):
|
||||||
|
a=np.zeros(len(REINSERTED_PREAMBLE), dtype=[('symb', np.complex64),
|
||||||
|
('scramble', np.complex64)])
|
||||||
|
a['symb'] = n_psk(8, REINSERTED_PREAMBLE)
|
||||||
|
a['scramble'] = n_psk(8, REINSERTED_PREAMBLE)
|
||||||
|
a['symb'][32:32+3*13] = 0 ## D0,D1,D2
|
||||||
|
return a
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_preamble():
|
||||||
|
"""preamble symbols + scrambler"""
|
||||||
|
a=np.zeros(len(PREAMBLE), dtype=[('symb', np.complex64),
|
||||||
|
('scramble', np.complex64)])
|
||||||
|
a['symb'] = n_psk(8, PREAMBLE)
|
||||||
|
a['scramble'] = n_psk(8, PREAMBLE)
|
||||||
|
##a['symb'][-30:] = 0
|
||||||
|
return a
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_preamble_z(sps):
|
||||||
|
"""preamble symbols for preamble correlation"""
|
||||||
|
a = PhysicalLayer.get_preamble()
|
||||||
|
return np.array([z for z in a['symb'] for i in range(sps)])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print(PREAMBLE)
|
||||||
|
z = n_psk(8,PREAMBLE)
|
||||||
|
cc = [np.sum(z[0:23]*np.conj(z[23*i:23*i+23])) for i in range(6)]
|
||||||
|
print(np.abs(cc))
|
||||||
|
print(np.angle(cc)/np.pi*4)
|
||||||
|
print(all(z==PhysicalLayer.get_preamble()['symb']))
|
||||||
|
print(len(PhysicalLayer.get_preamble()['symb']))
|
||||||
|
s = ScrambleData()
|
||||||
|
print([s.next(1) for _ in range(511)])
|
||||||
|
print([s.next(1) for _ in range(511)] ==
|
||||||
|
[s.next(1) for _ in range(511)])
|
||||||
|
print(QAM64)
|
||||||
|
print(QAM32)
|
||||||
|
print(QAM16)
|
||||||
|
print(PSK8)
|
||||||
|
print(QPSK)
|
||||||
|
print(BPSK)
|
Loading…
Reference in a new issue