libsdr  0.1.0
A simple SDR library
subsample.hh
1 #ifndef __SDR_SUBSAMPLE_HH__
2 #define __SDR_SUBSAMPLE_HH__
3 
4 #include "node.hh"
5 #include "buffer.hh"
6 #include "traits.hh"
7 #include "interpolate.hh"
8 #include "logger.hh"
9 
10 
11 namespace sdr {
12 
15 template <class Scalar>
16 class SubSample: public Sink<Scalar>, public Source
17 {
18 public:
20  typedef typename Traits<Scalar>::SScalar SScalar;
21 
22 public:
24  SubSample(size_t n)
25  : Sink<Scalar>(), Source(),
26  _n(n), _oFs(0), _last(0), _left(0), _buffer()
27  {
28  // pass...
29  }
30 
32  SubSample(double Fs)
33  : Sink<Scalar>(), Source(),
34  _n(1), _oFs(Fs), _last(0), _left(0), _buffer()
35  {
36  // pass...
37  }
38 
40  virtual void config(const Config &src_cfg) {
41  // Requires type and buffer size
42  if (!src_cfg.hasType() || !src_cfg.hasBufferSize()) { return; }
43  // check buffer type
44  if (Config::typeId<Scalar>() != src_cfg.type()) {
45  ConfigError err;
46  err << "Can not configure SubSample node: Invalid buffer type " << src_cfg.type()
47  << ", expected " << Config::typeId<Scalar>();
48  throw err;
49  }
50 
51  // If target sample rate is specified, determine _n by _oFs
52  if (_oFs > 0) {
53  _n = std::max(1.0, src_cfg.sampleRate()/_oFs);
54  }
55  // Determine buffer size
56  size_t out_size = src_cfg.bufferSize()/_n;
57  if (src_cfg.bufferSize() % _n) { out_size += 1; }
58 
59  LogMessage msg(LOG_DEBUG);
60  msg << "Configure SubSample node:" << std::endl
61  << " by: " << _n << std::endl
62  << " type: " << src_cfg.type() << std::endl
63  << " sample-rate: " << src_cfg.sampleRate()
64  << " -> " << src_cfg.sampleRate()/_n << std::endl
65  << " buffer-size: " << src_cfg.bufferSize()
66  << " -> " << out_size;
67  Logger::get().log(msg);
68 
69  // Resize buffer
70  _buffer = Buffer<Scalar>(out_size);
71  // Propergate config
72  this->setConfig(Config(src_cfg.type(), src_cfg.sampleRate()/_n, out_size, 1));
73  }
74 
76  virtual void process(const Buffer<Scalar> &buffer, bool allow_overwrite) {
77  if (allow_overwrite) {
78  _process(buffer, buffer);
79  } else if (_buffer.isUnused()) {
80  _process(buffer, _buffer);
81  } else {
82 #ifdef SDR_DEBUG
83  LogMessage msg(LOG_WARNING);
84  msg << "SubSample: Drop buffer, output buffer still in use.";
85  Logger::get().log(msg);
86 #endif
87  }
88  }
89 
90 protected:
92  void _process(const Buffer<Scalar> &in, const Buffer<Scalar> &out) {
93  size_t j=0;
94  for (size_t i=0; i<in.size(); i++) {
95  _last += in[i]; _left++;
96  if (_n <= _left) {
97  out[j] = _last/SScalar(_n); j++; _last=0; _left=0;
98  }
99  }
100  this->send(out.head(j), true);
101  }
102 
103 
104 protected:
106  size_t _n;
108  double _oFs;
110  SScalar _last;
112  size_t _left;
115 };
116 
117 
119 template <class Scalar>
121 {
122 public:
125 
126 public:
131  : _avg(0), _sample_count(0), _period(0) {
132  if (frac < 1) {
133  ConfigError err;
134  err << "FracSubSampleBase: Can not sub-sample with fraction smaller one: " << frac;
135  throw err;
136  }
137  _period = (frac*(1<<16));
138  }
139 
141  virtual ~FracSubSampleBase() {
142  // pass...
143  }
144 
146  inline void setFrac(double frac) {
147  if (frac < 1) {
148  ConfigError err;
149  err << "FracSubSampleBase: Can not sub-sample with fraction smaller one: " << frac;
150  throw err;
151  }
152  _period = (frac*(1<<16)); _sample_count=0; _avg = 0;
153  }
154 
156  inline double frac() const {
157  return double(_period)/(1<<16);
158  }
159 
161  inline void reset() {
162  _avg=0; _sample_count=0;
163  }
164 
167  inline Buffer<Scalar> subsample(const Buffer<Scalar> &in, const Buffer<Scalar> &out) {
168  size_t oidx = 0;
169  for (size_t i=0; i<in.size(); i++) {
170  _avg += in[i]; _sample_count += (1<<16);
171  if (_sample_count >= _period) {
172  out[oidx] = _avg/SScalar(_sample_count/(1<<16));
173  _sample_count=0; _avg = 0; oidx++;
174  }
175  }
176  return out.head(oidx);
177  }
178 
179 protected:
181  SScalar _avg;
185  size_t _period;
186 };
187 
188 
194 template <class iScalar, class oScalar = iScalar>
195 class InpolSubSampler: public Sink<iScalar>, public Source
196 {
197 public:
201  InpolSubSampler(float frac)
202  : Sink<iScalar>(), Source(), _frac(frac), _mu(0)
203  {
204  if (_frac <= 0) {
205  ConfigError err;
206  err << "Can not configure InpolSubSample node: Sample rate fraction must be > 0!"
207  << " Fraction given: " << _frac;
208  throw err;
209  }
210  }
211 
213  virtual ~InpolSubSampler() {
214  // pass...
215  }
216 
218  virtual void config(const Config &src_cfg) {
219  // Requires type and buffer size
220  if (!src_cfg.hasType() || !src_cfg.hasBufferSize()) { return; }
221 
222  // check buffer type
223  if (Config::typeId<iScalar>() != src_cfg.type()) {
224  ConfigError err;
225  err << "Can not configure InpolSubSample node: Invalid buffer type " << src_cfg.type()
226  << ", expected " << Config::typeId<iScalar>();
227  throw err;
228  }
229 
230  // Allocate buffer
231  size_t bufSize = std::ceil(src_cfg.bufferSize() * src_cfg.sampleRate()/_frac);
232  _buffer = Buffer<oScalar>(bufSize);
233 
234  // Allocate & init delay line
235  _dl = Buffer<oScalar>(16); _dl_idx = 0;
236  for (size_t i=0; i<16; i++) { _dl[i] = 0; }
237  _mu = 0;
238 
239  LogMessage msg(LOG_DEBUG);
240  msg << "Configure InpolSubSampler node:" << std::endl
241  << " by: " << _frac << std::endl
242  << " type: " << src_cfg.type() << std::endl
243  << " sample-rate: " << src_cfg.sampleRate()
244  << " -> " << src_cfg.sampleRate()/_frac;
245  Logger::get().log(msg);
246 
247  // Propergate config
248  this->setConfig(Config(Traits<oScalar>::scalarId, src_cfg.sampleRate()/_frac, bufSize, 1));
249  }
250 
252  virtual void process(const Buffer<iScalar> &buffer, bool allow_overwrite)
253  {
254  // Short cut
255  if (1 == _frac) {
256  this->send(buffer, allow_overwrite);
257  return;
258  }
259 
260  size_t i=0, o=0;
261  while (i<buffer.size()) {
262  // First, fill sampler...
263  while ( (_mu >= 1) && (i<buffer.size()) ) {
264  _dl[_dl_idx] = _dl[_dl_idx+8] = buffer[i]; i++;
265  _dl_idx = (_dl_idx + 1) % 8; _mu -= 1;
266  }
267  while (_mu <= 1) {
268  // Interpolate
269  _buffer[o] = interpolate(_dl.sub(_dl_idx,8), _mu);
270  _mu += _frac; o++;
271  }
272  }
273  this->send(_buffer.head(o));
274  }
275 
276 
277 protected:
279  float _frac;
281  float _mu;
285  size_t _dl_idx;
288 };
289 
290 }
291 #endif // __SDR_SUBSAMPLE_HH__
A collection of configuration information that is send by a source to all connected sinks to properga...
Definition: node.hh:35
Buffer< oScalar > _dl
A delay-line (buffer) for the interpolation.
Definition: subsample.hh:283
size_t _sample_count
The number of samples collected times (1<<16).
Definition: subsample.hh:183
void setFrac(double frac)
Resets the sample rate fraction.
Definition: subsample.hh:146
size_t _n
The sub-sampling, n=1 means no sub-sampling at all.
Definition: subsample.hh:106
Buffer< oScalar > _buffer
The output buffer.
Definition: subsample.hh:287
virtual void send(const RawBuffer &buffer, bool allow_overwrite=false)
Sends the given buffer to all connected sinks.
Definition: node.cc:67
virtual ~FracSubSampleBase()
Destructor.
Definition: subsample.hh:141
Typed sink.
Definition: node.hh:192
Definition: autocast.hh:8
InpolSubSampler(float frac)
Constructor.
Definition: subsample.hh:201
size_t _dl_idx
Index of the delay-line.
Definition: subsample.hh:285
float _mu
The current (fractional) sample count.
Definition: subsample.hh:281
Generic source class.
Definition: node.hh:213
virtual void process(const Buffer< iScalar > &buffer, bool allow_overwrite)
Performs the sub-sampling.
Definition: subsample.hh:252
double _oFs
Target sample rate.
Definition: subsample.hh:108
float _frac
The sub-sampling fraction.
Definition: subsample.hh:279
size_t size() const
Returns the number of elements of type T in this buffer.
Definition: buffer.hh:166
bool hasType() const
If true, the configuration has a type.
Definition: node.hh:69
double frac() const
Returns the effective sub-sample fraction.
Definition: subsample.hh:156
void reset()
Reset sample counter.
Definition: subsample.hh:161
virtual void setConfig(const Config &config)
Stores the configuration and propergates it if the configuration has been changed.
Definition: node.cc:98
SubSample(size_t n)
Constructs a sub-sampler.
Definition: subsample.hh:24
Buffer< T > head(size_t n) const
Returns a new view on this buffer.
Definition: buffer.hh:237
void log(const LogMessage &message)
Logs a message.
Definition: logger.cc:100
void _process(const Buffer< Scalar > &in, const Buffer< Scalar > &out)
Performs the sub-sampling from in into out.
Definition: subsample.hh:92
Buffer< Scalar > _buffer
The output buffer, unused if the sub-sampling is performed in-place.
Definition: subsample.hh:114
Type type() const
Returns the type.
Definition: node.hh:71
Traits< Scalar >::SScalar SScalar
The input & output type super-scalar.
Definition: subsample.hh:124
virtual void process(const Buffer< Scalar > &buffer, bool allow_overwrite)
Performs the sub-sampling on the given buffer.
Definition: subsample.hh:76
static Logger & get()
Returns the singleton instance of the logger.
Definition: logger.cc:89
Buffer< T > sub(size_t offset, size_t len) const
Returns a new view on this buffer.
Definition: buffer.hh:231
virtual void config(const Config &src_cfg)
Configures the sub-sampler.
Definition: subsample.hh:40
virtual void config(const Config &src_cfg)
Configures the sub-sampling node.
Definition: subsample.hh:218
The configuration error class.
Definition: exception.hh:24
A log message.
Definition: logger.hh:22
size_t bufferSize() const
Returns the max.
Definition: node.hh:83
SScalar _avg
The average.
Definition: subsample.hh:181
Implements a fractional sub-sampler.
Definition: subsample.hh:120
SubSample(double Fs)
Constructs a sub-sampler by target sample rate.
Definition: subsample.hh:32
size_t _left
How many samples are left.
Definition: subsample.hh:112
FracSubSampleBase(double frac)
Constructor.
Definition: subsample.hh:130
Traits< Scalar >::SScalar SScalar
The super-scalar of the input type.
Definition: subsample.hh:20
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
Forward declaration of type tratis template.
Definition: traits.hh:20
Buffer< Scalar > subsample(const Buffer< Scalar > &in, const Buffer< Scalar > &out)
Performs the sub-sampling.
Definition: subsample.hh:167
size_t _period
The sub-sample period.
Definition: subsample.hh:185
SScalar _last
The last value.
Definition: subsample.hh:110
virtual ~InpolSubSampler()
Destructor.
Definition: subsample.hh:213
An interpolating sub-sampler.
Definition: subsample.hh:195
bool hasBufferSize() const
If true, the configuration has a buffer size.
Definition: node.hh:81
Simple averaging sub-sampler.
Definition: subsample.hh:16
double sampleRate() const
Returns the sample rate.
Definition: node.hh:77