diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5540e8e..38f2fd2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -72,15 +72,13 @@ if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32)
add_definitions(-fvisibility=hidden)
endif()
-#include(GrPython)
find_package(PythonInterp)
if(NOT PYTHONINTERP_FOUND)
message(FATAL_ERROR "Python interpreter required by the build system.")
endif(NOT PYTHONINTERP_FOUND)
# locate python
include(FindPythonLibs)
-MESSAGE("YYY ${PYTHON_LIBRARIES}")
-#)
+
########################################################################
# Find boost
@@ -150,7 +148,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)
+set(GR_REQUIRED_COMPONENTS RUNTIME DIGITAL)
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 806dd42..50a7750 100644
--- a/examples/1st.grc
+++ b/examples/1st.grc
@@ -413,7 +413,7 @@
py_obj_name
- /Users/chm/Software/gr-digitalhf/examples/s4285.py
+ STANAG_4285
diff --git a/examples/s4285.py b/examples/s4285.py
deleted file mode 100644
index de9585e..0000000
--- a/examples/s4285.py
+++ /dev/null
@@ -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
diff --git a/include/digitalhf/adaptive_dfe.h b/include/digitalhf/adaptive_dfe.h
index 886c488..ebdb7be 100644
--- a/include/digitalhf/adaptive_dfe.h
+++ b/include/digitalhf/adaptive_dfe.h
@@ -50,7 +50,7 @@ class DIGITALHF_API adaptive_dfe : virtual public gr::block
int nB, // number of forward FIR taps
int nF, // number of backward FIR taps
int nW, // number of feedback taps
- std::string py_file_name);
+ std::string physical_layer_description);
} ;
diff --git a/lib/adaptive_dfe_impl.cc b/lib/adaptive_dfe_impl.cc
index c732cfe..aaa714c 100644
--- a/lib/adaptive_dfe_impl.cc
+++ b/lib/adaptive_dfe_impl.cc
@@ -23,7 +23,6 @@
#endif
#include
-#include
#include "adaptive_dfe_impl.h"
namespace gr {
@@ -45,10 +44,10 @@ adaptive_dfe::make(int sps, // samples per symbol
int nB, // number of forward FIR taps
int nF, // number of backward FIR taps
int nW, // number of feedback taps
- std::string python_file_name)
+ std::string python_module_name)
{
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 nF, // number of backward FIR taps
int nW, // number of feedback taps
- std::string python_file_name)
+ 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)))
@@ -66,10 +65,15 @@ adaptive_dfe_impl::adaptive_dfe_impl(int sps, // samples per symbol
, _nB(nB)
, _nF(nF)
, _nW(nW)
- , _py_file_name(python_file_name)
+ , _py_module_name(python_module_name)
, _physicalLayer()
, _taps_samples(nB+nF+1)
- , _taps_symbols(nW) {
+ , _taps_symbols(nW)
+ , _constellations()
+ , _constellation_index()
+ , _symbols()
+ , _scramble()
+{
// make sure python is ready for threading
if( Py_IsInitialized() ){
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_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;
- std::cout << "bits_per_symbol: " << boost::python::extract(_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);
@@ -112,39 +117,16 @@ adaptive_dfe_impl::general_work(int 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()
{
std::cout << "adaptive_dfe_impl::start()" << std::endl;
GILLock lock;
try {
- boost::python::object main = boost::python::import("__main__");
- boost::python::object globals = main.attr("__dict__");
- boost::python::object module = import("physicalLayer", _py_file_name, globals);
+ boost::python::object module = boost::python::import(boost::python::str("digitalhf.physical_layer." + _py_module_name));
boost::python::object PhysicalLayer = module.attr("PhysicalLayer");
_physicalLayer = PhysicalLayer();
-
- _physicalLayer.attr("get_frame")();
- } catch (const boost::python::error_already_set& ) {
+ update_constellations(_physicalLayer.attr("get_constellations")());
+ } catch (boost::python::error_already_set const&) {
PyErr_Print();
return false;
}
@@ -158,5 +140,48 @@ bool adaptive_dfe_impl::stop()
return true;
}
+void adaptive_dfe_impl::update_constellations(boost::python::object obj)
+{
+ int const n = boost::python::extract(obj.attr("__len__")());
+ _constellations.resize(n);
+ for (int i=0; i constell(m);
+ std::vector pre_diff_code(m);
+ for (int j=0; j(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(obj[1]);
+}
+void adaptive_dfe_impl::update_doppler_information(boost::python::object obj)
+{
+ int const n = boost::python::extract(obj.attr("__len__")());
+ assert(n==2);
+ double const do_continue = boost::python::extract(obj[0]);
+ double const doppler = boost::python::extract(obj[1]);
+ // TODO
+}
+
} /* namespace digitalhf */
} /* namespace gr */
diff --git a/lib/adaptive_dfe_impl.h b/lib/adaptive_dfe_impl.h
index d188932..69b7bf0 100644
--- a/lib/adaptive_dfe_impl.h
+++ b/lib/adaptive_dfe_impl.h
@@ -21,10 +21,10 @@
#ifndef INCLUDED_DIGITALHF_ADAPTIVE_DFE_IMPL_H
#define INCLUDED_DIGITALHF_ADAPTIVE_DFE_IMPL_H
-#include
-
#include
#include
+#include
+#include
namespace gr {
namespace digitalhf {
@@ -34,26 +34,32 @@ private:
int _sps;
int _nB, _nF, _nW;
- std::string _py_file_name;
- boost::python::object _physicalLayer;
+ // 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;
-// boost::python::numpy::ndarray _symbols;
- boost::python::object _constellation;
+ std::vector _constellations;
+ int _constellation_index;
+ std::vector _symbols;
+ std::vector _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:
adaptive_dfe_impl(int sps, // samples per symbol
int nB, // number of forward FIR taps
int nF, // number of backward FIR taps
int nW, // number of symbol taps
- std::string python_file_name);
+ std::string physical_layer_description);
virtual ~adaptive_dfe_impl();
- // Where all the action really happens
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
virtual bool start();
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index a7a5a57..4d5bf2e 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -43,3 +43,5 @@ include(GrTest)
set(GR_TEST_TARGET_DEPS gnuradio-digitalhf)
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)
+
+add_subdirectory(physical_layer)
diff --git a/python/physical_layer/CMakeLists.txt b/python/physical_layer/CMakeLists.txt
new file mode 100644
index 0000000..ddf7615
--- /dev/null
+++ b/python/physical_layer/CMakeLists.txt
@@ -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
+)
+
diff --git a/python/physical_layer/STANAG_4285.py b/python/physical_layer/STANAG_4285.py
new file mode 100644
index 0000000..5dbc4c4
--- /dev/null
+++ b/python/physical_layer/STANAG_4285.py
@@ -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
diff --git a/python/physical_layer/__init__.py b/python/physical_layer/__init__.py
new file mode 100644
index 0000000..323c58c
--- /dev/null
+++ b/python/physical_layer/__init__.py
@@ -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
+#