intermediate

This commit is contained in:
Christoph Mayer 2019-08-27 08:49:07 +02:00
parent 7482ebfdbe
commit f1f3708dfa
13 changed files with 567 additions and 1 deletions

View File

@ -21,5 +21,6 @@ install(FILES
digitalhf_adaptive_dfe.xml
digitalhf_physical_layer_driver.xml
digitalhf_doppler_correction_cc.xml
digitalhf_cis_12_channelizer.xml
digitalhf_msg_proxy.xml DESTINATION share/gnuradio/grc/blocks
)

View File

@ -0,0 +1,32 @@
<?xml version="1.0"?>
<block>
<name>cis_12_channelizer</name>
<key>digitalhf_cis_12_channelizer</key>
<category>[digitalhf]</category>
<import>import digitalhf</import>
<make>digitalhf.cis_12_channelizer()</make>
<!-- Make one 'param' node for every Parameter you want settable from the GUI.
Sub-nodes:
* name
* key (makes the value accessible as $keyname, e.g. in the make node)
<param>
<name>...</name>
<key>...</key>
<type>...</type>
</param>
* type -->
<sink>
<name>in</name>
<type>complex</type>
</sink>
<source>
<name>out1</name>
<type>complex</type>
</source>
<source>
<name>out2</name>
<type>complex</type>
</source>
</block>

View File

@ -29,5 +29,6 @@ install(FILES
viterbi29.h
viterbi39.h
viterbi48.h
vector_pll_cc.h
DESTINATION include/digitalhf
)

View File

@ -0,0 +1,59 @@
/* -*- c++ -*- */
/*
* Copyright 2018 hcab14@gmail.com.
*
* This 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 software 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 software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DIGITALHF_VECTOR_PLL_CC_H
#define INCLUDED_DIGITALHF_VECTOR_PLL_CC_H
#include <digitalhf/api.h>
#include <gnuradio/sync_block.h>
namespace gr {
namespace digitalhf {
/*!
* \brief <+description of block+>
* \ingroup digitalhf
*
*/
class DIGITALHF_API vector_pll_cc : virtual public gr::sync_block
{
public:
typedef boost::shared_ptr<vector_pll_cc> sptr;
/*!
* \brief Return a shared_ptr to a new instance of digitalhf::vector_pll_cc.
*
* To avoid accidental use of raw pointers, digitalhf::vector_pll_cc's
* constructor is in a private implementation
* class. digitalhf::vector_pll_cc::make is the public interface for
* creating new instances.
*/
static sptr make(float samp_rate,
size_t order,
std::vector<int> freq_multipliers);
};
} // namespace digitalhf
} // namespace gr
#endif /* INCLUDED_DIGITALHF_VECTOR_PLL_CC_H */

View File

@ -31,7 +31,8 @@ list(APPEND digitalhf_sources
viterbi27_impl.cc
viterbi29_impl.cc
viterbi39_impl.cc
viterbi48_impl.cc)
viterbi48_impl.cc
vector_pll_cc_impl.cc)
set(digitalhf_sources "${digitalhf_sources}" PARENT_SCOPE)
if(NOT digitalhf_sources)

131
lib/vector_pll_cc_impl.cc Normal file
View File

@ -0,0 +1,131 @@
/* -*- c++ -*- */
/*
* Copyright 2018 hcab14@gmail.com.
*
* This 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 software 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 software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <cmath>
#include <gnuradio/io_signature.h>
#include <gnuradio/expj.h>
#include <gnuradio/logger.h>
#include "vector_pll_cc_impl.h"
namespace gr {
namespace digitalhf {
vector_pll_cc::sptr
vector_pll_cc::make(float samp_rate,
size_t order,
std::vector<int> freq_multipliers)
{
return gnuradio::get_initial_sptr
(new vector_pll_cc_impl(samp_rate,
order,
freq_multipliers));
}
/*
* The private constructor
*/
vector_pll_cc_impl::vector_pll_cc_impl(float samp_rate,
size_t order,
std::vector<int> freq_multipliers)
: gr::sync_block("vector_pll_cc",
gr::io_signature::make(1, 1, freq_multipliers.size() * sizeof(gr_complex)),
gr::io_signature::make(1, 1, freq_multipliers.size() * sizeof(gr_complex)))
, _ts(1.0/samp_rate)
, _order(order)
, _freq_multipliers(freq_multipliers)
, _control_loop(6.28/600.0, -6.28/600.0*10, 6.28/600.0*10)
, _theta (freq_multipliers.size(), 0.0f)
, _dtheta(freq_multipliers.size(), 0.0f)
, _absz(freq_multipliers.size(), 1.0f)
, _b({+0.6284830097698858,
-0.6281540229565162})
, _uf(0)
, _ud(0)
{
GR_LOG_DECLARE_LOGPTR(d_logger);
GR_LOG_ASSIGN_LOGPTR(d_logger, "vector_pll_cc");
for (int i=0; i<_freq_multipliers.size(); ++i) {
std::cout << "FM: " << i <<" " << _freq_multipliers[i] << std::endl;
}
}
vector_pll_cc_impl::~vector_pll_cc_impl()
{
}
int
vector_pll_cc_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
gr::thread::scoped_lock lock(d_setlock);
size_t const vlen = _freq_multipliers.size();
const gr_complex *in = (const gr_complex*)input_items[0];
gr_complex *out = (gr_complex*)output_items[0];
_control_loop.frequency_limit();
std::vector<float> error(vlen);
float const mu = 5e-2;
for (int i=0; i<noutput_items; ++i) {
for (int j=0; j<vlen; ++j) {
_theta[j] += _uf * _freq_multipliers[j] * _ts + _dtheta[j];
_theta[j] = std::fmod(_theta[j], 2*M_PI*_order);
out[j] = gr_expj(-_theta[j]/_order) * in[j];
}
float weight=0, sum_weights=0;
for (int j=0; j<vlen; ++j) {
gr_complex z = in[j];
for (size_t k=1; k<_order; k*=2)
z *= z;
_absz[j] = weight = 0.99*_absz[j] + 0.01*std::abs(z);
sum_weights += weight;
gr_complex const x = gr_expj(-_theta[j]) * z;
error[j] = std::imag(x)/std::abs(x) * weight;
}
float sum_error = 0;
for (int j=0; j<vlen; ++j) {
error[j] *= vlen / sum_weights;
sum_error += error[j];
_dtheta[j] = mu * error[j];
}
float const ud = sum_error / vlen;
_uf += _b[0]*ud + _b[1]*_ud;
_ud = ud;
in += vlen;
out += vlen;
}
return noutput_items;
}
} /* namespace digitalhf */
} /* namespace gr */

63
lib/vector_pll_cc_impl.h Normal file
View File

@ -0,0 +1,63 @@
/* -*- c++ -*- */
/*
* Copyright 2018 hcab14@gmail.com.
*
* This 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 software 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 software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DIGITALHF_VECTOR_PLL_CC_IMPL_H
#define INCLUDED_DIGITALHF_VECTOR_PLL_CC_IMPL_H
#include <gnuradio/blocks/control_loop.h>
#include <digitalhf/vector_pll_cc.h>
#include <array>
namespace gr {
namespace digitalhf {
class vector_pll_cc_impl : public vector_pll_cc
{
private:
float _ts; // sample time (sec)
size_t _order; //
std::vector<int> _freq_multipliers;
gr::blocks::control_loop _control_loop;
std::vector<float> _theta;
std::vector<float> _dtheta;
std::vector<float> _absz;
std::array<float, 2> _b;
float _uf;
float _ud;
public:
vector_pll_cc_impl(float samp_rate,
size_t order,
std::vector<int> freq_multipliers);
virtual ~vector_pll_cc_impl();
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
protected:
};
} // namespace digitalhf
} // namespace gr
#endif /* INCLUDED_DIGITALHF_VECTOR_PLL_CC_IMPL_H */

View File

@ -33,6 +33,7 @@ GR_PYTHON_INSTALL(
FILES
__init__.py
physical_layer_driver.py
cis_12_channelizer.py
msg_proxy.py DESTINATION ${GR_PYTHON_DIR}/digitalhf
)

View File

@ -33,4 +33,5 @@ except ImportError:
# import any pure python here
from .physical_layer_driver import physical_layer_driver
from .msg_proxy import msg_proxy
from .cis_12_channelizer import cis_12_channelizer
#

View File

@ -0,0 +1,119 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2019 hcab14@gmail.com.
#
# This 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 software 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 software; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
import importlib
from gnuradio import analog
from gnuradio import blocks
from gnuradio import digital
from gnuradio import filter
from gnuradio.filter import firdes
from gnuradio.filter import pfb
from gnuradio import gr
import pmt
import digitalhf
import numpy as np
class cis_12_channelizer(gr.hier_block2):
"""
docstring for block CIS-12 channelizer
"""
def __init__(self):
gr.hier_block2.__init__(self,
"cis_12_channelizer",
gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
gr.io_signature(2, 2, gr.sizeof_gr_complex)) # Output signature
self.samp_rate = samp_rate = 12000.0
self.analog_pll_refout_cc_0 = analog.pll_refout_cc(2*np.pi/1000,
2*np.pi*3270/samp_rate,
2*np.pi*3330/samp_rate)
taps_pfb = firdes.low_pass_2(1,
self.samp_rate,
0.45*self.samp_rate/60,
0.05*self.samp_rate/60,
attenuation_dB=100,
window=filter.firdes.WIN_BLACKMAN_HARRIS)
taps_3300 = firdes.band_pass_2(1,
self.samp_rate,
3200,
3400,
100,
attenuation_dB=60,
window=filter.firdes.WIN_BLACKMAN_HARRIS)
print('N=', len(taps_3300))
self.filter_fir_filter_ccf_0 = filter.fir_filter_ccf(1,taps_3300)
self.blocks_multiply_conjugate_cc_0 = blocks.multiply_conjugate_cc(1)
self.blocks_delay_0 = blocks.delay(gr.sizeof_gr_complex,
(len(taps_3300)-1) // 2)
self.pfb_channelizer_ccf_0 = pfb.channelizer_ccf(
60,
(taps_pfb),
1.0,
100)
chmap = 60-(2+np.arange(12))
self.pfb_channelizer_ccf_0.set_channel_map((chmap.tolist()))
self.pfb_channelizer_ccf_0.set_channel_map(([47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58]))
self.pfb_channelizer_ccf_0.declare_sample_delay(0)
self.blocks_streams_to_vector_0 = blocks.streams_to_vector(gr.sizeof_gr_complex, 12)
self.blocks_streams_to_vector_1 = blocks.streams_to_vector(gr.sizeof_gr_complex, 48)
self.blocks_vector_to_stream_0 = blocks.vector_to_stream(gr.sizeof_gr_complex, 12)
self.blocks_vector_pll_cc_0 = digitalhf.vector_pll_cc(samp_rate = 600.0,
order = 2,
freq_multipliers = [13,12,11,10,9,8,7,6,5,4,3,2])
self.blocks_resamplers = [[] for _ in range(12)]
for i in range(12):
self.blocks_resamplers[i] = filter.rational_resampler_ccf(3,1)
self.connect((self, 0),
(self.filter_fir_filter_ccf_0, 0),
(self.analog_pll_refout_cc_0, 0),
(self.blocks_multiply_conjugate_cc_0, 1))
self.connect((self, 0),
(self.blocks_delay_0),
(self.blocks_multiply_conjugate_cc_0, 0))
self.connect((self.blocks_multiply_conjugate_cc_0, 0),
(self.pfb_channelizer_ccf_0, 0))
self.connect((self.blocks_multiply_conjugate_cc_0, 0), (self, 1))
#self.connect((self.filter_fir_filter_ccf_0, 0),
# (self, 1))
for i in range(12):
self.connect((self.pfb_channelizer_ccf_0, i),
(self.blocks_resamplers[i], 0),
(self.blocks_streams_to_vector_0, i))
self.blocks_null_sink_0 = blocks.null_sink(48*gr.sizeof_gr_complex)
for i in range(48):
self.connect((self.pfb_channelizer_ccf_0, 12+i), (self.blocks_streams_to_vector_1, i))
self.connect(self.blocks_streams_to_vector_1, self.blocks_null_sink_0)
self.connect(self.blocks_streams_to_vector_0,
self.blocks_vector_pll_cc_0,
self.blocks_vector_to_stream_0,
self)
#self.connect((self,0),
# (self.analog_pll_refout_cc_0, 0),
# (self,0))

View File

@ -0,0 +1,53 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2018 hcab14@mail.com.
#
# This 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 software 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 software; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
import digitalhf.digitalhf_swig as digitalhf
import random
import pmt
import numpy as np
def main():
v = digitalhf.viterbi27(0x6d, 0x4f)
N = 35*500+5
bits = [random.randint(0,1) for _ in range(N+7)]
a = [1,0,1,1,0,1,1]
b = [1,1,1,1,0,0,1]
llr_encoded_bits = []
for i in range(N):
t1=t2=0
for j in range(7):
t1 += a[j]*bits[i+7-j]
t2 += b[j]*bits[i+7-j]
llr_encoded_bits.extend([7*(1-2*(t1%2)), 7*(1-2*(t2%2))])
v.reset()
llr_encoded_bits = np.array(llr_encoded_bits)
llr_encoded_bits[3::6] = 0
llr_encoded_bits[4::6] = 0
decoded_bits = v.udpate(llr_encoded_bits)
print(bits[7:37])
print(decoded_bits[0:30])
print('quality:', v.quality()*1.2/2/N)
test = [all([decoded_bits[i] == bits[i+7] for i in range(N)]), abs(v.quality()*1.2-2*N)<1]
print('test:', test)
if not all(test):
raise Exception(test)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,100 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2018 hcab14@mail.com.
#
# This 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 software 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 software; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
import digitalhf.digitalhf_swig as digitalhf
import pmt
import numpy as np
def bit2llr(b):
return 7.0*(1 - 2*b)
class ViterbiEncoder(object):
def __init__(self, k, taps):
self._state = np.zeros(k, dtype=np.uint16)
self._taps = taps
def encode(self, bit):
self._state = np.roll(self._state, 1)
self._state[0] = bit
return [bit2llr(self._state.dot(tap) % 2) for tap in self._taps]
def run_test(N, data):
decoder = data['dec'](*data['polys'])
encoder = ViterbiEncoder(data['k'], data['taps'])
k = data['k']
for p,t in zip(data['polys'], data['taps']):
_t = [b=='1' for b in np.binary_repr(p,k)]
test = _t == t[::-1]
if not test:
raise Exception('inconsistent taps', _t, t[::-1])
np.random.seed(123)
bits = np.random.randint(2, size=N)
M = len(data['polys'])
llr_encoded_bits = np.zeros(M*N, dtype=np.float64)
for i in range(N-k+1,N):
encoder.encode(bits[i])
for i in range(0,N):
llr_encoded_bits[M*i:M*(i+1)] = encoder.encode(bits[i])
print(llr_encoded_bits[:14])
llr_encoded_bits[3::4] = 0
decoded_bits = np.roll(decoder.udpate(llr_encoded_bits), 0)
print(decoded_bits.tolist())
print(bits.tolist())
print('quality:', decoder.quality(), 100*4/3.5*decoder.quality()/M/N)
test = [np.all(decoded_bits == bits), abs(4/3.5*decoder.quality()-M*N)<1]
print('test:', test)
if not all(test):
raise Exception(test)
def main():
data = [{'dec' : digitalhf.viterbi27,
'polys': [0x6D, 0x4F],
'k' : 7,
'taps' : [[1,0,1,1,0,1,1],
[1,1,1,1,0,0,1]]},
{'dec' : digitalhf.viterbi29,
'polys': [0x11d, 0x1af],
'k' : 9,
'taps' : [[1,0,1,1,1,0,0,0,1],
[1,1,1,1,0,1,0,1,1]]},
{'dec' : digitalhf.viterbi39,
'polys': [0x127, 0x19B, 0x1ED],
'k' : 9,
'taps' : [[1,1,1,0,0,1,0,0,1],
[1,1,0,1,1,0,0,1,1],
[1,0,1,1,0,1,1,1,1]]},
{'dec' : digitalhf.viterbi48,
'polys': [0xB9, 0x9D, 0xD3, 0xF7],
'k' : 8,
'taps' : [[1,0,0,1,1,1,0,1],
[1,0,1,1,1,0,0,1],
[1,1,0,0,1,0,1,1],
[1,1,1,0,1,1,1,1]]}]
for d in data:
run_test(45, d)
if __name__ == '__main__':
main()

View File

@ -14,6 +14,7 @@
#include "digitalhf/viterbi29.h"
#include "digitalhf/viterbi39.h"
#include "digitalhf/viterbi48.h"
#include "digitalhf/vector_pll_cc.h"
%}
%include "digitalhf/adaptive_dfe.h"
@ -22,6 +23,9 @@ GR_SWIG_BLOCK_MAGIC2(digitalhf, adaptive_dfe);
%include "digitalhf/doppler_correction_cc.h"
GR_SWIG_BLOCK_MAGIC2(digitalhf, doppler_correction_cc);
%include "digitalhf/vector_pll_cc.h"
GR_SWIG_BLOCK_MAGIC2(digitalhf, vector_pll_cc);
/* FIXME */
%include "digitalhf/viterbi27.h"
GR_SWIG_BLOCK_MAGIC2(digitalhf, viterbi27);