demod.hh
#ifndef __SDR_DEMOD_HH__
#define __SDR_DEMOD_HH__
#include "node.hh"
#include "traits.hh"
#include "config.hh"
#include "combine.hh"
#include "logger.hh"
#include "math.hh"
namespace sdr {
template <class Scalar>
class AMDemod
: public Sink< std::complex<Scalar> >, public Source
{
public:
AMDemod() : Sink< std::complex<Scalar> >(), Source()
{
// pass...
}
virtual ~AMDemod() {
// free buffers
_buffer.unref();
}
virtual void config(const Config &src_cfg) {
// Requires type & buffer size
if (!src_cfg.hasType() || !src_cfg.hasBufferSize()) { return; }
// Check if buffer type matches template
if (Config::typeId< std::complex<Scalar> >() != src_cfg.type()) {
ConfigError err;
err << "Can not configure AMDemod: Invalid type " << src_cfg.type()
<< ", expected " << Config::typeId< std::complex<Scalar> >();
throw err;
}
// Unreference previous buffer
_buffer.unref();
// Allocate buffer
_buffer = Buffer<Scalar>(src_cfg.bufferSize());
LogMessage msg(LOG_DEBUG);
msg << "Configure AMDemod: " << this << std::endl
<< " input type: " << Traits< std::complex<Scalar> >::scalarId << std::endl
<< " output type: " << Traits<Scalar>::scalarId << std::endl
<< " sample rate: " << src_cfg.sampleRate() << std::endl
<< " buffer size: " << src_cfg.bufferSize();
Logger::get().log(msg);
// Propergate config
this->setConfig(Config(Config::typeId<Scalar>(), src_cfg.sampleRate(),
src_cfg.bufferSize(), src_cfg.numBuffers()));
}
virtual void process(const Buffer<std::complex<Scalar> > &buffer, bool allow_overwrite)
{
Buffer<Scalar> out_buffer;
// If source allow to overwrite the buffer, use it otherwise rely on own buffer
if (allow_overwrite) { out_buffer = Buffer<Scalar>(buffer); }
else { out_buffer = _buffer; }
// Perform demodulation
for (size_t i=0; i<buffer.size(); i++) {
out_buffer[i] = std::sqrt(buffer[i].real()*buffer[i].real() +
buffer[i].imag()*buffer[i].imag());
}
// If the source allowed to overwrite the buffer, this source will allow it too.
// If this source used the internal buffer (_buffer), it allows to overwrite it anyway.
this->send(out_buffer.head(buffer.size()), true);
}
protected:
Buffer<Scalar> _buffer;
};
template <class Scalar>
class USBDemod
: public Sink< std::complex<Scalar> >, public Source
{
public:
typedef std::complex<Scalar> CScalar;
typedef typename Traits<Scalar>::SScalar SScalar;
public:
USBDemod() : Sink<CScalar>(), Source()
{
// pass...
}
virtual ~USBDemod() {
_buffer.unref();
}
virtual void config(const Config &src_cfg) {
// Requires type & buffer size
if (!src_cfg.hasType() || !src_cfg.hasBufferSize()) { return; }
// Check if buffer type matches template
if (Config::typeId<CScalar>() != src_cfg.type()) {
ConfigError err;
err << "Can not configure USBDemod: Invalid type " << src_cfg.type()
<< ", expected " << Config::typeId<CScalar>();
throw err;
}
// Unreference previous buffer
_buffer.unref();
// Allocate buffer
_buffer = Buffer<Scalar>(src_cfg.bufferSize());
LogMessage msg(LOG_DEBUG);
msg << "Configure USBDemod: " << this << std::endl
<< " input type: " << Traits< std::complex<Scalar> >::scalarId << std::endl
<< " output type: " << Traits<Scalar>::scalarId << std::endl
<< " sample rate: " << src_cfg.sampleRate() << std::endl
<< " buffer size: " << src_cfg.bufferSize();
Logger::get().log(msg);
// Propergate config
this->setConfig(Config(Config::typeId<Scalar>(), src_cfg.sampleRate(),
src_cfg.bufferSize(), 1));
}
virtual void process(const Buffer<CScalar> &buffer, bool allow_overwrite) {
if (allow_overwrite) {
// Process in-place
_process(buffer, Buffer<Scalar>(buffer));
} else {
// Store result in buffer
_process(buffer, _buffer);
}
}
protected:
void _process(const Buffer< std::complex<Scalar> > &in, const Buffer< Scalar> &out) {
for (size_t i=0; i<in.size(); i++) {
out[i] = (SScalar(std::real(in[i])) + SScalar(std::imag(in[i])))/2;
}
this->send(out.head(in.size()));
}
protected:
Buffer<Scalar> _buffer;
};
template <class iScalar, class oScalar=iScalar>
class FMDemod: public Sink< std::complex<iScalar> >, public Source
{
public:
typedef typename Traits<iScalar>::SScalar SScalar;
public:
FMDemod():
Sink< std::complex<iScalar> >(), Source(), _shift(0), _can_overwrite(false)
{
_shift = 8*(sizeof(oScalar)-sizeof(iScalar));
}
virtual ~FMDemod() {
_buffer.unref();
}
virtual void config(const Config &src_cfg) {
// Requires type & buffer size
if (!src_cfg.hasType() || !src_cfg.hasBufferSize()) { return; }
// Check if buffer type matches template
if (Config::typeId< std::complex<iScalar> >() != src_cfg.type()) {
ConfigError err;
err << "Can not configure FMDemod: Invalid type " << src_cfg.type()
<< ", expected " << Config::typeId< std::complex<iScalar> >();
throw err;
}
// Unreference buffer if non-empty
if (! _buffer.isEmpty()) { _buffer.unref(); }
// Allocate buffer
_buffer = Buffer<oScalar>(src_cfg.bufferSize());
// reset last value
_last_value = 0;
// Check if FM demod can be performed in-place
_can_overwrite = (sizeof(std::complex<iScalar>) >= sizeof(oScalar));
LogMessage msg(LOG_DEBUG);
msg << "Configured FMDemod node: " << this << std::endl
<< " sample-rate: " << src_cfg.sampleRate() << std::endl
<< " in-type / out-type: " << src_cfg.type()
<< " / " << Config::typeId<oScalar>() << std::endl
<< " in-place: " << (_can_overwrite ? "true" : "false") << std::endl
<< " output scale: 2^" << _shift;
Logger::get().log(msg);
// Propergate config
this->setConfig(Config(Config::typeId<oScalar>(), src_cfg.sampleRate(),
src_cfg.bufferSize(), 1));
}
virtual void process(const Buffer<std::complex<iScalar> > &buffer, bool allow_overwrite)
{
if (0 == buffer.size()) { return; }
if (allow_overwrite && _can_overwrite) {
_process(buffer, Buffer<oScalar>(buffer));
} else {
_process(buffer, _buffer);
}
}
protected:
void _process(const Buffer< std::complex<iScalar> > &in, const Buffer<oScalar> &out)
{
// The last input value
std::complex<iScalar> last_value = _last_value;
// calc first value
SScalar a = (SScalar(in[0].real())*SScalar(last_value.real()))/2
+ (SScalar(in[0].imag())*SScalar(last_value.imag()))/2;
SScalar b = (SScalar(in[0].imag())*SScalar(last_value.real()))/2
- (SScalar(in[0].real())*SScalar(last_value.imag()))/2;
a >>= Traits<iScalar>::shift; b >>= Traits<iScalar>::shift;
// update last value
last_value = in[0];
// calc output (prob. overwriting the last value)
out[0] = fast_atan2<iScalar, oScalar>(a, b);
//out[0] = (1<<12)*(std::atan2(float(a),float(b))/M_PI);
// Calc remaining values
for (size_t i=1; i<in.size(); i++) {
a = (SScalar(in[i].real())*SScalar(last_value.real()))/2
+ (SScalar(in[i].imag())*SScalar(last_value.imag()))/2;
b = (SScalar(in[i].imag())*SScalar(last_value.real()))/2
- (SScalar(in[i].real())*SScalar(last_value.imag()))/2;
a >>= Traits<iScalar>::shift; b >>= Traits<iScalar>::shift;
last_value = in[i];
out[i] = fast_atan2<iScalar,oScalar>(a, b);
//out[i] = (1<<12)*(std::atan2(float(a),float(b))/M_PI);
}
// Store last value
_last_value = last_value;
// propergate result
this->send(out.head(in.size()));
}
protected:
int _shift;
std::complex<iScalar> _last_value;
bool _can_overwrite;
Buffer<oScalar> _buffer;
};
template <class Scalar>
class FMDeemph: public Sink<Scalar>, public Source
{
public:
FMDeemph(bool enabled=true)
: Sink<Scalar>(), Source(), _enabled(enabled), _alpha(0), _avg(0), _buffer(0)
{
// pass...
}
virtual ~FMDeemph() {
_buffer.unref();
}
inline bool isEnabled() const { return _enabled; }
inline void enable(bool enabled) { _enabled = enabled; }
virtual void config(const Config &src_cfg) {
// Requires type, sample rate & buffer size
if (!src_cfg.hasType() || !src_cfg.hasSampleRate() || !src_cfg.hasBufferSize()) { return; }
// Check if buffer type matches template
if (Config::typeId<Scalar>() != src_cfg.type()) {
ConfigError err;
err << "Can not configure FMDeemph: Invalid type " << src_cfg.type()
<< ", expected " << Config::typeId<Scalar>();
throw err;
}
// Determine filter constant alpha:
_alpha = (int)round(
1.0/( (1.0-exp(-1.0/(src_cfg.sampleRate() * 75e-6) )) ) );
// Reset average:
_avg = 0;
// Unreference previous buffer
_buffer.unref();
// Allocate buffer:
_buffer = Buffer<Scalar>(src_cfg.bufferSize());
LogMessage msg(LOG_DEBUG);
msg << "Configured FMDDeemph node: " << this << std::endl
<< " sample-rate: " << src_cfg.sampleRate() << std::endl
<< " type: " << src_cfg.type();
Logger::get().log(msg);
// Propergate config:
this->setConfig(Config(src_cfg.type(), src_cfg.sampleRate(), src_cfg.bufferSize(), 1));
}
virtual void process(const Buffer<Scalar> &buffer, bool allow_overwrite)
{
// Skip if disabled:
if (!_enabled) { this->send(buffer, allow_overwrite); return; }
// Process in-place or not
if (allow_overwrite) {
_process(buffer, buffer);
this->send(buffer, allow_overwrite);
} else {
_process(buffer, _buffer);
this->send(_buffer.head(buffer.size()), false);
}
}
protected:
void _process(const Buffer<Scalar> &in, const Buffer<Scalar> &out) {
for (size_t i=0; i<in.size(); i++) {
// Update average:
Scalar diff = in[i] - _avg;
if (diff > 0) { _avg += (diff + _alpha/2) / _alpha; }
else { _avg += (diff - _alpha/2) / _alpha; }
// Store result
out[i] = _avg;
}
}
protected:
bool _enabled;
int _alpha;
Scalar _avg;
Buffer<Scalar> _buffer;
};
}
#endif // __SDR_DEMOD_HH__
sdr::FMDeemph::isEnabled
bool isEnabled() const
Returns true if the filter node is enabled.
Definition: demod.hh:308
sdr::Config
A collection of configuration information that is send by a source to all connected sinks to properga...
Definition: node.hh:35
sdr::USBDemod::config
virtual void config(const Config &src_cfg)
Configures the USB demodulator.
Definition: demod.hh:114
sdr::USBDemod::CScalar
std::complex< Scalar > CScalar
The complex input scalar.
Definition: demod.hh:97
sdr::FMDemod::~FMDemod
virtual ~FMDemod()
Destructor.
Definition: demod.hh:190
sdr::USBDemod::~USBDemod
virtual ~USBDemod()
Destructor.
Definition: demod.hh:109
sdr::FMDeemph::_process
void _process(const Buffer< Scalar > &in, const Buffer< Scalar > &out)
Performs the actual filtering.
Definition: demod.hh:362
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::FMDemod::SScalar
Traits< iScalar >::SScalar SScalar
The super scalar.
Definition: demod.hh:179
sdr::FMDemod::config
virtual void config(const Config &src_cfg)
Configures the FM demodulator.
Definition: demod.hh:195
sdr::Sink
Typed sink.
Definition: node.hh:192
sdr
Definition: autocast.hh:8
sdr::Config::numBuffers
size_t numBuffers() const
Returns the max.
Definition: node.hh:89
sdr::FMDeemph
A tiny node to de-emphasize the higher frequencies of a FM transmitted audio signal.
Definition: demod.hh:292
sdr::RawBuffer::isEmpty
bool isEmpty() const
Returns true if the buffer is invalid/empty.
Definition: buffer.hh:77
std
Definition: operators.hh:9
sdr::USBDemod::_buffer
Buffer< Scalar > _buffer
The output buffer.
Definition: demod.hh:165
sdr::Config::hasSampleRate
bool hasSampleRate() const
If true, the configuration has a sample rate.
Definition: node.hh:75
sdr::FMDeemph::~FMDeemph
virtual ~FMDeemph()
Destructor.
Definition: demod.hh:303
sdr::Source
Generic source class.
Definition: node.hh:213
sdr::FMDemod::_shift
int _shift
Output rescaling.
Definition: demod.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::FMDeemph::_enabled
bool _enabled
If true, the filter is enabled.
Definition: demod.hh:375
sdr::FMDeemph::config
virtual void config(const Config &src_cfg)
Configures the node.
Definition: demod.hh:314
sdr::FMDeemph::_alpha
int _alpha
Filter constant.
Definition: demod.hh:377
sdr::USBDemod::process
virtual void process(const Buffer< CScalar > &buffer, bool allow_overwrite)
Performs the demodulation.
Definition: demod.hh:144
sdr::FMDeemph::process
virtual void process(const Buffer< Scalar > &buffer, bool allow_overwrite)
Dispatches in- or out-of-place filtering.
Definition: demod.hh:345
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::AMDemod
Amplitude modulation (AM) demodulator from an I/Q signal.
Definition: demod.hh:18
sdr::AMDemod::~AMDemod
virtual ~AMDemod()
Destructor.
Definition: demod.hh:29
sdr::FMDeemph::_buffer
Buffer< Scalar > _buffer
The output buffer.
Definition: demod.hh:381
sdr::FMDemod
Demodulates FM from an I/Q signal.
Definition: demod.hh:175
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::FMDemod::FMDemod
FMDemod()
Constructor.
Definition: demod.hh:183
sdr::FMDemod::_buffer
Buffer< oScalar > _buffer
The output buffer, unused if demodulation is performed in-place.
Definition: demod.hh:285
sdr::FMDemod::_can_overwrite
bool _can_overwrite
If true, in-place demodulation is poissible.
Definition: demod.hh:283
sdr::Config::type
Type type() const
Returns the type.
Definition: node.hh:71
sdr::Config::typeId
static Type typeId()
Returns the type-id of the template type.
sdr::AMDemod::process
virtual void process(const Buffer< std::complex< Scalar > > &buffer, bool allow_overwrite)
Handles the I/Q input buffer.
Definition: demod.hh:65
sdr::Logger::get
static Logger & get()
Returns the singleton instance of the logger.
Definition: logger.cc:89
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::USBDemod::USBDemod
USBDemod()
Constructor.
Definition: demod.hh:103
sdr::FMDemod::process
virtual void process(const Buffer< std::complex< iScalar > > &buffer, bool allow_overwrite)
Performs the FM demodulation.
Definition: demod.hh:229
sdr::FMDemod::_process
void _process(const Buffer< std::complex< iScalar > > &in, const Buffer< oScalar > &out)
The actual demodulation.
Definition: demod.hh:242
sdr::RawBuffer::unref
void unref()
Dereferences the buffer.
Definition: buffer.cc:63
sdr::FMDeemph::FMDeemph
FMDeemph(bool enabled=true)
Constructor.
Definition: demod.hh:296
sdr::FMDeemph::enable
void enable(bool enabled)
Enable/Disable the filter node.
Definition: demod.hh:311
sdr::AMDemod::_buffer
Buffer< Scalar > _buffer
The output buffer.
Definition: demod.hh:85
sdr::USBDemod
SSB upper side band (USB) demodulator from an I/Q signal.
Definition: demod.hh:92
sdr::Traits
Forward declaration of type tratis template.
Definition: traits.hh:20
sdr::AMDemod::config
virtual void config(const Config &src_cfg)
Configures the AM demod.
Definition: demod.hh:35
sdr::USBDemod::_process
void _process(const Buffer< std::complex< Scalar > > &in, const Buffer< Scalar > &out)
The actual demodulation.
Definition: demod.hh:156
sdr::AMDemod::AMDemod
AMDemod()
Constructor.
Definition: demod.hh:23
sdr::Buffer< Scalar >
sdr::USBDemod::SScalar
Traits< Scalar >::SScalar SScalar
The real compute scalar.
Definition: demod.hh:99
sdr::Config::hasBufferSize
bool hasBufferSize() const
If true, the configuration has a buffer size.
Definition: node.hh:81
sdr::Config::sampleRate
double sampleRate() const
Returns the sample rate.
Definition: node.hh:77
sdr::FMDemod::_last_value
std::complex< iScalar > _last_value
The last input value.
Definition: demod.hh:281
sdr::FMDeemph::_avg
Scalar _avg
Current averaged value.
Definition: demod.hh:379