libsdr  0.1.0
A simple SDR library
baseband.hh
1 #ifndef __SDR_BASEBAND_HH__
2 #define __SDR_BASEBAND_HH__
3 
4 #include "node.hh"
5 #include "config.hh"
6 #include "utils.hh"
7 #include "traits.hh"
8 #include "operators.hh"
9 #include "freqshift.hh"
10 
11 namespace sdr {
12 
13 
21 template <class Scalar>
22 class IQBaseBand: public Sink< std::complex<Scalar> >, public Source, public FreqShiftBase<Scalar>
23 {
24 public:
26  typedef std::complex<Scalar> CScalar;
29  typedef int32_t SScalar;
31  typedef std::complex<SScalar> CSScalar;
32 
33 public:
35  IQBaseBand(double Fc, double width, size_t order, size_t sub_sample, double oFs=0.0)
36  : Sink<CScalar>(), Source(), FreqShiftBase<Scalar>(Fc, 0),
37  _Fc(Fc), _Ff(Fc), _Fs(0), _width(width), _order(std::max(size_t(1), order)),
38  _sub_sample(sub_sample), _oFs(oFs), _ring_offset(0), _sample_count(0),
39  _last(0), _kernel(_order)
40  {
41  // Allocate and reset ring buffer:
43  for (size_t i=0; i<_order; i++) { _ring[i] = 0; }
44  }
45 
47  IQBaseBand(double Fc, double Ff, double width, size_t order, size_t sub_sample, double oFs=0.0)
48  : Sink<CScalar>(), Source(), FreqShiftBase<Scalar>(Fc, 0),
49  _Fc(Fc), _Ff(Ff), _Fs(0), _width(width), _order(std::max(size_t(1), order)),
50  _sub_sample(sub_sample), _oFs(oFs), _ring_offset(0), _sample_count(0),
51  _last(0), _kernel(_order)
52  {
53  // Allocate and reset ring buffer:
55  for (size_t i=0; i<_order; i++) { _ring[i] = 0; }
56  }
57 
59  virtual ~IQBaseBand() {
60  // Free buffers
61  _buffer.unref();
62  _kernel.unref();
63  _ring.unref();
64  }
65 
67  inline size_t order() const { return _order; }
69  void setOrder(size_t o) {
70  // ensure filter order >= 1
71  o = (o<1) ? 1 : o;
72  // Reallocate ring buffer and kernel
73  if (! _kernel.isEmpty()) { _kernel.unref(); }
74  if (! _ring.isEmpty()) { _ring.unref(); }
77  // Update filter kernel
79  }
80 
82  inline double centerFrequency() const { return _Fc; }
84  void setCenterFrequency(double Fc) {
85  _Fc = Fc; this->setFrequencyShift(_Fc);
86  }
87 
89  inline double filterFrequency() const { return _Ff; }
91  void setFilterFrequency(double Ff) {
92  _Ff = Ff; _update_filter_kernel();
93  }
94 
96  inline double filterWidth() const { return _width; }
98  void setFilterWidth(double width) {
99  _width = width; _update_filter_kernel();
100  }
101 
103  size_t subSample() const { return _sub_sample; }
105  void setSubsample(size_t sub_sample) {
106  _sub_sample = std::max(size_t(1), sub_sample); _reconfigure();
107  }
110  void setOutputSampleRate(double Fs) {
111  _oFs = Fs; _reconfigure();
112  }
113 
115  virtual void config(const Config &src_cfg)
116  {
117  // Requires type, sample rate & buffer size
118  if (!src_cfg.hasType() || !src_cfg.hasSampleRate() || !src_cfg.hasBufferSize()) { return; }
119  // Check buffer type
120  if (Config::typeId<CScalar>() != src_cfg.type()) {
121  ConfigError err;
122  err << "Can not configure IQBaseBand: Invalid type " << src_cfg.type()
123  << ", expected " << Config::typeId<CScalar>();
124  throw err;
125  }
126  // Store sample rate
127  _Fs = src_cfg.sampleRate();
128  // Store source buffer size
129  _sourceBs = src_cfg.bufferSize();
130 
131  _reconfigure();
132  }
133 
134 
136  virtual void process(const Buffer< std::complex<Scalar> > &buffer, bool allow_overwrite)
137  {
138  if (allow_overwrite) {
139  // Perform in-place if @c allow_overwrite
140  _process(buffer, buffer);
141  } else if (_buffer.isUnused()) {
142  // Otherwise store results into output buffer.
143  _process(buffer, _buffer);
144  } else {
145 #ifdef SDR_DEBUG
146  LogMessage msg(LOG_WARNING);
147  msg << "IQBaseBand: Drop buffer: Output buffer still in use.";
148  Logger::get().log(msg);
149 #endif
150  }
151  }
152 
153 
154 protected:
157  {
158  // If _oFs > 0 -> set _sub_sample to match the sample rate (approx).
159  if (_oFs > 0) {
160  _sub_sample = _Fs/_oFs;
161  if (_sub_sample < 1) { _sub_sample=1; }
162  }
163 
164  // Update filter kernel
166  // Update freq shift operator:
167  this->setSampleRate(_Fs);
168  // Calc output buffer size
169  size_t buffer_size = _sourceBs/_sub_sample;
170  if (_sourceBs%_sub_sample) { buffer_size += 1; }
171  // Allocate output buffer
172  _buffer = Buffer<CScalar>(buffer_size);
173 
174  // Reset internal state
175  _last = 0;
176  _sample_count = 0;
177  _ring_offset = 0;
178 
179  LogMessage msg(LOG_DEBUG);
180  msg << "Configured IQBaseBand node:" << std::endl
181  << " type " << Traits< std::complex<Scalar> >::scalarId << std::endl
182  << " sample-rate " << _Fs << "Hz" << std::endl
183  << " center freq " << _Fc << "Hz" << std::endl
184  << " width " << _width << "Hz" << std::endl
185  << " kernel " << _kernel << std::endl
186  << " in buffer size " << _sourceBs << std::endl
187  << " sub-sample by " << _sub_sample << std::endl
188  << " out buffer size " << buffer_size;
189  Logger::get().log(msg);
190 
191  // Propergate config
192  this->setConfig(Config(Traits< std::complex<Scalar> >::scalarId,
193  _Fs/_sub_sample, buffer_size, 1));
194  }
195 
198  inline void _process(const Buffer<CScalar> &in, const Buffer<CScalar> &out) {
199  size_t i=0, j=0;
200  for (; i<in.size(); i++, _sample_count++) {
201  // Store sample in ring buffer
202  _ring[_ring_offset] = in[i];
203 
204  // Apply filter on ring-buffer and shift freq
206 
207  // _ring_offset modulo _order
208  _ring_offset++;
209  if (_order == _ring_offset) { _ring_offset = 0; }
210 
211  // If _sample_count samples have been averaged:
212  if (_sub_sample == _sample_count) {
213  // Store average in output buffer
214  CSScalar value = _last/CSScalar(_sub_sample);
215  out[j] = value;
216  // reset average, sample count and increment output buffer index j
217  _last = 0; _sample_count=0; j++;
218  } else if (_sub_sample == 1) {
219  out[j] = _last; _last = 0; _sample_count = 0; j++;
220  }
221  }
222  this->send(out.head(j), true);
223  }
224 
226  inline CSScalar _filter_ring() const
227  {
228  CSScalar res = 0;
229  size_t idx = _ring_offset+1;
230  if (_order == idx) { idx = 0; }
231  for (size_t i=0; i<_order; i++, idx++) {
232  if (_order == idx) { idx = 0; }
233  res += _kernel[i]*_ring[idx];
234  }
235  return (res>>14);
236  }
237 
240  // First, create a filter kernel of a low-pass filter with _width/2 cut-off
242  double w = (M_PI*_width)/(_Fs);
243  double M = double(_order)/2.;
244  double norm = 0;
245 
246  //std::complex<double> phi(0.0, (2*M_PI*_Ff)/_Fs); phi = std::exp(phi);
247  for (size_t i=0; i<_order; i++) {
248  if (_order == 2*i) { alpha[i] = 4*(w/M_PI); }
249  else { alpha[i] = std::sin(w*(i-M))/(w*(i-M)); }
250  // Shift freq by +_Ff:
251  //alpha[i] = phi*alpha[i]; phi = phi*phi;
252  alpha[i] *= std::exp(std::complex<double>(0.0, (-2*M_PI*_Ff*i)/_Fs));
253  // apply window function
254  alpha[i] *= (0.42 - 0.5*cos((2*M_PI*i)/_order) + 0.08*cos((4*M_PI*i)/_order));
255  // Calc norm
256  norm += std::abs(alpha[i]);
257  }
258  // Normalize filter coeffs and store in _kernel:
259  for (size_t i=0; i<_order; i++) {
260  _kernel[i] = (double(1<<14) * alpha[i]) / norm;
261  }
262  }
263 
264 protected:
266  int32_t _Fc;
268  int32_t _Ff;
270  int32_t _Fs;
272  int32_t _width;
274  size_t _order;
276  size_t _sub_sample;
278  double _oFs;
280  size_t _ring_offset;
284  CSScalar _last;
286  size_t _sourceBs;
287 
294 };
295 
296 
297 
298 
304 template <class Scalar>
305 class BaseBand: public Sink<Scalar>, public Source, public FreqShiftBase<Scalar>
306 {
307 public:
314 
315 public:
322  BaseBand(double Fc, double width, size_t order, size_t sub_sample)
323  : Sink<Scalar>(), Source(), FreqShiftBase<Scalar>(Fc, 0),
324  _Ff(Fc), _width(width), _order(std::max(size_t(1), order)),
325  _sub_sample(sub_sample), _ring_offset(0), _sample_count(0),
326  _last(0), _kernel(_order)
327  {
328  // Allocate and reset ring buffer:
330  for (size_t i=0; i<_order; i++) { _ring[i] = 0; }
331  }
332 
340  BaseBand(double Fc, double Ff, double width, size_t order, size_t sub_sample)
341  : Sink<Scalar>(), Source(), FreqShiftBase<Scalar>(Fc, 0),
342  _Ff(Ff), _width(width), _order(std::max(size_t(1), order)),
343  _sub_sample(sub_sample), _ring_offset(0), _sample_count(0),
344  _last(0), _kernel(_order)
345  {
346  // Allocate and reset ring buffer:
348  for (size_t i=0; i<_order; i++) { _ring[i] = 0; }
349  }
350 
352  virtual ~BaseBand() {
353  // Free buffers
354  _buffer.unref();
355  _kernel.unref();
356  _ring.unref();
357  }
358 
360  virtual void config(const Config &src_cfg) {
361  // Requires type, sample rate & buffer size
362  if (!src_cfg.hasType() || !src_cfg.hasSampleRate() || !src_cfg.hasBufferSize()) { return; }
363  // Check buffer type
364  if (Config::typeId<Scalar>() != src_cfg.type()) {
365  ConfigError err;
366  err << "Can not configure BaseBand: Invalid type " << src_cfg.type()
367  << ", expected " << Config::typeId<Scalar>();
368  throw err;
369  }
370  // Store sample rate
371  this->setSampleRate(src_cfg.sampleRate());
372 
373  // Calc output buffer size
374  size_t buffer_size = src_cfg.bufferSize()/_sub_sample;
375  if (src_cfg.bufferSize()%_sub_sample) { buffer_size += 1; }
376  // Allocate output buffer
377  _buffer = Buffer<CScalar>(buffer_size);
378 
379  _last = 0;
380  _sample_count = 0;
381  _ring_offset = 0;
382 
383  LogMessage msg(LOG_DEBUG);
384  msg << "Configured BaseBand node:" << std::endl
385  << " type " << Traits< std::complex<Scalar> >::scalarId << std::endl
386  << " sample-rate " << FreqShiftBase<Scalar>::sampleRate() << "Hz" << std::endl
387  << " center freq " << FreqShiftBase<Scalar>::frequencyShift() << "Hz" << std::endl
388  << " width " << _width << "Hz" << std::endl
389  << " kernel " << _kernel << std::endl
390  << " in buffer size " << src_cfg.bufferSize() << std::endl
391  << " sub-sample by " << _sub_sample << std::endl
392  << " out buffer size " << buffer_size;
393  Logger::get().log(msg);
394 
395  // Propergate config
396  this->setConfig(Config(Traits< std::complex<Scalar> >::scalarId,
398  }
399 
400  virtual void setSampleRate(double Fs) {
404  }
405 
407  virtual void process(const Buffer<Scalar> &buffer, bool allow_overwrite)
408  {
409  if (_buffer.isUnused()) {
410  _process(buffer, _buffer);
411  } else {
412 #ifdef SDR_DEBUG
413  LogMessage msg(LOG_WARNING);
414  msg << "BaseBand: Drop buffer: Output buffer still in use.";
415  Logger::get().log(msg);
416 #endif
417  }
418  }
419 
420 
421 protected:
425  inline void _process(const Buffer<Scalar> &in, const Buffer<CScalar> &out) {
426  size_t i=0, j=0;
427  for (; i<in.size(); i++) {
428  // Store sample in ring buffer
429  _ring[_ring_offset] = in[i];
430 
432  _sample_count++;
433 
434  // _ring_offset modulo _order
435  _ring_offset++;
436  if (_order == _ring_offset) { _ring_offset = 0; }
437 
438  // If _sample_count samples have been averaged:
439  if (_sub_sample == _sample_count) {
440  // Store average in output buffer
441  out[j] = _last/CSScalar(_sub_sample);;
442  // reset average, sample count and increment output buffer index j
443  _last = 0; _sample_count=0; j++;
444  }
445  }
446  this->send(out.head(j), true);
447  }
448 
450  inline CSScalar _filter_ring()
451  {
452  CSScalar res = 0;
453  size_t idx = _ring_offset+1;
454  if (_order == idx) { idx = 0; }
455  for (size_t i=0; i<_order; i++, idx++) {
456  if (_order == idx) { idx = 0; }
457  res += _kernel[i]*_ring[idx];
458  }
459  return (res>>Traits<Scalar>::shift);
460  }
461 
464  // First, create a filter kernel of a low-pass filter with
465  // _width/2 cut-off
467  double w = (2*M_PI*_width)/(2*FreqShiftBase<Scalar>::sampleRate());
468  double M = double(_order)/2;
469  double norm = 0;
470  for (size_t i=0; i<_order; i++) {
471  if (_order == (2*i)) { alpha[i] = 1; }
472  else { alpha[i] = std::sin(w*(i-M))/(w*(i-M)); }
473  }
474  // Shift filter by _Fc, apply window function and calc norm of filter
475  std::complex<double> phi(0.0, (2*M_PI*_Ff)/FreqShiftBase<Scalar>::sampleRate()); phi = std::exp(phi);
476  for (size_t i=0; i<_order; i++) {
477  // Shift filter kernel
478  alpha[i] = alpha[i]*std::exp(std::complex<double>(0, (2*M_PI*_Ff*i)/FreqShiftBase<Scalar>::sampleRate()));
479  // apply window function
480  alpha[i] *= (0.42 - 0.5*cos((2*M_PI*(i+1))/(_order+2)) +
481  0.08*cos((4*M_PI*(i+1))/(_order+2)));
482  // Calc norm
483  norm += std::abs(alpha[i]);
484  }
485  // Normalize filter coeffs and store in _kernel:
486  for (size_t i=0; i<_order; i++) {
487  _kernel[i] = ((double(1<<Traits<Scalar>::shift) * alpha[i]) / norm);
488  }
489  // free alpha
490  alpha.unref();
491  }
492 
493 protected:
495  double _Ff;
497  double _width;
499  size_t _order;
501  size_t _sub_sample;
503  size_t _ring_offset;
504 
508  CSScalar _last;
509 
515  size_t _lut_inc;
517  size_t _lut_count;
518 
525 
526 protected:
528  static const size_t _lut_size=128;
529 };
530 
531 }
532 
533 #endif // __SDR_BASEBAND_HH__
FreqShiftBase< Scalar >::CSScalar CSScalar
The complex super scalar.
Definition: baseband.hh:313
virtual ~BaseBand()
Destructor.
Definition: baseband.hh:352
A collection of configuration information that is send by a source to all connected sinks to properga...
Definition: node.hh:35
double frequencyShift() const
Returns the frequency shift.
Definition: freqshift.hh:51
size_t subSample() const
Returns the sub sampling.
Definition: baseband.hh:103
size_t _ring_offset
The current index of the ring buffer.
Definition: baseband.hh:280
int32_t _width
The filter width.
Definition: baseband.hh:272
std::complex< SScalar > CSScalar
Complex SScalar type.
Definition: baseband.hh:31
size_t _sample_count
The current number of averages.
Definition: baseband.hh:506
double filterFrequency() const
Returns the filter frequency.
Definition: baseband.hh:89
FreqShiftBase< Scalar >::CScalar CScalar
The complex input scalar.
Definition: baseband.hh:309
void setOrder(size_t o)
(Re-) Sets the filter order.
Definition: baseband.hh:69
virtual void setSampleRate(double Fs)
Sets the sample rate and updates the LUT.
Definition: freqshift.hh:46
virtual void send(const RawBuffer &buffer, bool allow_overwrite=false)
Sends the given buffer to all connected sinks.
Definition: node.cc:67
size_t _sub_sample
The number of sample averages for the sub sampling.
Definition: baseband.hh:276
This class performs several operations on the complex (integral) input stream, it first filters out s...
Definition: baseband.hh:22
IQBaseBand(double Fc, double width, size_t order, size_t sub_sample, double oFs=0.0)
Constructor, the filter center frequency Ff equals the given center frequency Fc. ...
Definition: baseband.hh:35
void _process(const Buffer< Scalar > &in, const Buffer< CScalar > &out)
Performs the actual procssing.
Definition: baseband.hh:425
Typed sink.
Definition: node.hh:192
Definition: autocast.hh:8
double centerFrequency() const
Returns the center frequency.
Definition: baseband.hh:82
bool isEmpty() const
Returns true if the buffer is invalid/empty.
Definition: buffer.hh:77
Definition: operators.hh:9
void setCenterFrequency(double Fc)
Resets the center frequency.
Definition: baseband.hh:84
virtual void setFrequencyShift(double F)
Sets the frequency shift and updates the LUT.
Definition: freqshift.hh:53
bool hasSampleRate() const
If true, the configuration has a sample rate.
Definition: node.hh:75
size_t order() const
Returns the order of the band-pass filter.
Definition: baseband.hh:67
CSScalar _filter_ring()
Applies the filter on the data stored in the ring buffer.
Definition: baseband.hh:450
void _reconfigure()
Reconfigures the node.
Definition: baseband.hh:156
Generic source class.
Definition: node.hh:213
bool _shift_freq
If true, Fc!=0.
Definition: baseband.hh:511
double sampleRate() const
Returns the sample rate.
Definition: freqshift.hh:44
void setOutputSampleRate(double Fs)
Resets the output sample rate.
Definition: baseband.hh:110
std::complex< SScalar > CSScalar
The complex compute (super) scalar of the input type.
Definition: freqshift.hh:22
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
size_t _sourceBs
Buffer size of the source.
Definition: baseband.hh:286
int32_t _Fs
The input sample rate.
Definition: baseband.hh:270
size_t _ring_offset
The current index of the ring buffer.
Definition: baseband.hh:503
int32_t SScalar
The (real) computation scalar type (super scalar), the computations are performed with this scalar ty...
Definition: baseband.hh:29
virtual void setSampleRate(double Fs)
Sets the sample rate and updates the LUT.
Definition: baseband.hh:400
void _update_filter_kernel()
Updates the band-pass filter kernel.
Definition: baseband.hh:239
virtual void setConfig(const Config &config)
Stores the configuration and propergates it if the configuration has been changed.
Definition: node.cc:98
double _oFs
Holds the desired output sample rate, _sub_sample will be adjusted accordingly.
Definition: baseband.hh:278
size_t _order
The order of the filter.
Definition: baseband.hh:274
BaseBand(double Fc, double width, size_t order, size_t sub_sample)
Constructs a new BaseBand instance.
Definition: baseband.hh:322
CSScalar _last
The current sum of the last _sample_count samples.
Definition: baseband.hh:508
Buffer< CScalar > _buffer
The output buffer.
Definition: baseband.hh:293
IQBaseBand(double Fc, double Ff, double width, size_t order, size_t sub_sample, double oFs=0.0)
Constructor.
Definition: baseband.hh:47
Buffer< T > head(size_t n) const
Returns a new view on this buffer.
Definition: buffer.hh:237
void _process(const Buffer< CScalar > &in, const Buffer< CScalar > &out)
Performs the base-band selection, frequency shift and sub-sampling.
Definition: baseband.hh:198
std::complex< Scalar > CScalar
The complex input signal.
Definition: freqshift.hh:18
virtual ~IQBaseBand()
Destructor.
Definition: baseband.hh:59
int32_t _Ff
The center frequency of the base band.
Definition: baseband.hh:268
void _update_filter_kernel()
Calculates or updates the filter kernel.
Definition: baseband.hh:463
void log(const LogMessage &message)
Logs a message.
Definition: logger.cc:100
void setFilterFrequency(double Ff)
(Re-) Sets the filter frequency.
Definition: baseband.hh:91
Type type() const
Returns the type.
Definition: node.hh:71
Buffer< CSScalar > _ring
A ring buffer of past values.
Definition: baseband.hh:291
virtual void process(const Buffer< Scalar > &buffer, bool allow_overwrite)
Processes the input buffer.
Definition: baseband.hh:407
Traits< Scalar >::SScalar SScalar
The compute (super) scalar of the input type.
Definition: freqshift.hh:20
static Logger & get()
Returns the singleton instance of the logger.
Definition: logger.cc:89
size_t _sample_count
Holds the current number of samples averaged.
Definition: baseband.hh:282
Buffer< CScalar > _buffer
The output buffer.
Definition: baseband.hh:524
A performant implementation of a frequency-shift operation on integer signals.
Definition: freqshift.hh:14
int32_t _Fc
The frequency shift of the base band.
Definition: baseband.hh:266
virtual void config(const Config &src_cfg)
Configures the BaseBand node.
Definition: baseband.hh:115
size_t _order
The order of the band pass filter.
Definition: baseband.hh:499
The configuration error class.
Definition: exception.hh:24
Buffer< CSScalar > _lut
look-up table
Definition: baseband.hh:513
A log message.
Definition: logger.hh:22
size_t bufferSize() const
Returns the max.
Definition: node.hh:83
std::complex< Scalar > CScalar
The complex type of the input stream.
Definition: baseband.hh:26
void setSubsample(size_t sub_sample)
Resets the sub sampling.
Definition: baseband.hh:105
size_t _lut_count
The current LUT index times (1<<4).
Definition: baseband.hh:517
static const size_t _lut_size
Size of the look-up table.
Definition: baseband.hh:528
FreqShiftBase< Scalar >::SScalar SScalar
The real super scalar.
Definition: baseband.hh:311
This class performs several operations on the real input stream, It first filters out some part of th...
Definition: baseband.hh:305
CSScalar applyFrequencyShift(CSScalar value)
Performs the frequency shift on a single sample.
Definition: freqshift.hh:58
size_t _sub_sample
The number of averages taken for subsampling.
Definition: baseband.hh:501
double _Ff
The center frequency of the band pass filter.
Definition: baseband.hh:495
void unref()
Dereferences the buffer.
Definition: buffer.cc:63
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
BaseBand(double Fc, double Ff, double width, size_t order, size_t sub_sample)
Constructs a new BaseBand instance.
Definition: baseband.hh:340
Forward declaration of type tratis template.
Definition: traits.hh:20
Buffer< CSScalar > _kernel
The filter kernel of order _order.
Definition: baseband.hh:289
virtual void process(const Buffer< std::complex< Scalar > > &buffer, bool allow_overwrite)
Processes the given buffer.
Definition: baseband.hh:136
CSScalar _last
Holds the current sum of the last _sample_count samples.
Definition: baseband.hh:284
double filterWidth() const
Returns the filter width.
Definition: baseband.hh:96
double _width
The width of the band pass filter.
Definition: baseband.hh:497
size_t _lut_inc
The LUT index increment per (1<<4) samples.
Definition: baseband.hh:515
Buffer< CSScalar > _kernel
The filter kernel of order _order.
Definition: baseband.hh:520
CSScalar _filter_ring() const
Applies the filter on the data stored in the ring buffer.
Definition: baseband.hh:226
Buffer< SScalar > _ring
A ring buffer of past values.
Definition: baseband.hh:522
bool hasBufferSize() const
If true, the configuration has a buffer size.
Definition: node.hh:81
double sampleRate() const
Returns the sample rate.
Definition: node.hh:77
void setFilterWidth(double width)
Sets the filter width.
Definition: baseband.hh:98
virtual void config(const Config &src_cfg)
Configures the base band node.
Definition: baseband.hh:360