SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
downchannelizer.cpp
Go to the documentation of this file.
1 // Copyright (C) 2016-2019 F4EXB //
3 // written by Edouard Griffiths //
4 // //
5 // This program is free software; you can redistribute it and/or modify //
6 // it under the terms of the GNU General Public License as published by //
7 // the Free Software Foundation as version 3 of the License, or //
8 // (at your option) any later version. //
9 // //
10 // This program is distributed in the hope that it will be useful, //
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
13 // GNU General Public License V3 for more details. //
14 // //
15 // You should have received a copy of the GNU General Public License //
16 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
18 
19 #include <dsp/downchannelizer.h>
20 #include "dsp/inthalfbandfilter.h"
21 #include "dsp/dspcommands.h"
23 
24 #include <QString>
25 #include <QDebug>
26 
29 
31  m_filterChainSetMode(false),
32  m_sampleSink(sampleSink),
33  m_inputSampleRate(0),
34  m_requestedOutputSampleRate(0),
35  m_requestedCenterFrequency(0),
36  m_currentOutputSampleRate(0),
37  m_currentCenterFrequency(0)
38 {
39  QString name = "DownChannelizer(" + m_sampleSink->objectName() + ")";
40  setObjectName(name);
41 }
42 
44 {
46 }
47 
48 void DownChannelizer::configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency)
49 {
50  Message* cmd = new DSPConfigureChannelizer(sampleRate, centerFrequency);
51  messageQueue->push(cmd);
52 }
53 
54 void DownChannelizer::set(MessageQueue* messageQueue, unsigned int log2Decim, unsigned int filterChainHash)
55 {
56  Message* cmd = new MsgSetChannelizer(log2Decim, filterChainHash);
57  messageQueue->push(cmd);
58 }
59 
60 void DownChannelizer::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly)
61 {
62  if(m_sampleSink == 0) {
63  m_sampleBuffer.clear();
64  return;
65  }
66 
67  if (m_filterStages.size() == 0) // optimization when no downsampling is done anyway
68  {
69  m_sampleSink->feed(begin, end, positiveOnly);
70  }
71  else
72  {
73  m_mutex.lock();
74 
75  for(SampleVector::const_iterator sample = begin; sample != end; ++sample)
76  {
77  Sample s(*sample);
78  FilterStages::iterator stage = m_filterStages.begin();
79 
80  for (; stage != m_filterStages.end(); ++stage)
81  {
82 #ifndef SDR_RX_SAMPLE_24BIT
83  s.m_real /= 2; // avoid saturation on 16 bit samples
84  s.m_imag /= 2;
85 #endif
86  if(!(*stage)->work(&s))
87  {
88  break;
89  }
90  }
91 
92  if(stage == m_filterStages.end())
93  {
94 #ifdef SDR_RX_SAMPLE_24BIT
95  s.m_real /= (1<<(m_filterStages.size())); // on 32 bit samples there is enough headroom to just divide the final result
96  s.m_imag /= (1<<(m_filterStages.size()));
97 #endif
98  m_sampleBuffer.push_back(s);
99  }
100  }
101 
102  m_mutex.unlock();
103 
104  m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), positiveOnly);
105  m_sampleBuffer.clear();
106  }
107 }
108 
110 {
111  if (m_sampleSink != 0)
112  {
113  qDebug() << "DownChannelizer::start: thread: " << thread()
114  << " m_inputSampleRate: " << m_inputSampleRate
115  << " m_requestedOutputSampleRate: " << m_requestedOutputSampleRate
116  << " m_requestedCenterFrequency: " << m_requestedCenterFrequency;
117  m_sampleSink->start();
118  }
119 }
120 
122 {
123  if(m_sampleSink != 0)
124  m_sampleSink->stop();
125 }
126 
128 {
129  // TODO: apply changes only if input sample rate or requested output sample rate change. Change of center frequency has no impact.
130 
132  {
135  qDebug() << "DownChannelizer::handleMessage: DSPSignalNotification: m_inputSampleRate: " << m_inputSampleRate;
136 
137  if (!m_filterChainSetMode) {
139  }
140 
141  if (m_sampleSink != 0)
142  {
143  DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy
145  }
146 
147  emit inputSampleRateChanged();
148  return true;
149  }
150  else if (DSPConfigureChannelizer::match(cmd))
151  {
155 
156  // qDebug() << "DownChannelizer::handleMessage: DSPConfigureChannelizer:"
157  // << " m_requestedOutputSampleRate: " << m_requestedOutputSampleRate
158  // << " m_requestedCenterFrequency: " << m_requestedCenterFrequency;
159 
161 
162  return true;
163  }
164  else if (MsgSetChannelizer::match(cmd))
165  {
166  MsgSetChannelizer& chan = (MsgSetChannelizer&) cmd;
167  qDebug() << "DownChannelizer::handleMessage: MsgSetChannelizer";
169 
170  return true;
171  }
173  {
174  qDebug() << "DownChannelizer::handleMessage: MsgThreadedSink: forwarded to demod";
175  return m_sampleSink->handleMessage(cmd); // this message is passed to the demod
176  }
177  else
178  {
179  qDebug() << "DownChannelizer::handleMessage: " << cmd.getIdentifier() << " unhandled";
180  return false;
181  }
182 }
183 
185 {
186  m_filterChainSetMode = false;
187 
188  if (m_inputSampleRate == 0)
189  {
190  qDebug() << "DownChannelizer::applyConfiguration: m_inputSampleRate=0 aborting";
191  return;
192  }
193 
194  m_mutex.lock();
195 
196  freeFilterChain();
197 
201 
202  m_mutex.unlock();
203 
204  //debugFilterChain();
205 
207 
208  qDebug() << "DownChannelizer::applyConfiguration in=" << m_inputSampleRate
209  << ", req=" << m_requestedOutputSampleRate
210  << ", out=" << m_currentOutputSampleRate
211  << ", fc=" << m_currentCenterFrequency;
212 
213  if (m_sampleSink != 0)
214  {
217  }
218 }
219 
220 void DownChannelizer::applySetting(unsigned int log2Decim, unsigned int filterChainHash)
221 {
222  m_filterChainSetMode = true;
223  std::vector<unsigned int> stageIndexes;
224  m_currentCenterFrequency = m_inputSampleRate * HBFilterChainConverter::convertToIndexes(log2Decim, filterChainHash, stageIndexes);
226 
227  m_mutex.lock();
228  freeFilterChain();
229  setFilterChain(stageIndexes);
230  m_mutex.unlock();
231 
234 
235  qDebug() << "DownChannelizer::applySetting inputSampleRate:" << m_inputSampleRate
236  << " currentOutputSampleRate: " << m_currentOutputSampleRate
237  << " currentCenterFrequency: " << m_currentCenterFrequency
238  << " nb_filters: " << stageIndexes.size()
239  << " nb_stages: " << m_filterStages.size();
240 
241  if (m_sampleSink != 0)
242  {
245  }
246 }
247 
248 #ifdef SDR_RX_SAMPLE_24BIT
251  m_workFunction(0),
252  m_mode(mode),
253  m_sse(true)
254 {
255  switch(mode) {
256  case ModeCenter:
258  break;
259 
260  case ModeLowerHalf:
262  break;
263 
264  case ModeUpperHalf:
266  break;
267  }
268 }
269 #else
271  m_filter(new IntHalfbandFilterEO<qint32, qint32, DOWNCHANNELIZER_HB_FILTER_ORDER>),
272  m_workFunction(0),
273  m_mode(mode),
274  m_sse(true)
275 {
276  switch(mode) {
277  case ModeCenter:
279  break;
280 
281  case ModeLowerHalf:
283  break;
284 
285  case ModeUpperHalf:
287  break;
288  }
289 }
290 #endif
291 
293 {
294  delete m_filter;
295 }
296 
297 bool DownChannelizer::signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const
298 {
299  //qDebug(" testing signal [%f, %f], channel [%f, %f]", sigStart, sigEnd, chanStart, chanEnd);
300  if(sigEnd <= sigStart)
301  return false;
302  if(chanEnd <= chanStart)
303  return false;
304  return (sigStart <= chanStart) && (sigEnd >= chanEnd);
305 }
306 
307 Real DownChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd)
308 {
309  Real sigBw = sigEnd - sigStart;
310  Real rot = sigBw / 4;
311 
312  //qDebug("DownChannelizer::createFilterChain: Signal [%.1f, %.1f] (BW %.1f), Channel [%.1f, %.1f], Rot %.1f", sigStart, sigEnd, sigBw, chanStart, chanEnd, rot);
313 
314  // check if it fits into the left half
315  if(signalContainsChannel(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd))
316  {
317  //qDebug("DownChannelizer::createFilterChain: -> take left half (rotate by +1/4 and decimate by 2)");
319  return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd);
320  }
321 
322  // check if it fits into the right half
323  if(signalContainsChannel(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd))
324  {
325  //qDebug("DownChannelizer::createFilterChain: -> take right half (rotate by -1/4 and decimate by 2)");
327  return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd);
328  }
329 
330  // check if it fits into the center
331  if(signalContainsChannel(sigStart + rot, sigEnd - rot, chanStart, chanEnd))
332  {
333  //qDebug("DownChannelizer::createFilterChain: -> take center half (decimate by 2)");
335  return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd);
336  }
337 
338  Real ofs = ((chanEnd - chanStart) / 2.0 + chanStart) - ((sigEnd - sigStart) / 2.0 + sigStart);
339  //qDebug("DownChannelizer::createFilterChain: -> complete (final BW %.1f, frequency offset %.1f)", sigBw, ofs);
340  return ofs;
341 }
342 
343 void DownChannelizer::setFilterChain(const std::vector<unsigned int>& stageIndexes)
344 {
345  // filters are described from lower to upper level but the chain is constructed the other way round
346  std::vector<unsigned int>::const_reverse_iterator rit = stageIndexes.rbegin();
347 
348  // Each index is a base 3 number with 0 = low, 1 = center, 2 = high
349  // Functions at upper level will convert a number to base 3 to describe the filter chain. Common converting
350  // algorithms will go from LSD to MSD. This explains the reverse order.
351  for (; rit != stageIndexes.rend(); ++rit)
352  {
353  if (*rit == 0) {
355  } else if (*rit == 1) {
357  } else if (*rit == 2) {
359  }
360  }
361 }
362 
364 {
365  for(FilterStages::iterator it = m_filterStages.begin(); it != m_filterStages.end(); ++it)
366  delete *it;
367  m_filterStages.clear();
368 }
369 
371 {
372  qDebug("DownChannelizer::debugFilterChain: %lu stages", m_filterStages.size());
373 
374  for(FilterStages::iterator it = m_filterStages.begin(); it != m_filterStages.end(); ++it)
375  {
376  switch ((*it)->m_mode)
377  {
379  qDebug("DownChannelizer::debugFilterChain: center %s", (*it)->m_sse ? "sse" : "no_sse");
380  break;
382  qDebug("DownChannelizer::debugFilterChain: lower %s", (*it)->m_sse ? "sse" : "no_sse");
383  break;
385  qDebug("DownChannelizer::debugFilterChain: upper %s", (*it)->m_sse ? "sse" : "no_sse");
386  break;
387  default:
388  qDebug("DownChannelizer::debugFilterChain: none %s", (*it)->m_sse ? "sse" : "no_sse");
389  break;
390  }
391  }
392 }
virtual void stop()
void configure(MessageQueue *messageQueue, int sampleRate, int centerFrequency)
void push(Message *message, bool emitSignal=true)
Push message onto queue.
#define DOWNCHANNELIZER_HB_FILTER_ORDER
unsigned int getFilterChainHash() const
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
void inputSampleRateChanged()
SampleVector m_sampleBuffer
bool signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const
int getSampleRate() const
Definition: dspcommands.h:367
static double convertToIndexes(unsigned int log2, unsigned int chainHash, std::vector< unsigned int > &chainIndexes)
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool positiveOnly)=0
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool positiveOnly)
virtual void start()=0
virtual bool handleMessage(const Message &cmd)=0
Processing of a message. Returns true if message has actually been processed.
virtual ~DownChannelizer()
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
FilterStages m_filterStages
IntHalfbandFilterEO< qint32, qint32, DOWNCHANNELIZER_HB_FILTER_ORDER > * m_filter
int getCenterFrequency() const
Definition: dspcommands.h:368
FixReal m_real
Definition: dsptypes.h:64
Real createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd)
virtual bool handleMessage(const Message &cmd)
Processing of a message. Returns true if message has actually been processed.
void set(MessageQueue *messageQueue, unsigned int log2Decim, unsigned int filterChainHash)
static bool match(const Message *message)
Definition: message.cpp:45
virtual void start()
int getSampleRate() const
Definition: dspcommands.h:328
virtual const char * getIdentifier() const
Definition: message.cpp:35
FixReal m_imag
Definition: dsptypes.h:65
void applySetting(unsigned int log2Decim, unsigned int filterChainHash)
BasebandSampleSink * m_sampleSink
Demodulator.
virtual void stop()=0
float Real
Definition: dsptypes.h:42
void setFilterChain(const std::vector< unsigned int > &stageIndexes)
static MsgChannelizerNotification * create(int samplerate, qint64 frequencyOffset)