summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/Packaging/Ubuntu-15.10.cmake13
-rw-r--r--gr-dtv/CMakeLists.txt2
-rw-r--r--gr-dtv/examples/CMakeLists.txt25
-rwxr-xr-xgr-dtv/examples/atsc_ctrlport_monitor.py149
-rw-r--r--gr-dtv/include/gnuradio/dtv/atsc_equalizer.h3
-rw-r--r--gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h15
-rw-r--r--gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h6
-rw-r--r--gr-dtv/lib/atsc/atsc_equalizer_impl.cc89
-rw-r--r--gr-dtv/lib/atsc/atsc_equalizer_impl.h7
-rw-r--r--gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc89
-rw-r--r--gr-dtv/lib/atsc/atsc_rs_decoder_impl.h13
-rw-r--r--gr-dtv/lib/atsc/atsc_single_viterbi.cc65
-rw-r--r--gr-dtv/lib/atsc/atsc_single_viterbi.h17
-rw-r--r--gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc25
-rw-r--r--gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h4
-rw-r--r--gr-uhd/include/gnuradio/uhd/usrp_source.h5
-rw-r--r--gr-uhd/lib/usrp_sink_impl.cc6
-rw-r--r--gr-uhd/lib/usrp_source_impl.cc45
-rw-r--r--gr-uhd/lib/usrp_source_impl.h4
19 files changed, 482 insertions, 100 deletions
diff --git a/cmake/Packaging/Ubuntu-15.10.cmake b/cmake/Packaging/Ubuntu-15.10.cmake
new file mode 100644
index 0000000000..ed14b1ab22
--- /dev/null
+++ b/cmake/Packaging/Ubuntu-15.10.cmake
@@ -0,0 +1,13 @@
+SET(PACKAGE_DEPENDS_GRUEL_RUNTIME "libboost-all-dev" "libc6")
+SET(PACKAGE_DEPENDS_UTILS "python-mako")
+SET(PACKAGE_DEPENDS_GRUEL_PYTHON "python" "python-numpy")
+SET(PACKAGE_DEPENDS_CORE_RUNTIME "libfftw3-3")
+SET(PACKAGE_DEPENDS_QTGUI_RUNTIME "libqtcore4" "libqwt6")
+SET(PACKAGE_DEPENDS_QTGUI_PYTHON "python-qt4" "python-qwt5-qt4")
+SET(PACKAGE_DEPENDS_GRC "python" "python-numpy" "python-gtk2" "python-lxml" "python-cheetah")
+SET(PACKAGE_DEPENDS_WXGUI "python-wxgtk2.8" "python-opengl")
+SET(PACKAGE_DEPENDS_VIDEO_SDL_RUNTIME "libsdl1.2debian")
+SET(PACKAGE_DEPENDS_UHD_RUNTIME "uhd")
+SET(PACKAGE_DEPENDS_AUDIO_RUNTIME "libpulse0" "alsa-base" "libjack0")
+SET(PACKAGE_DEPENDS_WAVELET_RUNTIME "libgsl0ldbl")
+SET(PACKAGE_DEPENDS_WAVELET_PYTHON "python" "python-numpy")
diff --git a/gr-dtv/CMakeLists.txt b/gr-dtv/CMakeLists.txt
index fc7ab56bef..5a23482b26 100644
--- a/gr-dtv/CMakeLists.txt
+++ b/gr-dtv/CMakeLists.txt
@@ -41,6 +41,8 @@ GR_SET_GLOBAL(GR_DTV_INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}/lib
)
+SET(GR_PKG_DTV_EXAMPLES_DIR ${GR_PKG_DATA_DIR}/examples/dtv)
+
########################################################################
# Begin conditional configuration
########################################################################
diff --git a/gr-dtv/examples/CMakeLists.txt b/gr-dtv/examples/CMakeLists.txt
index 82b663d924..315cb33de9 100644
--- a/gr-dtv/examples/CMakeLists.txt
+++ b/gr-dtv/examples/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2014 Free Software Foundation, Inc.
+# Copyright 2014-2015 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -21,6 +21,29 @@ include(GrPython)
GR_PYTHON_INSTALL(
PROGRAMS
+ atsc_ctrlport_monitor.py
+ DESTINATION ${GR_PKG_DTV_EXAMPLES_DIR}
+ COMPONENT "dtv_python"
+)
+
+install(
+ FILES
+ README.dvbs
+ README.dvbs2
+ README.dvbt
+ README.dvbt2
+ dvbs2_tx.grc
+ dvbs_tx.grc
+ dvbt_rx_8k.grc
+ dvbt_tx_2k.grc
+ dvbt_tx_8k.grc
+ file_atsc_rx.grc
+ file_atsc_tx.grc
+ uhd_atsc_capture.grc
+ uhd_rx_atsc.grc
+ vv003-cr23.grc
+ vv009-4kfft.grc
+ vv018-miso.grc
DESTINATION ${GR_PKG_DTV_EXAMPLES_DIR}
COMPONENT "dtv_python"
)
diff --git a/gr-dtv/examples/atsc_ctrlport_monitor.py b/gr-dtv/examples/atsc_ctrlport_monitor.py
new file mode 100755
index 0000000000..7c43aebb77
--- /dev/null
+++ b/gr-dtv/examples/atsc_ctrlport_monitor.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Free Software Foundation
+#
+# This program 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 program 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; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import sys
+import matplotlib
+matplotlib.use("QT4Agg")
+import matplotlib.pyplot as plt
+import matplotlib.animation as animation
+from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient
+import scipy
+from scipy import fftpack
+
+"""
+If a host is running the ATSC receiver chain with ControlPort
+turned on, this script will connect to the host using the hostname and
+port pair of the ControlPort instance and display metrics of the
+receiver. The ATSC publishes information about the succes of the
+Reed-Solomon decoder and Viterbi metrics for use here in displaying
+the link quality. This also gets the equalizer taps of the receiver
+and displays the frequency response.
+"""
+
+class atsc_ctrlport_monitor:
+ def __init__(self, host, port):
+ argv = [None, host, port]
+ radiosys = GNURadioControlPortClient(argv=argv, rpcmethod='thrift')
+ self.radio = radiosys.client
+ print self.radio
+
+
+ vt_init_key = 'dtv_atsc_viterbi_decoder0::decoder_metrics'
+ data = self.radio.getKnobs([vt_init_key])[vt_init_key]
+ init_metric = scipy.mean(data.value)
+ self._viterbi_metric = 100*[init_metric,]
+
+ table_col_labels = ('Num Packets', 'Error Rate', 'Packet Error Rate',
+ 'Viterbi Metric', 'SNR')
+
+ self._fig = plt.figure(1, figsize=(12,12), facecolor='w')
+ self._sp0 = self._fig.add_subplot(4,1,1)
+ self._sp1 = self._fig.add_subplot(4,1,2)
+ self._sp2 = self._fig.add_subplot(4,1,3)
+ self._plot_taps = self._sp0.plot([], [], 'k', linewidth=2)
+ self._plot_psd = self._sp1.plot([], [], 'k', linewidth=2)
+ self._plot_data = self._sp2.plot([], [], 'ok', linewidth=2, markersize=4, alpha=0.05)
+
+ self._ax2 = self._fig.add_subplot(4,1,4)
+ self._table = self._ax2.table(cellText=[len(table_col_labels)*['0']],
+ colLabels=table_col_labels,
+ loc='center')
+ self._ax2.axis('off')
+ cells = self._table.properties()['child_artists']
+ for c in cells:
+ c.set_lw(0.1) # set's line width
+ c.set_ls('solid')
+ c.set_height(0.2)
+
+ ani = animation.FuncAnimation(self._fig, self.update_data, frames=200,
+ fargs=(self._plot_taps[0], self._plot_psd[0],
+ self._plot_data[0], self._table),
+ init_func=self.init_function,
+ blit=True)
+ plt.show()
+
+ def update_data(self, x, taps, psd, syms, table):
+ try:
+ eqdata_key = 'dtv_atsc_equalizer0::taps'
+ symdata_key = 'dtv_atsc_equalizer0::data'
+ rs_nump_key = 'dtv_atsc_rs_decoder0::num_packets'
+ rs_numbp_key = 'dtv_atsc_rs_decoder0::num_bad_packets'
+ rs_numerrs_key = 'dtv_atsc_rs_decoder0::num_errors_corrected'
+ vt_metrics_key = 'dtv_atsc_viterbi_decoder0::decoder_metrics'
+ snr_key = 'probe2_f0::SNR'
+
+ data = self.radio.getKnobs([])
+ eqdata = data[eqdata_key]
+ symdata = data[symdata_key]
+ rs_num_packets = data[rs_nump_key]
+ rs_num_bad_packets = data[rs_numbp_key]
+ rs_num_errors_corrected = data[rs_numerrs_key]
+ vt_decoder_metrics = data[vt_metrics_key]
+ snr_est = data[snr_key]
+
+ vt_decoder_metrics = scipy.mean(vt_decoder_metrics.value)
+ self._viterbi_metric.pop()
+ self._viterbi_metric.insert(0, vt_decoder_metrics)
+
+ except:
+ sys.stderr.write("Lost connection, exiting")
+ sys.exit(1)
+
+ ntaps = len(eqdata.value)
+ taps.set_ydata(eqdata.value)
+ taps.set_xdata(xrange(ntaps))
+ self._sp0.set_xlim(0, ntaps)
+ self._sp0.set_ylim(min(eqdata.value), max(eqdata.value))
+
+ fs = 6.25e6
+ freq = scipy.linspace(-fs/2, fs/2, 10000)
+ H = fftpack.fftshift(fftpack.fft(eqdata.value, 10000))
+ HdB = 20.0*scipy.log10(abs(H))
+ psd.set_ydata(HdB)
+ psd.set_xdata(freq)
+ self._sp1.set_xlim(0, fs/2)
+ self._sp1.set_ylim([min(HdB), max(HdB)])
+ self._sp1.set_yticks([min(HdB), max(HdB)])
+ self._sp1.set_yticklabels(["min", "max"])
+
+ nsyms = len(symdata.value)
+ syms.set_ydata(symdata.value)
+ syms.set_xdata(nsyms*[0,])
+ self._sp2.set_xlim([-1, 1])
+ self._sp2.set_ylim([-10, 10])
+
+ per = float(rs_num_bad_packets.value) / float(rs_num_packets.value)
+ ber = float(rs_num_errors_corrected.value) / float(187*rs_num_packets.value)
+
+ table._cells[(1,0)]._text.set_text("{0}".format(rs_num_packets.value))
+ table._cells[(1,1)]._text.set_text("{0:.2g}".format(ber))
+ table._cells[(1,2)]._text.set_text("{0:.2g}".format(per))
+ table._cells[(1,3)]._text.set_text("{0:.1f}".format(scipy.mean(self._viterbi_metric)))
+ table._cells[(1,4)]._text.set_text("{0:.4f}".format(snr_est.value[0]))
+
+ return (taps, psd, syms, table)
+
+ def init_function(self):
+ return self._plot_taps + self._plot_psd + self._plot_data
+
+if __name__ == "__main__":
+ host = sys.argv[1]
+ port = sys.argv[2]
+ m = atsc_ctrlport_monitor(host, port)
diff --git a/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h b/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h
index 3fe101ac25..17f2e8f768 100644
--- a/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h
+++ b/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h
@@ -45,6 +45,9 @@ namespace gr {
* \brief Make a new instance of gr::dtv::atsc_equalizer.
*/
static sptr make();
+
+ virtual std::vector<float> taps() const = 0;
+ virtual std::vector<float> data() const = 0;
};
} /* namespace dtv */
diff --git a/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h b/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h
index 92eb263e5d..c2b7d0defa 100644
--- a/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h
+++ b/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h
@@ -42,6 +42,21 @@ namespace gr {
typedef boost::shared_ptr<atsc_rs_decoder> sptr;
/*!
+ * Returns the number of errors corrected by the decoder.
+ */
+ virtual int num_errors_corrected() const = 0;
+
+ /*!
+ * Returns the number of bad packets rejected by the decoder.
+ */
+ virtual int num_bad_packets() const = 0;
+
+ /*!
+ * Returns the total number of packets seen by the decoder.
+ */
+ virtual int num_packets() const = 0;
+
+ /*!
* \brief Make a new instance of gr::dtv::atsc_rs_decoder.
*/
static sptr make();
diff --git a/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h b/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h
index a4c18c39da..8efece4c43 100644
--- a/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h
+++ b/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h
@@ -45,6 +45,12 @@ namespace gr {
* \brief Make a new instance of gr::dtv::atsc_viterbi_decoder.
*/
static sptr make();
+
+ /*!
+ * For each decoder, returns the current best state of the
+ * decoding metrics.
+ */
+ virtual std::vector<float> decoder_metrics() const = 0;
};
} /* namespace dtv */
diff --git a/gr-dtv/lib/atsc/atsc_equalizer_impl.cc b/gr-dtv/lib/atsc/atsc_equalizer_impl.cc
index c804be6dc7..de01cea6f2 100644
--- a/gr-dtv/lib/atsc/atsc_equalizer_impl.cc
+++ b/gr-dtv/lib/atsc/atsc_equalizer_impl.cc
@@ -28,6 +28,7 @@
#include "atsc_types.h"
#include "atsc_pnXXX_impl.h"
#include <gnuradio/io_signature.h>
+#include <volk/volk.h>
namespace gr {
namespace dtv {
@@ -76,23 +77,42 @@ namespace gr {
init_field_sync_common(training_sequence1, 0);
init_field_sync_common(training_sequence2, 1);
- for (int i = 0; i < NTAPS; i++)
- d_taps[i] = 0.0;
+ d_taps.resize(NTAPS, 0.0f);
d_buff_not_filled = true;
+
+ const int alignment_multiple =
+ volk_get_alignment() / sizeof(float);
+ set_alignment(std::max(1, alignment_multiple));
}
atsc_equalizer_impl::~atsc_equalizer_impl()
{
}
+ std::vector<float>
+ atsc_equalizer_impl::taps() const
+ {
+ return d_taps;
+ }
+
+ std::vector<float>
+ atsc_equalizer_impl::data() const
+ {
+ std::vector<float> ret(&data_mem2[0], &data_mem2[ATSC_DATA_SEGMENT_LENGTH-1]);
+ return ret;
+ }
+
void
- atsc_equalizer_impl::filterN(const float *input_samples, float *output_samples, int nsamples)
+ atsc_equalizer_impl::filterN(const float *input_samples,
+ float *output_samples,
+ int nsamples)
{
for (int j = 0; j < nsamples; j++) {
output_samples[j] = 0;
- for(int i = 0; i < NTAPS; i++)
- output_samples[j] += d_taps[i] * input_samples[j + i];
+ volk_32f_x2_dot_prod_32f(&output_samples[j],
+ &input_samples[j],
+ &d_taps[0], NTAPS);
}
}
@@ -107,14 +127,16 @@ namespace gr {
for(int j = 0; j < nsamples; j++) {
output_samples[j] = 0;
- for( int i = 0; i < NTAPS; i++ )
- output_samples[j] += d_taps[i] * input_samples[j + i];
+ volk_32f_x2_dot_prod_32f(&output_samples[j],
+ &input_samples[j],
+ &d_taps[0], NTAPS);
- double e = output_samples[j] - training_pattern[j];
+ float e = output_samples[j] - training_pattern[j];
// update taps...
- for( int i = 0; i < NTAPS; i++ )
- d_taps[i] -= BETA * e * (double)(input_samples[j + i]);
+ float tmp_taps[NTAPS];
+ volk_32f_s32f_multiply_32f(tmp_taps, &input_samples[j], BETA*e, NTAPS);
+ volk_32f_x2_subtract_32f(&d_taps[0], &d_taps[0], tmp_taps, NTAPS);
}
}
@@ -131,8 +153,8 @@ namespace gr {
int i = 0;
if(d_buff_not_filled) {
- for(int j = 0; j < ATSC_DATA_SEGMENT_LENGTH; j++)
- data_mem[NPRETAPS + j] = in[i].data[j];
+ memcpy(&data_mem[NPRETAPS], in[i].data,
+ ATSC_DATA_SEGMENT_LENGTH*sizeof(float));
d_flags = in[i].pli._flags;
d_segno = in[i].pli._segno;
d_buff_not_filled = false;
@@ -141,8 +163,8 @@ namespace gr {
for (; i < noutput_items; i++) {
- for(int j = 0; j < NTAPS - NPRETAPS; j++)
- data_mem[ATSC_DATA_SEGMENT_LENGTH + NPRETAPS + j] = in[i].data[j];
+ memcpy(&data_mem[ATSC_DATA_SEGMENT_LENGTH + NPRETAPS], in[i].data,
+ (NTAPS - NPRETAPS)*sizeof(float));
if(d_segno == -1) {
if(d_flags & 0x0010) {
@@ -157,19 +179,18 @@ namespace gr {
else {
filterN(data_mem, data_mem2, ATSC_DATA_SEGMENT_LENGTH);
- for(int j = 0; j < ATSC_DATA_SEGMENT_LENGTH; j++)
- out[output_produced].data[j] = data_mem2[j];
+ memcpy(out[output_produced].data, data_mem2,
+ ATSC_DATA_SEGMENT_LENGTH*sizeof(float));
out[output_produced].pli._flags = d_flags;
out[output_produced].pli._segno = d_segno;
output_produced++;
}
- for( int j = 0; j < NPRETAPS; j++ )
- data_mem[j] = data_mem[ATSC_DATA_SEGMENT_LENGTH + j];
-
- for(int j = 0; j < ATSC_DATA_SEGMENT_LENGTH; j++)
- data_mem[NPRETAPS + j] = in[i].data[j];
+ memcpy(data_mem, &data_mem[ATSC_DATA_SEGMENT_LENGTH],
+ NPRETAPS*sizeof(float));
+ memcpy(&data_mem[NPRETAPS], in[i].data,
+ ATSC_DATA_SEGMENT_LENGTH*sizeof(float));
d_flags = in[i].pli._flags;
d_segno = in[i].pli._segno;
@@ -179,5 +200,31 @@ namespace gr {
return output_produced;
}
+ void
+ atsc_equalizer_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_equalizer, std::vector<float> >(
+ alias(), "taps",
+ &atsc_equalizer::taps,
+ pmt::make_f32vector(1,-10),
+ pmt::make_f32vector(1,10),
+ pmt::make_f32vector(1,0),
+ "", "Equalizer Taps", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_equalizer, std::vector<float> >(
+ alias(), "data",
+ &atsc_equalizer::data,
+ pmt::make_f32vector(1,-10),
+ pmt::make_f32vector(1,10),
+ pmt::make_f32vector(1,0),
+ "", "Post-equalizer Data", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+#endif /* GR_CTRLPORT */
+ }
+
} /* namespace dtv */
} /* namespace gr */
diff --git a/gr-dtv/lib/atsc/atsc_equalizer_impl.h b/gr-dtv/lib/atsc/atsc_equalizer_impl.h
index 6ff89ca646..75862f6408 100644
--- a/gr-dtv/lib/atsc/atsc_equalizer_impl.h
+++ b/gr-dtv/lib/atsc/atsc_equalizer_impl.h
@@ -46,7 +46,7 @@ namespace gr {
void adaptN(const float *input_samples, const float *training_pattern,
float *output_samples, int nsamples);
- float d_taps[NTAPS];
+ std::vector<float> d_taps;
float data_mem[ATSC_DATA_SEGMENT_LENGTH + NTAPS]; // Buffer for previous data packet
float data_mem2[ATSC_DATA_SEGMENT_LENGTH];
@@ -59,6 +59,11 @@ namespace gr {
atsc_equalizer_impl();
~atsc_equalizer_impl();
+ void setup_rpc();
+
+ std::vector<float> taps() const;
+ std::vector<float> data() const;
+
virtual int general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
diff --git a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc
index 7a950e716e..b8ee91a52d 100644
--- a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc
+++ b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc
@@ -56,9 +56,9 @@ namespace gr {
{
d_rs = init_rs_char(rs_init_symsize, rs_init_gfpoly, rs_init_fcr, rs_init_prim, rs_init_nroots);
assert (d_rs != 0);
- nerrors_corrrected_count = 0;
- bad_packet_count = 0;
- total_packets = 0;
+ d_nerrors_corrrected_count = 0;
+ d_bad_packet_count = 0;
+ d_total_packets = 0;
}
int atsc_rs_decoder_impl::decode (atsc_mpeg_packet_no_sync &out, const atsc_mpeg_packet_rs_encoded &in)
@@ -89,6 +89,24 @@ namespace gr {
}
int
+ atsc_rs_decoder_impl::num_errors_corrected() const
+ {
+ return d_nerrors_corrrected_count;
+ }
+
+ int
+ atsc_rs_decoder_impl::num_bad_packets() const
+ {
+ return d_bad_packet_count;
+ }
+
+ int
+ atsc_rs_decoder_impl::num_packets() const
+ {
+ return d_total_packets;
+ }
+
+ int
atsc_rs_decoder_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
@@ -102,24 +120,20 @@ namespace gr {
int nerrors_corrrected = decode(out[i], in[i]);
out[i].pli.set_transport_error(nerrors_corrrected == -1);
- if (nerrors_corrrected == -1)
- bad_packet_count++;
- else
- nerrors_corrrected_count += nerrors_corrrected;
+ if (nerrors_corrrected == -1) {
+ d_bad_packet_count++;
+ d_nerrors_corrrected_count += 10; // lower bound estimate; most this RS can fix
+ }
+ else {
+ d_nerrors_corrrected_count += nerrors_corrrected;
+ }
- total_packets++;
+ d_total_packets++;
#if 0
- if (total_packets > 1000) {
- // FIXME: convert to logger
- std::cout << "Error rate: "
- << (float)nerrors_corrrected_count/total_packets
- << "\tPacket error rate: "
- << (float)bad_packet_count/total_packets
- << std::endl;
-
- nerrors_corrrected_count = 0;
- bad_packet_count = 0;
- total_packets = 0;
+ if (d_total_packets > 1000) {
+ GR_LOG_INFO(d_logger, boost::format("Error rate: %1%\tPacket error rate: %2%") \
+ % ((float)d_nerrors_corrrected_count/(ATSC_MPEG_DATA_LENGTH*d_total_packets))
+ % ((float)d_bad_packet_count/d_total_packets));
}
#endif
}
@@ -127,5 +141,42 @@ namespace gr {
return noutput_items;
}
+
+ void
+ atsc_rs_decoder_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_rs_decoder, int >(
+ alias(), "num_errors_corrected",
+ &atsc_rs_decoder::num_errors_corrected,
+ pmt::from_long(0),
+ pmt::from_long(10000000),
+ pmt::from_long(0),
+ "", "Number of errors corrected", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_rs_decoder, int >(
+ alias(), "num_bad_packets",
+ &atsc_rs_decoder::num_bad_packets,
+ pmt::from_long(0),
+ pmt::from_long(10000000),
+ pmt::from_long(0),
+ "", "Number of bad packets", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_rs_decoder, int >(
+ alias(), "num_packets",
+ &atsc_rs_decoder::num_packets,
+ pmt::from_long(0),
+ pmt::from_long(10000000),
+ pmt::from_long(0),
+ "", "Number of packets", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+#endif /* GR_CTRLPORT */
+ }
+
} /* namespace dtv */
} /* namespace gr */
diff --git a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h
index 57460128dc..adbc4879a9 100644
--- a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h
+++ b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h
@@ -36,15 +36,22 @@ namespace gr {
class atsc_rs_decoder_impl : public atsc_rs_decoder
{
private:
- int nerrors_corrrected_count;
- int bad_packet_count;
- int total_packets;
+ int d_nerrors_corrrected_count;
+ int d_bad_packet_count;
+ int d_total_packets;
+ int d_total_bits;
void *d_rs;
public:
atsc_rs_decoder_impl();
~atsc_rs_decoder_impl();
+ void setup_rpc();
+
+ int num_errors_corrected() const;
+ int num_bad_packets() const;
+ int num_packets() const;
+
/*!
* Decode RS encoded packet.
* \returns a count of corrected symbols, or -1 if the block was uncorrectible.
diff --git a/gr-dtv/lib/atsc/atsc_single_viterbi.cc b/gr-dtv/lib/atsc/atsc_single_viterbi.cc
index 385940e453..011cc0fe96 100644
--- a/gr-dtv/lib/atsc/atsc_single_viterbi.cc
+++ b/gr-dtv/lib/atsc/atsc_single_viterbi.cc
@@ -28,7 +28,7 @@ namespace gr {
/* was_sent is a table of what symbol we get given what bit pair
was sent and what state we where in [state][pair] */
- const int atsc_single_viterbi::was_sent[4][4] = {
+ const int atsc_single_viterbi::d_was_sent[4][4] = {
{0,2,4,6},
{0,2,4,6},
{1,3,5,7},
@@ -37,7 +37,7 @@ namespace gr {
/* transition_table is a table of what state we were in
given current state and bit pair sent [state][pair] */
- const int atsc_single_viterbi::transition_table[4][4] = {
+ const int atsc_single_viterbi::d_transition_table[4][4] = {
{0,2,0,2},
{2,0,2,0},
{1,3,1,3},
@@ -49,11 +49,12 @@ namespace gr {
{
for (unsigned int i = 0; i<2; i++)
for (unsigned int j = 0; j<4; j++) {
- path_metrics[i][j] = 0;
- traceback[i][j] = 0;
+ d_path_metrics[i][j] = 0;
+ d_traceback[i][j] = 0;
}
- post_coder_state = 0;
- phase = 0;
+ d_post_coder_state = 0;
+ d_phase = 0;
+ d_best_state_metric = 100000;
}
atsc_single_viterbi::atsc_single_viterbi()
@@ -61,17 +62,24 @@ namespace gr {
reset();
}
+ float
+ atsc_single_viterbi::best_state_metric() const
+ {
+ return d_best_state_metric;
+ }
+
char
atsc_single_viterbi::decode(float input)
{
unsigned int best_state = 0;
- float best_state_metric = 100000;
+ //float best_state_metric = 100000;
+ d_best_state_metric = 100000;
/* Precompute distances from input to each possible symbol */
- float distances[8] = { (float)fabs( input + 7 ), (float)fabs( input + 5 ),
- (float)fabs( input + 3 ), (float)fabs( input + 1 ),
- (float)fabs( input - 1 ), (float)fabs( input - 3 ),
- (float)fabs( input - 5 ), (float)fabs( input - 7 ) };
+ float distances[8] = { fabsf( input + 7 ), fabsf( input + 5 ),
+ fabsf( input + 3 ), fabsf( input + 1 ),
+ fabsf( input - 1 ), fabsf( input - 3 ),
+ fabsf( input - 5 ), fabsf( input - 7 ) };
/* We start by iterating over all possible states */
for (unsigned int state = 0; state < 4; state++) {
@@ -79,15 +87,20 @@ namespace gr {
states to the state we are testing, we only need to look at
the 4 paths that can be taken given the 2-bit input */
int min_metric_symb = 0;
- float min_metric = distances[was_sent[state][0]] + path_metrics[phase][transition_table[state][0]];
+ float min_metric = distances[d_was_sent[state][0]] +
+ d_path_metrics[d_phase][d_transition_table[state][0]];
+
for (unsigned int symbol_sent = 1; symbol_sent < 4; symbol_sent++)
- if( (distances[was_sent[state][symbol_sent]] + path_metrics[phase][transition_table[state][symbol_sent]]) < min_metric) {
- min_metric = distances[was_sent[state][symbol_sent]] + path_metrics[phase][transition_table[state][symbol_sent]];
+ if( (distances[d_was_sent[state][symbol_sent]] +
+ d_path_metrics[d_phase][d_transition_table[state][symbol_sent]]) < min_metric) {
+ min_metric = distances[d_was_sent[state][symbol_sent]] +
+ d_path_metrics[d_phase][d_transition_table[state][symbol_sent]];
min_metric_symb = symbol_sent;
}
- path_metrics[phase^1][state] = min_metric;
- traceback[phase^1][state] = (((unsigned long long)min_metric_symb) << 62) | (traceback[phase][transition_table[state][min_metric_symb]] >> 2);
+ d_path_metrics[d_phase^1][state] = min_metric;
+ d_traceback[d_phase^1][state] = (((unsigned long long)min_metric_symb) << 62) |
+ (d_traceback[d_phase][d_transition_table[state][min_metric_symb]] >> 2);
/* If this is the most probable state so far remember it, this
only needs to be checked when we are about to output a path
@@ -98,26 +111,24 @@ namespace gr {
head state path will tend towards the optimal path with a
probability approaching 1 in just 8 or so transitions
*/
- if(min_metric <= best_state_metric) {
- best_state_metric = min_metric;
+ if(min_metric <= d_best_state_metric) {
+ d_best_state_metric = min_metric;
best_state = state;
}
}
- if(best_state_metric > 10000) {
+ if(d_best_state_metric > 10000) {
for(unsigned int state = 0; state < 4; state++)
- path_metrics[phase^1][state] -= best_state_metric;
+ d_path_metrics[d_phase^1][state] -= d_best_state_metric;
}
- phase ^= 1;
+ d_phase ^= 1;
- int y2 = (0x2 & traceback[phase][best_state]) >> 1;
- int x2 = y2 ^ post_coder_state;
- post_coder_state = y2;
+ int y2 = (0x2 & d_traceback[d_phase][best_state]) >> 1;
+ int x2 = y2 ^ d_post_coder_state;
+ d_post_coder_state = y2;
- return ( x2 << 1 ) | (0x1 & traceback[phase][best_state]);
+ return ( x2 << 1 ) | (0x1 & d_traceback[d_phase][best_state]);
}
} /* namespace dtv */
} /* namespace gr */
-
-
diff --git a/gr-dtv/lib/atsc/atsc_single_viterbi.h b/gr-dtv/lib/atsc/atsc_single_viterbi.h
index 3c756c7690..9522e2eb1b 100644
--- a/gr-dtv/lib/atsc/atsc_single_viterbi.h
+++ b/gr-dtv/lib/atsc/atsc_single_viterbi.h
@@ -44,14 +44,17 @@ namespace gr {
//! internal delay of decoder
static int delay () { return TB_LEN - 1; }
- protected:
- static const int transition_table[4][4];
- static const int was_sent[4][4];
+ float best_state_metric() const;
- float path_metrics [2][4];
- unsigned long long traceback [2][4];
- unsigned char phase;
- int post_coder_state;
+ protected:
+ static const int d_transition_table[4][4];
+ static const int d_was_sent[4][4];
+
+ float d_path_metrics [2][4];
+ unsigned long long d_traceback [2][4];
+ unsigned char d_phase;
+ int d_post_coder_state;
+ float d_best_state_metric;
};
} /* namespace dtv */
diff --git a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc
index 430eb55a17..2284372dfb 100644
--- a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc
+++ b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc
@@ -77,6 +77,15 @@ namespace gr {
fifo[i]->reset();
}
+ std::vector<float>
+ atsc_viterbi_decoder_impl::decoder_metrics() const
+ {
+ std::vector<float> metrics(NCODERS);
+ for (int i = 0; i < NCODERS; i++)
+ metrics[i] = viterbi[i].best_state_metric();
+ return metrics;
+ }
+
int
atsc_viterbi_decoder_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
@@ -135,5 +144,21 @@ namespace gr {
return noutput_items;
}
+ void
+ atsc_viterbi_decoder_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_viterbi_decoder, std::vector<float> >(
+ alias(), "decoder_metrics",
+ &atsc_viterbi_decoder::decoder_metrics,
+ pmt::make_f32vector(1,0),
+ pmt::make_f32vector(1,100000),
+ pmt::make_f32vector(1,0),
+ "", "Viterbi decoder metrics", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+#endif /* GR_CTRLPORT */
+ }
+
} /* namespace dtv */
} /* namespace gr */
diff --git a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h
index b4fbbd1033..ef4faab313 100644
--- a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h
+++ b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h
@@ -63,8 +63,12 @@ namespace gr {
atsc_viterbi_decoder_impl();
~atsc_viterbi_decoder_impl();
+ void setup_rpc();
+
void reset();
+ std::vector<float> decoder_metrics() const;
+
virtual int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
diff --git a/gr-uhd/include/gnuradio/uhd/usrp_source.h b/gr-uhd/include/gnuradio/uhd/usrp_source.h
index 19b3feb61f..19201c031c 100644
--- a/gr-uhd/include/gnuradio/uhd/usrp_source.h
+++ b/gr-uhd/include/gnuradio/uhd/usrp_source.h
@@ -96,10 +96,13 @@ namespace gr {
/*!
* \param device_addr the address to identify the hardware
* \param stream_args the IO format and channel specification
+ * \param issue_stream_cmd_on_start enable or disable continuous streaming when flowgraph
+ * starts (default true)
* \return a new USRP source block object
*/
static sptr make(const ::uhd::device_addr_t &device_addr,
- const ::uhd::stream_args_t &stream_args);
+ const ::uhd::stream_args_t &stream_args,
+ const bool issue_stream_cmd_on_start = true);
/*!
* Set the start time for incoming samples.
diff --git a/gr-uhd/lib/usrp_sink_impl.cc b/gr-uhd/lib/usrp_sink_impl.cc
index 53050051f9..e2e4d334b6 100644
--- a/gr-uhd/lib/usrp_sink_impl.cc
+++ b/gr-uhd/lib/usrp_sink_impl.cc
@@ -321,7 +321,8 @@ namespace gr {
{
_update_stream_args(stream_args);
#ifdef GR_UHD_USE_STREAM_API
- _tx_stream.reset();
+ if(_tx_stream)
+ _tx_stream.reset();
#else
throw std::runtime_error("not implemented in this version");
#endif
@@ -609,7 +610,8 @@ namespace gr {
_nitems_to_send = 0;
#ifdef GR_UHD_USE_STREAM_API
- _tx_stream->send(gr_vector_const_void_star(_nchan), 0, _metadata, 1.0);
+ if(_tx_stream)
+ _tx_stream->send(gr_vector_const_void_star(_nchan), 0, _metadata, 1.0);
#else
_dev->get_device()->send
(gr_vector_const_void_star(_nchan), 0, _metadata,
diff --git a/gr-uhd/lib/usrp_source_impl.cc b/gr-uhd/lib/usrp_source_impl.cc
index fbeb992192..7ce8633597 100644
--- a/gr-uhd/lib/usrp_source_impl.cc
+++ b/gr-uhd/lib/usrp_source_impl.cc
@@ -53,20 +53,23 @@ namespace gr {
usrp_source::sptr
usrp_source::make(const ::uhd::device_addr_t &device_addr,
- const ::uhd::stream_args_t &stream_args)
+ const ::uhd::stream_args_t &stream_args,
+ const bool issue_stream_cmd_on_start)
{
check_abi();
return usrp_source::sptr
- (new usrp_source_impl(device_addr, stream_args_ensure(stream_args)));
+ (new usrp_source_impl(device_addr, stream_args_ensure(stream_args), issue_stream_cmd_on_start));
}
usrp_source_impl::usrp_source_impl(const ::uhd::device_addr_t &device_addr,
- const ::uhd::stream_args_t &stream_args):
+ const ::uhd::stream_args_t &stream_args,
+ const bool issue_stream_cmd_on_start):
usrp_block("usrp_source",
io_signature::make(0, 0, 0),
args_to_io_sig(stream_args)),
usrp_block_impl(device_addr, stream_args, ""),
- _tag_now(false)
+ _tag_now(false),
+ _issue_stream_cmd_on_start(issue_stream_cmd_on_start)
{
std::stringstream str;
str << name() << unique_id();
@@ -348,7 +351,8 @@ namespace gr {
{
_update_stream_args(stream_args);
#ifdef GR_UHD_USE_STREAM_API
- _rx_stream.reset();
+ if(_rx_stream)
+ _rx_stream.reset();
#else
throw std::runtime_error("not implemented in this version");
#endif
@@ -381,18 +385,20 @@ namespace gr {
_samps_per_packet = _rx_stream->get_max_num_samps();
}
#endif
- //setup a stream command that starts streaming slightly in the future
- static const double reasonable_delay = 0.1; //order of magnitude over RTT
- ::uhd::stream_cmd_t stream_cmd(::uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
- stream_cmd.stream_now = _stream_now;
- if(_start_time_set) {
- _start_time_set = false; //cleared for next run
- stream_cmd.time_spec = _start_time;
- }
- else {
- stream_cmd.time_spec = get_time_now() + ::uhd::time_spec_t(reasonable_delay);
+ if(_issue_stream_cmd_on_start){
+ //setup a stream command that starts streaming slightly in the future
+ static const double reasonable_delay = 0.1; //order of magnitude over RTT
+ ::uhd::stream_cmd_t stream_cmd(::uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ stream_cmd.stream_now = _stream_now;
+ if(_start_time_set) {
+ _start_time_set = false; //cleared for next run
+ stream_cmd.time_spec = _start_time;
+ }
+ else {
+ stream_cmd.time_spec = get_time_now() + ::uhd::time_spec_t(reasonable_delay);
+ }
+ this->issue_stream_cmd(stream_cmd);
}
- this->issue_stream_cmd(stream_cmd);
_tag_now = true;
return true;
}
@@ -409,7 +415,12 @@ namespace gr {
while(true) {
#ifdef GR_UHD_USE_STREAM_API
const size_t bpi = ::uhd::convert::get_bytes_per_item(_stream_args.cpu_format);
- _rx_stream->recv(outputs, nbytes/bpi, _metadata, 0.0);
+ if(_rx_stream)
+ // get the remaining samples out of the buffers
+ _rx_stream->recv(outputs, nbytes/bpi, _metadata, 0.0);
+ else
+ // no rx streamer -- nothing to flush
+ break;
#else
_dev->get_device()->recv
(outputs, nbytes/_type->size, _metadata, *_type,
diff --git a/gr-uhd/lib/usrp_source_impl.h b/gr-uhd/lib/usrp_source_impl.h
index 98af816c02..b43df4dab3 100644
--- a/gr-uhd/lib/usrp_source_impl.h
+++ b/gr-uhd/lib/usrp_source_impl.h
@@ -55,7 +55,8 @@ namespace gr {
{
public:
usrp_source_impl(const ::uhd::device_addr_t &device_addr,
- const ::uhd::stream_args_t &stream_args);
+ const ::uhd::stream_args_t &stream_args,
+ const bool issue_stream_cmd_on_start = true);
~usrp_source_impl();
// Get Commands
@@ -119,6 +120,7 @@ namespace gr {
bool _tag_now;
::uhd::rx_metadata_t _metadata;
pmt::pmt_t _id;
+ bool _issue_stream_cmd_on_start;
//tag shadows
double _samp_rate;