mirror of
https://github.com/hb9fxq/gr-digitalhf
synced 2024-11-05 05:55:53 +00:00
python->C++ information transfer
This commit is contained in:
parent
37d98db318
commit
cdbe8dcd88
|
@ -72,15 +72,13 @@ if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32)
|
||||||
add_definitions(-fvisibility=hidden)
|
add_definitions(-fvisibility=hidden)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#include(GrPython)
|
|
||||||
find_package(PythonInterp)
|
find_package(PythonInterp)
|
||||||
if(NOT PYTHONINTERP_FOUND)
|
if(NOT PYTHONINTERP_FOUND)
|
||||||
message(FATAL_ERROR "Python interpreter required by the build system.")
|
message(FATAL_ERROR "Python interpreter required by the build system.")
|
||||||
endif(NOT PYTHONINTERP_FOUND)
|
endif(NOT PYTHONINTERP_FOUND)
|
||||||
# locate python
|
# locate python
|
||||||
include(FindPythonLibs)
|
include(FindPythonLibs)
|
||||||
MESSAGE("YYY ${PYTHON_LIBRARIES}")
|
|
||||||
#)
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# Find boost
|
# Find boost
|
||||||
|
@ -150,7 +148,7 @@ find_package(Doxygen)
|
||||||
# components required to the list of GR_REQUIRED_COMPONENTS (in all
|
# components required to the list of GR_REQUIRED_COMPONENTS (in all
|
||||||
# caps such as FILTER or FFT) and change the version to the minimum
|
# caps such as FILTER or FFT) and change the version to the minimum
|
||||||
# API compatible version required.
|
# API compatible version required.
|
||||||
set(GR_REQUIRED_COMPONENTS RUNTIME)
|
set(GR_REQUIRED_COMPONENTS RUNTIME DIGITAL)
|
||||||
find_package(Gnuradio "3.7.2" REQUIRED)
|
find_package(Gnuradio "3.7.2" REQUIRED)
|
||||||
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
||||||
include(GrVersion)
|
include(GrVersion)
|
||||||
|
|
|
@ -413,7 +413,7 @@
|
||||||
</param>
|
</param>
|
||||||
<param>
|
<param>
|
||||||
<key>py_obj_name</key>
|
<key>py_obj_name</key>
|
||||||
<value>/Users/chm/Software/gr-digitalhf/examples/s4285.py</value>
|
<value>STANAG_4285</value>
|
||||||
</param>
|
</param>
|
||||||
</block>
|
</block>
|
||||||
<connection>
|
<connection>
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
## -*- python -*-
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from gnuradio import digital
|
|
||||||
|
|
||||||
class PhysicalLayer(object):
|
|
||||||
"""Physical layer description for STANAG 4285"""
|
|
||||||
|
|
||||||
def __init__(self, mode=0):
|
|
||||||
"""For STANAG 4258 the mode has to be set manually: mode=0 -> BPSK, mode=1 -> QPSK, mode=2 -> 8PSK"""
|
|
||||||
print('Hello from PhysicalLayer!\n')
|
|
||||||
self._preamble = [get_preamble(), digital.constellation_bpsk()]
|
|
||||||
self._constellations = [digital.constellation_bpsk(),
|
|
||||||
digital.constellation_qpsk(),
|
|
||||||
digital.constellation_8psk()]
|
|
||||||
self._data = [get_data(), self._constellations[mode]]
|
|
||||||
self._counter = 0
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
print('Bye from PhysicalLayer!\n')
|
|
||||||
|
|
||||||
def set_mode(self):
|
|
||||||
"""For STANAG 4258 the mode has to be set manually: mode=0 -> BPSK, mode=1 -> QPSK, mode=2 -> 8PSK"""
|
|
||||||
self._data[1] = self._constellations[mode];
|
|
||||||
|
|
||||||
def get_frame(self):
|
|
||||||
"""returns the known+unknown symbols and scrambling"""
|
|
||||||
print('get_frame', self._counter, self._preamble, self._preamble[1].__deref__())
|
|
||||||
if self._counter == 0:
|
|
||||||
return self._preamble
|
|
||||||
else:
|
|
||||||
return self._data
|
|
||||||
|
|
||||||
def get_doppler(self, symbols):
|
|
||||||
"""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"""
|
|
||||||
self._counter = (self._counter+1)&2
|
|
||||||
## TODO: doppler calculations
|
|
||||||
doppler = 0.0
|
|
||||||
return [True, doppler]
|
|
||||||
|
|
||||||
def get_preamble():
|
|
||||||
"""preamble symbols + scrambler(=1)"""
|
|
||||||
state = np.array([1,1,0,1,0], dtype='b')
|
|
||||||
taps = np.array([0,0,1,0,1], dtype='b')
|
|
||||||
p = np.zeros(80, dtype='f')
|
|
||||||
for i in range(80):
|
|
||||||
p[i] = state[-1];
|
|
||||||
state = np.concatenate(([np.sum(state&taps)&1], state[0:-1]))
|
|
||||||
a = np.zeros(80, dtype=[('symb','c'), ('scramble', 'c')])
|
|
||||||
## BPSK modulation
|
|
||||||
a['symb'] = np.exp(np.pi*1j*p)
|
|
||||||
a['scramble'] = 1;
|
|
||||||
return a
|
|
||||||
|
|
||||||
def get_data():
|
|
||||||
"""data symbols + scrambler; for unknown symbols 'symb'=0"""
|
|
||||||
state = np.array([1,1,1,1,1,1,1,1,1], dtype='b')
|
|
||||||
taps = np.array([0,0,0,0,1,0,0,0,1], dtype='b')
|
|
||||||
p = np.zeros(176, dtype='f')
|
|
||||||
for i in range(176):
|
|
||||||
p[i] = np.sum(state[-3:]*[4,2,1]);
|
|
||||||
for j in range(3):
|
|
||||||
state = np.concatenate(([np.sum(state&taps)&1], state[0:-1]))
|
|
||||||
a=np.zeros(176, dtype=[('symb','c'), ('scramble', 'c')])
|
|
||||||
## PSK-8 modulation
|
|
||||||
a['scramble'] = np.exp(np.pi*1j*p/4)
|
|
||||||
a['symb'][ 32: 48] = 1; ## mini-probe 1
|
|
||||||
a['symb'][ 80: 96] = 1; ## mini-probe 2
|
|
||||||
a['symb'][128:144] = 1; ## mini-probe 3
|
|
||||||
return a
|
|
|
@ -50,7 +50,7 @@ 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
|
||||||
std::string py_file_name);
|
std::string physical_layer_description);
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <gnuradio/io_signature.h>
|
#include <gnuradio/io_signature.h>
|
||||||
#include <gnuradio/digital/constellation.h>
|
|
||||||
#include "adaptive_dfe_impl.h"
|
#include "adaptive_dfe_impl.h"
|
||||||
|
|
||||||
namespace gr {
|
namespace gr {
|
||||||
|
@ -45,10 +44,10 @@ 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
|
||||||
std::string python_file_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_file_name));
|
(new adaptive_dfe_impl(sps, nB, nF, nW, python_module_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -58,7 +57,7 @@ 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
|
||||||
std::string python_file_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(0, 0, sizeof(gr_complex)))
|
gr::io_signature::make(0, 0, sizeof(gr_complex)))
|
||||||
|
@ -66,10 +65,15 @@ adaptive_dfe_impl::adaptive_dfe_impl(int sps, // samples per symbol
|
||||||
, _nB(nB)
|
, _nB(nB)
|
||||||
, _nF(nF)
|
, _nF(nF)
|
||||||
, _nW(nW)
|
, _nW(nW)
|
||||||
, _py_file_name(python_file_name)
|
, _py_module_name(python_module_name)
|
||||||
, _physicalLayer()
|
, _physicalLayer()
|
||||||
, _taps_samples(nB+nF+1)
|
, _taps_samples(nB+nF+1)
|
||||||
, _taps_symbols(nW) {
|
, _taps_symbols(nW)
|
||||||
|
, _constellations()
|
||||||
|
, _constellation_index()
|
||||||
|
, _symbols()
|
||||||
|
, _scramble()
|
||||||
|
{
|
||||||
// make sure python is ready for threading
|
// make sure python is ready for threading
|
||||||
if( Py_IsInitialized() ){
|
if( Py_IsInitialized() ){
|
||||||
if(PyEval_ThreadsInitialized() != 1 ){
|
if(PyEval_ThreadsInitialized() != 1 ){
|
||||||
|
@ -100,11 +104,12 @@ adaptive_dfe_impl::general_work(int noutput_items,
|
||||||
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)
|
||||||
{
|
{
|
||||||
const gr_complex *in = (const gr_complex *) input_items[0];
|
gr_complex const* in = (gr_complex const *)input_items[0];
|
||||||
|
|
||||||
get_next_frame();
|
|
||||||
GILLock lock;
|
GILLock lock;
|
||||||
std::cout << "bits_per_symbol: " << boost::python::extract<int>(_constellation.attr("bits_per_symbol")()) << std::endl;
|
// TODO: wait for preamble correlation tag etc...
|
||||||
|
update_frame_information(_physicalLayer.attr("get_frame")());
|
||||||
|
update_doppler_information(_physicalLayer.attr("get_doppler")()); // symbols
|
||||||
|
|
||||||
consume_each (noutput_items);
|
consume_each (noutput_items);
|
||||||
|
|
||||||
|
@ -112,39 +117,16 @@ adaptive_dfe_impl::general_work(int noutput_items,
|
||||||
return noutput_items;
|
return noutput_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
void adaptive_dfe_impl::get_next_frame()
|
|
||||||
{
|
|
||||||
GILLock lock;
|
|
||||||
boost::python::object const& obj = _physicalLayer.attr("get_frame")();
|
|
||||||
std::cout << "get_frame" << std::endl;
|
|
||||||
boost::python::numpy::ndarray symbols = boost::python::numpy::array(obj[0]);
|
|
||||||
_constellation = obj[1];
|
|
||||||
}
|
|
||||||
boost::python::object import(const std::string& module, const std::string& path, boost::python::object& globals)
|
|
||||||
{
|
|
||||||
boost::python::dict locals;
|
|
||||||
locals["module_name"] = module;
|
|
||||||
locals["path"] = path;
|
|
||||||
|
|
||||||
boost::python::exec("import imp\n"
|
|
||||||
"new_module = imp.load_module(module_name, open(path), path, ('py', 'U', imp.PY_SOURCE))\n",
|
|
||||||
globals,
|
|
||||||
locals);
|
|
||||||
return locals["new_module"];
|
|
||||||
}
|
|
||||||
bool adaptive_dfe_impl::start()
|
bool adaptive_dfe_impl::start()
|
||||||
{
|
{
|
||||||
std::cout << "adaptive_dfe_impl::start()" << std::endl;
|
std::cout << "adaptive_dfe_impl::start()" << std::endl;
|
||||||
GILLock lock;
|
GILLock lock;
|
||||||
try {
|
try {
|
||||||
boost::python::object main = boost::python::import("__main__");
|
boost::python::object module = boost::python::import(boost::python::str("digitalhf.physical_layer." + _py_module_name));
|
||||||
boost::python::object globals = main.attr("__dict__");
|
|
||||||
boost::python::object module = import("physicalLayer", _py_file_name, globals);
|
|
||||||
boost::python::object PhysicalLayer = module.attr("PhysicalLayer");
|
boost::python::object PhysicalLayer = module.attr("PhysicalLayer");
|
||||||
_physicalLayer = PhysicalLayer();
|
_physicalLayer = PhysicalLayer();
|
||||||
|
update_constellations(_physicalLayer.attr("get_constellations")());
|
||||||
_physicalLayer.attr("get_frame")();
|
} catch (boost::python::error_already_set const&) {
|
||||||
} catch (const boost::python::error_already_set& ) {
|
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -158,5 +140,48 @@ bool adaptive_dfe_impl::stop()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void adaptive_dfe_impl::update_constellations(boost::python::object obj)
|
||||||
|
{
|
||||||
|
int const n = boost::python::extract<int>(obj.attr("__len__")());
|
||||||
|
_constellations.resize(n);
|
||||||
|
for (int i=0; i<n; ++i) {
|
||||||
|
boost::python::numpy::ndarray const& array = boost::python::numpy::array(obj[i]);
|
||||||
|
char const* data = array.get_data();
|
||||||
|
int const m = array.shape(0);
|
||||||
|
std::vector<gr_complex> constell(m);
|
||||||
|
std::vector<int> pre_diff_code(m);
|
||||||
|
for (int j=0; j<m; ++j) {
|
||||||
|
std::memcpy(&constell[j], data+9*j, sizeof(gr_complex));
|
||||||
|
pre_diff_code[j] = (data+9*j)[8];
|
||||||
|
}
|
||||||
|
unsigned int const rotational_symmetry = 0;
|
||||||
|
unsigned int const dimensionality = 1;
|
||||||
|
_constellations[i] = gr::digital::constellation_calcdist::make(constell, pre_diff_code, rotational_symmetry, dimensionality);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void adaptive_dfe_impl::update_frame_information(boost::python::object obj)
|
||||||
|
{
|
||||||
|
int const n = boost::python::extract<int>(obj.attr("__len__")());
|
||||||
|
assert(n==2);
|
||||||
|
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);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
_constellation_index = boost::python::extract<int>(obj[1]);
|
||||||
|
}
|
||||||
|
void adaptive_dfe_impl::update_doppler_information(boost::python::object obj)
|
||||||
|
{
|
||||||
|
int const n = boost::python::extract<int>(obj.attr("__len__")());
|
||||||
|
assert(n==2);
|
||||||
|
double const do_continue = boost::python::extract<bool>(obj[0]);
|
||||||
|
double const doppler = boost::python::extract<float>(obj[1]);
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace digitalhf */
|
} /* namespace digitalhf */
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
#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 <digitalhf/adaptive_dfe.h>
|
|
||||||
|
|
||||||
#include <boost/python.hpp>
|
#include <boost/python.hpp>
|
||||||
#include <boost/python/numpy.hpp>
|
#include <boost/python/numpy.hpp>
|
||||||
|
#include <gnuradio/digital/constellation.h>
|
||||||
|
#include <digitalhf/adaptive_dfe.h>
|
||||||
|
|
||||||
namespace gr {
|
namespace gr {
|
||||||
namespace digitalhf {
|
namespace digitalhf {
|
||||||
|
@ -34,26 +34,32 @@ private:
|
||||||
int _sps;
|
int _sps;
|
||||||
int _nB, _nF, _nW;
|
int _nB, _nF, _nW;
|
||||||
|
|
||||||
std::string _py_file_name;
|
// module name w.r.t. digitalhf.physical_layer containing a PhysicalLayer class
|
||||||
boost::python::object _physicalLayer;
|
std::string _py_module_name;
|
||||||
|
boost::python::object _physicalLayer; // class instance of physical layer description
|
||||||
|
|
||||||
std::vector<gr_complex> _taps_samples;
|
std::vector<gr_complex> _taps_samples;
|
||||||
std::vector<gr_complex> _taps_symbols;
|
std::vector<gr_complex> _taps_symbols;
|
||||||
|
|
||||||
// boost::python::numpy::ndarray _symbols;
|
std::vector<gr::digital::constellation_sptr> _constellations;
|
||||||
boost::python::object _constellation;
|
int _constellation_index;
|
||||||
|
std::vector<gr_complex> _symbols;
|
||||||
|
std::vector<gr_complex> _scramble;
|
||||||
|
|
||||||
void get_next_frame();
|
int _sample_counter;
|
||||||
|
|
||||||
|
void update_constellations(boost::python::object obj);
|
||||||
|
void update_frame_information(boost::python::object obj);
|
||||||
|
void update_doppler_information(boost::python::object obj);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
adaptive_dfe_impl(int sps, // samples per symbol
|
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 symbol taps
|
int nW, // number of symbol taps
|
||||||
std::string python_file_name);
|
std::string physical_layer_description);
|
||||||
virtual ~adaptive_dfe_impl();
|
virtual ~adaptive_dfe_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
|
||||||
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
|
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
|
||||||
|
|
||||||
virtual bool start();
|
virtual bool start();
|
||||||
|
|
|
@ -43,3 +43,5 @@ include(GrTest)
|
||||||
set(GR_TEST_TARGET_DEPS gnuradio-digitalhf)
|
set(GR_TEST_TARGET_DEPS gnuradio-digitalhf)
|
||||||
set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig)
|
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)
|
||||||
|
|
38
python/physical_layer/CMakeLists.txt
Normal file
38
python/physical_layer/CMakeLists.txt
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# Copyright 2011 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file was generated by gr_modtool, a tool from the GNU Radio framework
|
||||||
|
# This file is a part of gr-digitalhf
|
||||||
|
#
|
||||||
|
# GNU Radio 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.
|
||||||
|
#
|
||||||
|
# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Include python install macros
|
||||||
|
########################################################################
|
||||||
|
include(GrPython)
|
||||||
|
if(NOT PYTHONINTERP_FOUND)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Install python sources
|
||||||
|
########################################################################
|
||||||
|
GR_PYTHON_INSTALL(
|
||||||
|
FILES
|
||||||
|
__init__.py
|
||||||
|
STANAG_4285.py
|
||||||
|
DESTINATION ${GR_PYTHON_DIR}/digitalhf/physical_layer
|
||||||
|
)
|
||||||
|
|
80
python/physical_layer/STANAG_4285.py
Normal file
80
python/physical_layer/STANAG_4285.py
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
## -*- python -*-
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from gnuradio import digital
|
||||||
|
|
||||||
|
class PhysicalLayer(object):
|
||||||
|
"""Physical layer description for STANAG 4285"""
|
||||||
|
|
||||||
|
def __init__(self, mode=0):
|
||||||
|
"""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]),
|
||||||
|
PhysicalLayer.make_psk(4, [0,1,3,2]),
|
||||||
|
PhysicalLayer.make_psk(8, [1,0,2,3,6,7,5,4])]
|
||||||
|
self._preamble = [PhysicalLayer.get_preamble(), 0] ## BPSK
|
||||||
|
self._data = [PhysicalLayer.get_data(), mode] ## according to the mode
|
||||||
|
self._counter = 0
|
||||||
|
|
||||||
|
def set_mode(self):
|
||||||
|
"""For STANAG 4258 the mode has to be set manually: mode=0 -> BPSK, mode=1 -> QPSK, mode=2 -> 8PSK"""
|
||||||
|
self._data[1] = mode
|
||||||
|
|
||||||
|
def get_constellations(self):
|
||||||
|
return self._constellations
|
||||||
|
|
||||||
|
def get_frame(self):
|
||||||
|
"""returns the known+unknown symbols and scrambling"""
|
||||||
|
if self._counter == 0:
|
||||||
|
return self._preamble
|
||||||
|
else:
|
||||||
|
return self._data
|
||||||
|
|
||||||
|
def get_doppler(self): ## symbols
|
||||||
|
"""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"""
|
||||||
|
self._counter = (self._counter+1)&1
|
||||||
|
## TODO: doppler calculations
|
||||||
|
doppler = 0.1234
|
||||||
|
return [True, doppler]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_preamble():
|
||||||
|
"""preamble symbols + scrambler(=1)"""
|
||||||
|
state = np.array([1,1,0,1,0], dtype=np.bool)
|
||||||
|
taps = np.array([0,0,1,0,1], dtype=np.bool)
|
||||||
|
p = np.zeros(80, dtype=np.uint8)
|
||||||
|
for i in range(80):
|
||||||
|
p[i] = state[-1]
|
||||||
|
state = np.concatenate(([np.sum(state&taps)&1], state[0:-1]))
|
||||||
|
a = np.zeros(80, dtype=[('symb',np.complex64), ('scramble', np.complex64)])
|
||||||
|
## BPSK modulation
|
||||||
|
constellation = PhysicalLayer.make_psk(2,range(2))['points']
|
||||||
|
a['symb'] = constellation[p,]
|
||||||
|
a['scramble'] = 1
|
||||||
|
return a
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_data():
|
||||||
|
"""data symbols + scrambler; for unknown symbols 'symb'=0"""
|
||||||
|
state = np.array([1,1,1,1,1,1,1,1,1], dtype=np.bool)
|
||||||
|
taps = np.array([0,0,0,0,1,0,0,0,1], dtype=np.bool)
|
||||||
|
p = np.zeros(176, dtype=np.uint8)
|
||||||
|
for i in range(176):
|
||||||
|
p[i] = np.sum(state[-3:]*[4,2,1])
|
||||||
|
for j in range(3):
|
||||||
|
state = np.concatenate(([np.sum(state&taps)&1], state[0:-1]))
|
||||||
|
a=np.zeros(176, dtype=[('symb',np.complex64), ('scramble', np.complex64)])
|
||||||
|
## 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
|
||||||
|
return a
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def make_psk(n, gray_code):
|
||||||
|
c = np.zeros(n, dtype=[('points', np.complex64), ('symbols', np.uint8)])
|
||||||
|
c['points'] = np.exp(2*np.pi*1j*np.array(range(n))/n)
|
||||||
|
c['symbols'] = gray_code
|
||||||
|
return c
|
26
python/physical_layer/__init__.py
Normal file
26
python/physical_layer/__init__.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#
|
||||||
|
# Copyright 2008,2009 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This application 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 application 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 program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
#
|
||||||
|
|
||||||
|
# The presence of this file turns this directory into a Python package
|
||||||
|
|
||||||
|
'''
|
||||||
|
Physical layer descriptions for digital HF modes
|
||||||
|
'''
|
||||||
|
|
||||||
|
# import any pure python here
|
||||||
|
#
|
Loading…
Reference in a new issue