I'd like to code my own sink block with 1 input port and 0 output ports for GNU Radio in C++. I read and followed the steps described here:
I'm using
Using gr_modtool I created the new module "jammertrap". Inside it, I created the block "bandpower". This created among others the three files
bandpower.h:
#ifndef INCLUDED_JAMMERTRAP_BANDPOWER_H
#define INCLUDED_JAMMERTRAP_BANDPOWER_H
#include <jammertrap/api.h>
#include <gnuradio/block.h>
namespace gr
{
namespace jammertrap
{
class JAMMERTRAP_API bandpower : virtual public gr::block
{
public:
typedef boost::shared_ptr<bandpower> sptr;
// Return a shared_ptr to a new instance of jammertrap::bandpower.
// To avoid accidental use of raw pointers, jammertrap::bandpower's constructor is in a private implementation class.
// jammertrap::bandpower::make is the public interface for creating new instances.
static sptr make();
};
} // namespace jammertrap
} // namespace gr
#endif /* INCLUDED_JAMMERTRAP_BANDPOWER_H */
bandpower_impl.h:
#ifndef INCLUDED_JAMMERTRAP_BANDPOWER_IMPL_H
#define INCLUDED_JAMMERTRAP_BANDPOWER_IMPL_H
#include <jammertrap/bandpower.h>
namespace gr
{
namespace jammertrap
{
class bandpower_impl : public bandpower
{
private:
double d_bandpower_;
public:
bandpower_impl();
~bandpower_impl();
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
// Where all the action really happens
int general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items);
// Returns the calculated RMS Bandpower
double get_bandpower();
};
} // namespace jammertrap
} // namespace gr
#endif /* INCLUDED_JAMMERTRAP_BANDPOWER_IMPL_H */
bandpower_impl.cc:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "bandpower_impl.h"
namespace gr
{
namespace jammertrap
{
bandpower::sptr
bandpower::make()
{
return gnuradio::get_initial_sptr (new bandpower_impl());
}
// The private constructor
bandpower_impl::bandpower_impl() : gr::block("bandpower", gr::io_signature::make(1, 1, sizeof(gr_complex)), gr::io_signature::make(0, 0, 0))
{
d_bandpower_ = 0;
}
// Our virtual destructor
bandpower_impl::~bandpower_impl()
{}
void bandpower_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required)
{
// ninput_items_required[0] = noutput_items;
}
int bandpower_impl::general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items)
{
const gr_complex *in = (const gr_complex *) input_items[0];
d_bandpower_ = 0;
for(int i = 0; i < noutput_items; i++)
{
d_bandpower_ += (in[i].real() * in[i].real()) + (in[i].imag() * in[i].imag());
}
d_bandpower_ = sqrt(d_bandpower_ / noutput_items);
// Tell runtime system how many input items we consumed on each input stream.
consume_each (noutput_items);
// Tell runtime system how many output items we produced
return noutput_items;
}
double bandpower_impl::get_bandpower()
{
return d_bandpower_;
}
} /* namespace jammertrap */
} /* namespace gr */
To make and install this new block, I entered the following commands inside /home/sdr/gnuradio/gr-jammertrap/build:
This sink block "bandpower" should receive items of type gr_complex, compute the average received power and store this value inside the private member "d_bandpower_". Additional I defined the method "get_bandpower()" to get the stored value.
Inside another program, I created a flowgraph class with the two blocks
osmosdr::source:sptr osmosdr_source_;
gr::jammertrap::bandpower::sptr bandpower_measurement_;
and instanced them with
osmosdr_source_ = osmosdr::source::make(std::string());
bandpower_measurement_ = gr::jammertrap::bandpower::make();
After starting the flowgraph, I want to read the calculated bandpower by calling get_bandpower() but Eclipse shows no method "bandpower_measurement_->get_bandpower()"
What have I forgotten to write inside bandpower.h, bandpower_impl.h or bandpower_impl.cc?
The public API of the normal OOT layout is in the bandpower.h
, so you must add a
virtual double get_bandpower() = 0;
in that file.
Then, you overload/implement that, like you do, in the _impl.cc
/_impl.h
.
By the way, I slightly object the math behind your implementation: as noutput_items
, ie. the number of input items available, changes depending on buffer fillage / runtime behaviour, your "averaging length" is not constant, which means that if your flow graph runs fast, your buffers will usually be full, and your averaging length high, whilst in a "trickle" situation, the length will be much smaller (down to noutput_items==1
, in extreme cases). Hence, the variance of your power estimator will depend on computational aspects.
That's not a good thing. Better work with a constant number of items you average about. In your case, you can use set_output_multiple
(because a sink is also a sync block, this also affects the input multiples) to guarantee you always get a multiple of a fixed number.
Other than that, there's already blocks that can do what you want:
level()
which does the same as your get_bandpower
(aside from the √(.) )signal()
method, which does what your get_bandpower
does. CPU load of this is relatively small -- it's really just the magnitude finding for every sample, and then 123 real multiplications + 123 real additions per 123 samples,in the filter, all SIMD increased, so basically, less than 1 FMAC per sample.