subsample.hh
#ifndef __SDR_SUBSAMPLE_HH__
#define __SDR_SUBSAMPLE_HH__
#include "node.hh"
#include "buffer.hh"
#include "traits.hh"
#include "interpolate.hh"
#include "logger.hh"
namespace sdr {
template <class Scalar>
class SubSample: public Sink<Scalar>, public Source
{
public:
typedef typename Traits<Scalar>::SScalar SScalar;
public:
SubSample(size_t n)
: Sink<Scalar>(), Source(),
_n(n), _oFs(0), _last(0), _left(0), _buffer()
{
// pass...
}
SubSample(double Fs)
: Sink<Scalar>(), Source(),
_n(1), _oFs(Fs), _last(0), _left(0), _buffer()
{
// pass...
}
virtual void config(const Config &src_cfg) {
// Requires type and buffer size
if (!src_cfg.hasType() || !src_cfg.hasBufferSize()) { return; }
// check buffer type
if (Config::typeId<Scalar>() != src_cfg.type()) {
ConfigError err;
err << "Can not configure SubSample node: Invalid buffer type " << src_cfg.type()
<< ", expected " << Config::typeId<Scalar>();
throw err;
}
// If target sample rate is specified, determine _n by _oFs
if (_oFs > 0) {
_n = std::max(1.0, src_cfg.sampleRate()/_oFs);
}
// Determine buffer size
size_t out_size = src_cfg.bufferSize()/_n;
if (src_cfg.bufferSize() % _n) { out_size += 1; }
LogMessage msg(LOG_DEBUG);
msg << "Configure SubSample node:" << std::endl
<< " by: " << _n << std::endl
<< " type: " << src_cfg.type() << std::endl
<< " sample-rate: " << src_cfg.sampleRate()
<< " -> " << src_cfg.sampleRate()/_n << std::endl
<< " buffer-size: " << src_cfg.bufferSize()
<< " -> " << out_size;
Logger::get().log(msg);
// Resize buffer
_buffer = Buffer<Scalar>(out_size);
// Propergate config
this->setConfig(Config(src_cfg.type(), src_cfg.sampleRate()/_n, out_size, 1));
}
virtual void process(const Buffer<Scalar> &buffer, bool allow_overwrite) {
if (allow_overwrite) {
_process(buffer, buffer);
} else if (_buffer.isUnused()) {
_process(buffer, _buffer);
} else {
#ifdef SDR_DEBUG
LogMessage msg(LOG_WARNING);
msg << "SubSample: Drop buffer, output buffer still in use.";
Logger::get().log(msg);
#endif
}
}
protected:
void _process(const Buffer<Scalar> &in, const Buffer<Scalar> &out) {
size_t j=0;
for (size_t i=0; i<in.size(); i++) {
_last += in[i]; _left++;
if (_n <= _left) {
out[j] = _last/SScalar(_n); j++; _last=0; _left=0;
}
}
this->send(out.head(j), true);
}
protected:
size_t _n;
double _oFs;
SScalar _last;
size_t _left;
Buffer<Scalar> _buffer;
};
template <class Scalar>
class FracSubSampleBase
{
public:
typedef typename Traits<Scalar>::SScalar SScalar;
public:
FracSubSampleBase(double frac)
: _avg(0), _sample_count(0), _period(0) {
if (frac < 1) {
ConfigError err;
err << "FracSubSampleBase: Can not sub-sample with fraction smaller one: " << frac;
throw err;
}
_period = (frac*(1<<16));
}
virtual ~FracSubSampleBase() {
// pass...
}
inline void setFrac(double frac) {
if (frac < 1) {
ConfigError err;
err << "FracSubSampleBase: Can not sub-sample with fraction smaller one: " << frac;
throw err;
}
_period = (frac*(1<<16)); _sample_count=0; _avg = 0;
}
inline double frac() const {
return double(_period)/(1<<16);
}
inline void reset() {
_avg=0; _sample_count=0;
}
inline Buffer<Scalar> subsample(const Buffer<Scalar> &in, const Buffer<Scalar> &out) {
size_t oidx = 0;
for (size_t i=0; i<in.size(); i++) {
_avg += in[i]; _sample_count += (1<<16);
if (_sample_count >= _period) {
out[oidx] = _avg/SScalar(_sample_count/(1<<16));
_sample_count=0; _avg = 0; oidx++;
}
}
return out.head(oidx);
}
protected:
SScalar _avg;
size_t _sample_count;
size_t _period;
};
template <class iScalar, class oScalar = iScalar>
class InpolSubSampler: public Sink<iScalar>, public Source
{
public:
InpolSubSampler(float frac)
: Sink<iScalar>(), Source(), _frac(frac), _mu(0)
{
if (_frac <= 0) {
ConfigError err;
err << "Can not configure InpolSubSample node: Sample rate fraction must be > 0!"
<< " Fraction given: " << _frac;
throw err;
}
}
virtual ~InpolSubSampler() {
// pass...
}
virtual void config(const Config &src_cfg) {
// Requires type and buffer size
if (!src_cfg.hasType() || !src_cfg.hasBufferSize()) { return; }
// check buffer type
if (Config::typeId<iScalar>() != src_cfg.type()) {
ConfigError err;
err << "Can not configure InpolSubSample node: Invalid buffer type " << src_cfg.type()
<< ", expected " << Config::typeId<iScalar>();
throw err;
}
// Allocate buffer
size_t bufSize = std::ceil(src_cfg.bufferSize() * src_cfg.sampleRate()/_frac);
_buffer = Buffer<oScalar>(bufSize);
// Allocate & init delay line
_dl = Buffer<oScalar>(16); _dl_idx = 0;
for (size_t i=0; i<16; i++) { _dl[i] = 0; }
_mu = 0;
LogMessage msg(LOG_DEBUG);
msg << "Configure InpolSubSampler node:" << std::endl
<< " by: " << _frac << std::endl
<< " type: " << src_cfg.type() << std::endl
<< " sample-rate: " << src_cfg.sampleRate()
<< " -> " << src_cfg.sampleRate()/_frac;
Logger::get().log(msg);
// Propergate config
this->setConfig(Config(Traits<oScalar>::scalarId, src_cfg.sampleRate()/_frac, bufSize, 1));
}
virtual void process(const Buffer<iScalar> &buffer, bool allow_overwrite)
{
// Short cut
if (1 == _frac) {
this->send(buffer, allow_overwrite);
return;
}
size_t i=0, o=0;
while (i<buffer.size()) {
// First, fill sampler...
while ( (_mu >= 1) && (i<buffer.size()) ) {
_dl[_dl_idx] = _dl[_dl_idx+8] = buffer[i]; i++;
_dl_idx = (_dl_idx + 1) % 8; _mu -= 1;
}
while (_mu <= 1) {
// Interpolate
_buffer[o] = interpolate(_dl.sub(_dl_idx,8), _mu);
_mu += _frac; o++;
}
}
this->send(_buffer.head(o));
}
protected:
float _frac;
float _mu;
Buffer<oScalar> _dl;
size_t _dl_idx;
Buffer<oScalar> _buffer;
};
}
#endif // __SDR_SUBSAMPLE_HH__
sdr::Config
A collection of configuration information that is send by a source to all connected sinks to properga...
Definition: node.hh:35
sdr::InpolSubSampler::_dl
Buffer< oScalar > _dl
A delay-line (buffer) for the interpolation.
Definition: subsample.hh:283
sdr::FracSubSampleBase::_sample_count
size_t _sample_count
The number of samples collected times (1<<16).
Definition: subsample.hh:183
sdr::FracSubSampleBase::setFrac
void setFrac(double frac)
Resets the sample rate fraction.
Definition: subsample.hh:146
sdr::SubSample::_n
size_t _n
The sub-sampling, n=1 means no sub-sampling at all.
Definition: subsample.hh:106
sdr::InpolSubSampler::_buffer
Buffer< oScalar > _buffer
The output buffer.
Definition: subsample.hh:287
sdr::Source::send
virtual void send(const RawBuffer &buffer, bool allow_overwrite=false)
Sends the given buffer to all connected sinks.
Definition: node.cc:67
sdr::FracSubSampleBase::~FracSubSampleBase
virtual ~FracSubSampleBase()
Destructor.
Definition: subsample.hh:141
sdr::Sink
Typed sink.
Definition: node.hh:192
sdr
Definition: autocast.hh:8
sdr::InpolSubSampler::InpolSubSampler
InpolSubSampler(float frac)
Constructor.
Definition: subsample.hh:201
sdr::InpolSubSampler::_dl_idx
size_t _dl_idx
Index of the delay-line.
Definition: subsample.hh:285
sdr::InpolSubSampler::_mu
float _mu
The current (fractional) sample count.
Definition: subsample.hh:281
sdr::Source
Generic source class.
Definition: node.hh:213
sdr::InpolSubSampler::process
virtual void process(const Buffer< iScalar > &buffer, bool allow_overwrite)
Performs the sub-sampling.
Definition: subsample.hh:252
sdr::SubSample::_oFs
double _oFs
Target sample rate.
Definition: subsample.hh:108
sdr::InpolSubSampler::_frac
float _frac
The sub-sampling fraction.
Definition: subsample.hh:279
sdr::Buffer::size
size_t size() const
Returns the number of elements of type T in this buffer.
Definition: buffer.hh:166
sdr::Config::hasType
bool hasType() const
If true, the configuration has a type.
Definition: node.hh:69
sdr::FracSubSampleBase::frac
double frac() const
Returns the effective sub-sample fraction.
Definition: subsample.hh:156
sdr::FracSubSampleBase::reset
void reset()
Reset sample counter.
Definition: subsample.hh:161
sdr::Source::setConfig
virtual void setConfig(const Config &config)
Stores the configuration and propergates it if the configuration has been changed.
Definition: node.cc:98
sdr::SubSample::SubSample
SubSample(size_t n)
Constructs a sub-sampler.
Definition: subsample.hh:24
sdr::Buffer::head
Buffer< T > head(size_t n) const
Returns a new view on this buffer.
Definition: buffer.hh:237
sdr::Logger::log
void log(const LogMessage &message)
Logs a message.
Definition: logger.cc:100
sdr::SubSample::_process
void _process(const Buffer< Scalar > &in, const Buffer< Scalar > &out)
Performs the sub-sampling from in into out.
Definition: subsample.hh:92
sdr::SubSample::_buffer
Buffer< Scalar > _buffer
The output buffer, unused if the sub-sampling is performed in-place.
Definition: subsample.hh:114
sdr::Config::type
Type type() const
Returns the type.
Definition: node.hh:71
sdr::FracSubSampleBase::SScalar
Traits< Scalar >::SScalar SScalar
The input & output type super-scalar.
Definition: subsample.hh:124
sdr::SubSample::process
virtual void process(const Buffer< Scalar > &buffer, bool allow_overwrite)
Performs the sub-sampling on the given buffer.
Definition: subsample.hh:76
sdr::Logger::get
static Logger & get()
Returns the singleton instance of the logger.
Definition: logger.cc:89
sdr::Buffer::sub
Buffer< T > sub(size_t offset, size_t len) const
Returns a new view on this buffer.
Definition: buffer.hh:231
sdr::SubSample::config
virtual void config(const Config &src_cfg)
Configures the sub-sampler.
Definition: subsample.hh:40
sdr::InpolSubSampler::config
virtual void config(const Config &src_cfg)
Configures the sub-sampling node.
Definition: subsample.hh:218
sdr::ConfigError
The configuration error class.
Definition: exception.hh:24
sdr::LogMessage
A log message.
Definition: logger.hh:22
sdr::Config::bufferSize
size_t bufferSize() const
Returns the max.
Definition: node.hh:83
sdr::FracSubSampleBase::_avg
SScalar _avg
The average.
Definition: subsample.hh:181
sdr::FracSubSampleBase
Implements a fractional sub-sampler.
Definition: subsample.hh:120
sdr::SubSample::SubSample
SubSample(double Fs)
Constructs a sub-sampler by target sample rate.
Definition: subsample.hh:32
sdr::SubSample::_left
size_t _left
How many samples are left.
Definition: subsample.hh:112
sdr::FracSubSampleBase::FracSubSampleBase
FracSubSampleBase(double frac)
Constructor.
Definition: subsample.hh:130
sdr::SubSample::SScalar
Traits< Scalar >::SScalar SScalar
The super-scalar of the input type.
Definition: subsample.hh:20
sdr::RawBuffer::isUnused
bool isUnused() const
We assume here that buffers are owned by one object: A buffer is therefore "unused" if the owner hold...
Definition: buffer.hh:87
sdr::Traits
Forward declaration of type tratis template.
Definition: traits.hh:20
sdr::FracSubSampleBase::subsample
Buffer< Scalar > subsample(const Buffer< Scalar > &in, const Buffer< Scalar > &out)
Performs the sub-sampling.
Definition: subsample.hh:167
sdr::FracSubSampleBase::_period
size_t _period
The sub-sample period.
Definition: subsample.hh:185
sdr::SubSample::_last
SScalar _last
The last value.
Definition: subsample.hh:110
sdr::Buffer< Scalar >
sdr::InpolSubSampler::~InpolSubSampler
virtual ~InpolSubSampler()
Destructor.
Definition: subsample.hh:213
sdr::InpolSubSampler
An interpolating sub-sampler.
Definition: subsample.hh:195
sdr::Config::hasBufferSize
bool hasBufferSize() const
If true, the configuration has a buffer size.
Definition: node.hh:81
sdr::SubSample
Simple averaging sub-sampler.
Definition: subsample.hh:16
sdr::Config::sampleRate
double sampleRate() const
Returns the sample rate.
Definition: node.hh:77