libsdr  0.1.0
A simple SDR library
filternode.hh
1 #ifndef __SDR_FILTERNODE_HH__
2 #define __SDR_FILTERNODE_HH__
3 
4 #include <limits>
5 #include <list>
6 
7 #include "config.hh"
8 #include "node.hh"
9 #include "buffer.hh"
10 #include "buffernode.hh"
11 #include "fftplan.hh"
12 
13 
14 namespace sdr {
15 
17 template <class Scalar>
18 inline std::complex<Scalar> sinc_flt_kernel(int i, int N, double Fc, double bw, double Fs) {
19  std::complex<Scalar> v;
20  // Eval sinc
21  if ( (N/2) == i) { v = M_PI*(bw/Fs); }
22  else { v = std::sin(M_PI*(bw/Fs)*(i-N/2))/(i-N/2); }
23  // shift frequency
24  v *= std::exp(std::complex<Scalar>(0.0, (2*M_PI*Fc*i)/Fs));
25  // Apply window
26  v *= (0.42 - 0.5*cos((2*M_PI*i)/N) + 0.08*cos((4*M_PI*i)/N));
27  return v;
28 }
29 
30 
31 
33 template <class Scalar>
34 class FilterSink: public Sink< std::complex<Scalar> >, public Source
35 {
36 public:
38  FilterSink(size_t block_size)
39  : Sink< std::complex<Scalar> >(), Source(), _block_size(block_size),
40  _in_buffer(2*block_size), _out_buffer(2*block_size),
41  _plan(_in_buffer, _out_buffer, FFT::FORWARD)
42  {
43  // Fill second half of input buffer with 0s
44  for(size_t i=0; i<2*_block_size; i++) {
45  _in_buffer[i] = 0;
46  }
47  }
48 
50  virtual ~FilterSink() {
51  _in_buffer.unref();
53  }
54 
56  virtual void config(const Config &src_cfg) {
57  // Skip if config is incomplete
58  if ((Config::Type_UNDEFINED==src_cfg.type()) || (0 == src_cfg.sampleRate()) || (0 == src_cfg.bufferSize())) {
59  return;
60  }
61  // Now check type (must be real double)
62  if (Config::typeId< std::complex<Scalar> >() != src_cfg.type()) {
63  ConfigError err;
64  err << "Can not configure filter-sink: Invalid type " << src_cfg.type()
65  << ", expected " << Config::typeId< std::complex<Scalar> >();
66  throw err;
67  }
68  // Check buffer size
69  if (_block_size != src_cfg.bufferSize()) {
70  ConfigError err;
71  err << "Can not configure filter-sink: Invalid buffer size " << src_cfg.bufferSize()
72  << ", expected " << _block_size;
73  throw err;
74  }
75  // Propagate configuration
76  setConfig(Config(Config::typeId< std::complex<Scalar> >(), src_cfg.sampleRate(),
77  src_cfg.bufferSize(), src_cfg.numBuffers()));
78  }
79 
81  virtual void process(const Buffer< std::complex<Scalar> > &buffer, bool allow_overwrite) {
82  // Copy buffer into 1st half of input buffer
83  for (size_t i=0; i<_block_size; i++) { _in_buffer[i] = buffer[i]; }
84  // perform fft
85  _plan();
86  // send fft result
87  this->send(_out_buffer);
88  }
89 
90 protected:
92  size_t _block_size;
99 };
100 
101 
102 
104 template <class Scalar>
105 class FilterSource: public Sink< std::complex<Scalar> >, public Source
106 {
107 public:
109  FilterSource(size_t block_size, double fmin, double fmax)
110  : Sink< std::complex<Scalar> >(), Source(),
111  _block_size(block_size), _sample_rate(0),
113  _kern(2u*_block_size), _buffers(1, _block_size), _fmin(fmin), _fmax(fmax),
114  _plan(_in_buffer, _trafo_buffer, FFT::BACKWARD)
115  {
116  // Set input & output buffer to 0
117  for (size_t i=0; i<_block_size; i++) {
118  _last_trafo[i] = 0;
119  }
120  }
121 
123  virtual ~FilterSource() {
124  // pas...
125  }
126 
128  void setFreq(double fmin, double fmax) {
129  _fmin = fmin; _fmax = fmax; _updateFilter();
130  }
131 
133  virtual void config(const Config &src_cfg) {
134  // Check config
135  if ((0 == src_cfg.sampleRate()) || (0 == src_cfg.bufferSize())) { return; }
136  if (_block_size != src_cfg.bufferSize()) {
137  ConfigError err;
138  err << "Can not configure FilterSource, block-size (=" << _block_size
139  << ") != buffer-size (=" << src_cfg.bufferSize() << ")!";
140  throw err;
141  }
142  // calc filter kernel
143  _sample_rate = src_cfg.sampleRate();
144  _updateFilter();
145  // Resize buffer-set
146  _buffers.resize(src_cfg.numBuffers());
147 
148  LogMessage msg(LOG_DEBUG);
149  double fmin = std::max(_fmin, -src_cfg.sampleRate()/2);
150  double fmax = std::min(_fmax, src_cfg.sampleRate()/2);
151  msg << "Configured FFT Filter: " << std::endl
152  << " range: [" << fmin << ", " << fmax << "]" << std::endl
153  << " fft size: " << 2*_block_size << std::endl
154  << " Fc/BW: " << fmin+(fmax-fmin)/2 << " / " << (fmax-fmin) << std::endl
155  << " sample rate: " << src_cfg.sampleRate();
156  Logger::get().log(msg);
157 
158  // Propergate config
159  Source::setConfig(Config(Config::typeId< std::complex<Scalar> >(), src_cfg.sampleRate(),
160  _block_size, src_cfg.numBuffers()));
161  }
162 
164  virtual void process(const Buffer<std::complex<Scalar> > &buffer, bool allow_overwrite) {
165  // Multiply with F(_kern)
166  for (size_t i=0; i<(2*_block_size); i++) {
167  _in_buffer[i] = buffer[i]*_kern[i];
168  }
169  // perform FFT
170  _plan();
171  // Get a output buffer
173  // Add first half of trafo buffer to second half of last trafo
174  // and store second half of the current trafo
175  for (size_t i=0; i<_block_size; i++) {
176  out[i] = _last_trafo[i] + (_trafo_buffer[i]/((Scalar)(2*_block_size)));
177  _last_trafo[i] = (_trafo_buffer[i+_block_size]/((Scalar)(2*_block_size)));
178  }
179  // Send output
180  this->send(out);
181  }
182 
183 
184 protected:
186  void _updateFilter() {
187  // Calc filter kernel
188  double Fs = _sample_rate;
189  double fmin = std::max(_fmin, -Fs/2);
190  double fmax = std::min(_fmax, Fs/2);
191  double bw = fmax-fmin;
192  double Fc = fmin + bw/2;
193  for (size_t i=0; i<_block_size; i++) {
194  // Eval kernel
195  _kern[i] = sinc_flt_kernel<Scalar>(i, _block_size, Fc, bw, Fs);
196  // set second half to 0
197  _kern[i+_block_size] = 0;
198  }
199  // Calculate FFT in-place
200  FFT::exec(_kern, FFT::FORWARD);
201  // Normalize filter kernel
202  _kern /= _kern.norm2();
203  }
204 
205 protected:
207  size_t _block_size;
209  double _sample_rate;
221  double _fmin;
223  double _fmax;
226 };
227 
228 
231 template <class Scalar>
233 {
234 public:
236  FilterNode(size_t block_size=1024)
237  : _block_size(block_size), _buffer(0), _fft_fwd(0), _filters()
238  {
239  // Create input buffer node
240  _buffer = new BufferNode< std::complex<Scalar> >(block_size);
241  // Create FFT fwd transform
242  _fft_fwd = new FilterSink<Scalar>(block_size);
243  // Connect buffer source to FFT sink directly
244  _buffer->connect(_fft_fwd, true);
245  }
246 
248  virtual ~FilterNode() {
249  delete _buffer; delete _fft_fwd;
250  typename std::list< FilterSource<Scalar> *>::iterator item=_filters.begin();
251  for (; item!=_filters.end(); item++) {
252  delete *item;
253  }
254  }
255 
258  return _buffer;
259  }
260 
262  FilterSource<Scalar> *addFilter(double fmin, double fmax) {
263  // Check if fmin < fmax
264  if (fmax < fmin) { std::swap(fmin, fmax); }
265  // Create and store filter instance
266  _filters.push_back(new FilterSource<Scalar>(_block_size, fmin, fmax));
267  // Connect fft_fwd trafo to filter directly
268  _fft_fwd->connect(_filters.back(), true);
269  return _filters.back();
270  }
271 
272 protected:
274  size_t _block_size;
276  double _sample_rate;
282  std::list<FilterSource<Scalar> *> _filters;
283 };
284 
285 }
286 
287 #endif // __SDR_FILTERNODE_HH__
double _sample_rate
The current sample rate.
Definition: filternode.hh:276
A collection of configuration information that is send by a source to all connected sinks to properga...
Definition: node.hh:35
FFTPlan< Scalar > _plan
The FFT plan for the FFT back-transform.
Definition: filternode.hh:225
void _updateFilter()
Updates the sink-filter.
Definition: filternode.hh:186
FilterSink(size_t block_size)
Constructor, best performance with block-size being a power of 2.
Definition: filternode.hh:38
Performs the overlap-add FFT filtering and back-transform.
Definition: filternode.hh:105
virtual void send(const RawBuffer &buffer, bool allow_overwrite=false)
Sends the given buffer to all connected sinks.
Definition: node.cc:67
Sink< std::complex< Scalar > > * sink() const
The filter sink.
Definition: filternode.hh:257
Typed sink.
Definition: node.hh:192
Definition: autocast.hh:8
size_t numBuffers() const
Returns the max.
Definition: node.hh:89
size_t _block_size
The block size of the filters.
Definition: filternode.hh:274
Definition: operators.hh:9
Performs the FFT forward transform.
Definition: filternode.hh:34
void setFreq(double fmin, double fmax)
Set the frequency range.
Definition: filternode.hh:128
Generic source class.
Definition: node.hh:213
virtual void process(const Buffer< std::complex< Scalar > > &buffer, bool allow_overwrite)
Performs the FFT forward transform.
Definition: filternode.hh:81
A set of buffers, that tracks their usage.
Definition: buffer.hh:288
A simple buffering node, that ensures a fixed buffer size.
Definition: buffernode.hh:18
BufferSet< std::complex< Scalar > > _buffers
The output buffers.
Definition: filternode.hh:219
virtual void setConfig(const Config &config)
Stores the configuration and propergates it if the configuration has been changed.
Definition: node.cc:98
Buffer< std::complex< Scalar > > _out_buffer
The output buffer (transformed).
Definition: filternode.hh:96
Buffer< std::complex< Scalar > > _last_trafo
Holds a copy of the second-half of the last output signal.
Definition: filternode.hh:215
double norm2() const
Returns the norm of the buffer.
Definition: buffer.hh:182
void connect(SinkBase *sink, bool direct=false)
Connect this source to a sink.
Definition: node.cc:87
FFTPlan< Scalar > _plan
The plan for the FFT forward transform.
Definition: filternode.hh:98
Trivial FFT implementation for buffer sizes of N=2**K.
Definition: fftplan.hh:11
double _fmin
The lower frequency range.
Definition: filternode.hh:221
FilterSink< Scalar > * _fft_fwd
The filter sink (forward FFT).
Definition: filternode.hh:280
virtual void process(const Buffer< std::complex< Scalar > > &buffer, bool allow_overwrite)
Performs the FFT filtering and back-transform.
Definition: filternode.hh:164
Buffer< std::complex< Scalar > > _kern
Holds the current filter kernel.
Definition: filternode.hh:217
double _sample_rate
The current sample-rate.
Definition: filternode.hh:209
void log(const LogMessage &message)
Logs a message.
Definition: logger.cc:100
virtual void config(const Config &src_cfg)
Configures the node.
Definition: filternode.hh:56
Type type() const
Returns the type.
Definition: node.hh:71
Buffer< std::complex< Scalar > > _in_buffer
An input buffer.
Definition: filternode.hh:211
static void exec(const Buffer< std::complex< Scalar > > &in, const Buffer< std::complex< Scalar > > &out, FFT::Direction dir)
Performs a FFT transform.
Definition: fftplan.hh:23
static Type typeId()
Returns the type-id of the template type.
void resize(size_t numBuffers)
Resize the buffer set.
Definition: buffer.hh:332
static Logger & get()
Returns the singleton instance of the logger.
Definition: logger.cc:89
std::list< FilterSource< Scalar > * > _filters
The filter bank.
Definition: filternode.hh:282
virtual ~FilterSink()
Destructor.
Definition: filternode.hh:50
Buffer< std::complex< Scalar > > _in_buffer
The input buffer.
Definition: filternode.hh:94
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
FilterSource< Scalar > * addFilter(double fmin, double fmax)
Adds a filter to the filter bank.
Definition: filternode.hh:262
double _fmax
The upper frequency range.
Definition: filternode.hh:223
virtual ~FilterSource()
Destructor.
Definition: filternode.hh:123
virtual ~FilterNode()
Destructor.
Definition: filternode.hh:248
FilterSource(size_t block_size, double fmin, double fmax)
Constructor.
Definition: filternode.hh:109
void unref()
Dereferences the buffer.
Definition: buffer.cc:63
Buffer< std::complex< Scalar > > _trafo_buffer
A compute buffer.
Definition: filternode.hh:213
size_t _block_size
The block size.
Definition: filternode.hh:92
Buffer< Scalar > getBuffer()
Obtains a free buffer.
Definition: buffer.hh:318
FFT module class, provides static methods to perfrom a FFT directly.
Definition: fftplan.hh:14
BufferNode< std::complex< Scalar > > * _buffer
The input buffer (to ensure buffers of _block_size size.
Definition: filternode.hh:278
virtual void config(const Config &src_cfg)
Configures the filter node.
Definition: filternode.hh:133
A typed buffer.
Definition: buffer.hh:111
FilterNode(size_t block_size=1024)
Constructor.
Definition: filternode.hh:236
double sampleRate() const
Returns the sample rate.
Definition: node.hh:77
A FFT filter bank node wich consists of several filters.
Definition: filternode.hh:232
size_t _block_size
Holds the block size of the filter.
Definition: filternode.hh:207