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.
upchannelizer.cpp
Go to the documentation of this file.
1 // Copyright (C) 2016 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 
20 #include "dsp/upchannelizer.h"
21 #include "dsp/inthalfbandfilter.h"
22 #include "dsp/dspcommands.h"
24 
25 #include <QString>
26 #include <QDebug>
27 
30 
32  m_filterChainSetMode(false),
33  m_sampleSource(sampleSource),
34  m_outputSampleRate(0),
35  m_requestedInputSampleRate(0),
36  m_requestedCenterFrequency(0),
37  m_currentInputSampleRate(0),
38  m_currentCenterFrequency(0)
39 {
40  QString name = "UpChannelizer(" + m_sampleSource->objectName() + ")";
41  setObjectName(name);
42 }
43 
45 {
47 }
48 
49 void UpChannelizer::configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency)
50 {
51  Message* cmd = new DSPConfigureChannelizer(sampleRate, centerFrequency);
52  messageQueue->push(cmd);
53 }
54 
55 void UpChannelizer::set(MessageQueue* messageQueue, unsigned int log2Interp, unsigned int filterChainHash)
56 {
57  Message* cmd = new MsgSetChannelizer(log2Interp, filterChainHash);
58  messageQueue->push(cmd);
59 }
60 
62 {
63  if(m_sampleSource == 0) {
64  m_sampleBuffer.clear();
65  return;
66  }
67 
68  if (m_filterStages.size() == 0) // optimization when no downsampling is done anyway
69  {
70  m_sampleSource->pull(sample);
71  }
72  else
73  {
74  m_mutex.lock();
75 
76  FilterStages::iterator stage = m_filterStages.begin();
77  std::vector<Sample>::iterator stageSample = m_stageSamples.begin();
78 
79  for (; stage != m_filterStages.end(); ++stage, ++stageSample)
80  {
81  if(stage == m_filterStages.end() - 1)
82  {
83  if ((*stage)->work(&m_sampleIn, &(*stageSample)))
84  {
85  m_sampleSource->pull(m_sampleIn); // get new input sample
86  }
87  }
88  else
89  {
90  if (!(*stage)->work(&(*(stageSample+1)), &(*stageSample)))
91  {
92  break;
93  }
94  }
95  }
96 
97  sample = *m_stageSamples.begin();
98 
99 // for (; stage != m_filterStages.end(); ++stage)
100 // {
101 // // let's make it work for one stage only (96 kS/s < SR < 192 kS/s)
102 // if(stage == m_filterStages.end() - 1)
103 // {
104 // if ((*stage)->work(&m_sampleIn, &sample))
105 // {
106 // m_sampleSource->pull(m_sampleIn); // get new input sample
107 // }
108 // }
109 // }
110 
111  m_mutex.unlock();
112  }
113 }
114 
116 {
117  if (m_sampleSource != 0)
118  {
119  qDebug() << "UpChannelizer::start: thread: " << thread()
120  << " m_outputSampleRate: " << m_outputSampleRate
121  << " m_requestedInputSampleRate: " << m_requestedInputSampleRate
122  << " m_requestedCenterFrequency: " << m_requestedCenterFrequency;
124  }
125 }
126 
128 {
129  if(m_sampleSource != 0)
130  m_sampleSource->stop();
131 }
132 
134 {
135  qDebug() << "UpChannelizer::handleMessage: " << cmd.getIdentifier();
136 
137  // TODO: apply changes only if input sample rate or requested output sample rate change. Change of center frequency has no impact.
138 
140  {
143  qDebug() << "UpChannelizer::handleMessage: DSPSignalNotification: m_outputSampleRate: " << m_outputSampleRate;
144 
145  if (!m_filterChainSetMode) {
147  }
148 
149  if (m_sampleSource != 0)
150  {
151  DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy
153  }
154 
156  return true;
157  }
158  else if (DSPConfigureChannelizer::match(cmd))
159  {
163 
164  qDebug() << "UpChannelizer::handleMessage: DSPConfigureChannelizer:"
165  << " m_requestedInputSampleRate: " << m_requestedInputSampleRate
166  << " m_requestedCenterFrequency: " << m_requestedCenterFrequency;
167 
169 
170  return true;
171  }
172  else if (MsgSetChannelizer::match(cmd))
173  {
174  MsgSetChannelizer& chan = (MsgSetChannelizer&) cmd;
175  qDebug() << "UpChannelizer::handleMessage: MsgSetChannelizer";
177 
178  return true;
179  }
180  else
181  {
182  return false;
183 // if (m_sampleSource != 0)
184 // {
185 // return m_sampleSource->handleMessage(cmd);
186 // }
187 // else
188 // {
189 // return false;
190 // }
191  }
192 }
193 
195 {
196  m_filterChainSetMode = false;
197 
198  if (m_outputSampleRate == 0)
199  {
200  qDebug() << "UpChannelizer::applyConfiguration: aborting (out=0):"
201  << " out =" << m_outputSampleRate
202  << ", req =" << m_requestedInputSampleRate
203  << ", in =" << m_currentInputSampleRate
204  << ", fc =" << m_currentCenterFrequency;
205  return;
206  }
207 
208 
209  m_mutex.lock();
210 
211  freeFilterChain();
212 
216 
217  m_mutex.unlock();
218 
220 
221  qDebug() << "UpChannelizer::applyConfiguration:"
222  << " out=" << m_outputSampleRate
223  << ", req=" << m_requestedInputSampleRate
224  << ", in=" << m_currentInputSampleRate
225  << ", fc=" << m_currentCenterFrequency;
226 
227  if (m_sampleSource != 0)
228  {
231  }
232 }
233 
234 void UpChannelizer::applySetting(unsigned int log2Interp, unsigned int filterChainHash)
235 {
236  m_filterChainSetMode = true;
237  std::vector<unsigned int> stageIndexes;
238  m_currentCenterFrequency = m_outputSampleRate * HBFilterChainConverter::convertToIndexes(log2Interp, filterChainHash, stageIndexes);
240 
241  m_mutex.lock();
242  freeFilterChain();
244  m_mutex.unlock();
245 
248 
249  qDebug() << "UpChannelizer::applySetting in=" << m_outputSampleRate
250  << ", out=" << m_currentInputSampleRate
251  << ", fc=" << m_currentCenterFrequency;
252 
253  if (m_sampleSource != 0)
254  {
257  }
258 }
259 
260 #ifdef USE_SSE4_1
263  m_workFunction(0)
264 {
265  switch(mode) {
266  case ModeCenter:
268  break;
269 
270  case ModeLowerHalf:
272  break;
273 
274  case ModeUpperHalf:
276  break;
277  }
278 }
279 #else
281  m_filter(new IntHalfbandFilterDB<qint32, UPCHANNELIZER_HB_FILTER_ORDER>),
282  m_workFunction(0)
283 {
284  switch(mode) {
285  case ModeCenter:
287  break;
288 
289  case ModeLowerHalf:
291  break;
292 
293  case ModeUpperHalf:
295  break;
296  }
297 }
298 #endif
299 
301 {
302  delete m_filter;
303 }
304 
305 bool UpChannelizer::signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const
306 {
307  //qDebug(" testing signal [%f, %f], channel [%f, %f]", sigStart, sigEnd, chanStart, chanEnd);
308  if(sigEnd <= sigStart)
309  return false;
310  if(chanEnd <= chanStart)
311  return false;
312  return (sigStart <= chanStart) && (sigEnd >= chanEnd);
313 }
314 
315 Real UpChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd)
316 {
317  Real sigBw = sigEnd - sigStart;
318  Real rot = sigBw / 4;
319  Sample s;
320 
321  qDebug() << "UpChannelizer::createFilterChain: start:"
322  << " sig: [" << sigStart << ":" << sigEnd << "]"
323  << " BW: " << sigBw
324  << " chan: [" << chanStart << ":" << chanEnd << "]"
325  << " rot: " << rot;
326 
327  // check if it fits into the left half
328  if(signalContainsChannel(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd))
329  {
330  qDebug() << "UpChannelizer::createFilterChain: take left half (rotate by +1/4 and decimate by 2):"
331  << " [" << m_filterStages.size() << "]"
332  << " sig: [" << sigStart << ":" << sigStart + sigBw / 2.0 << "]";
334  m_stageSamples.push_back(s);
335  return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd);
336  }
337 
338  // check if it fits into the right half
339  if(signalContainsChannel(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd))
340  {
341  qDebug() << "UpChannelizer::createFilterChain: take right half (rotate by -1/4 and decimate by 2):"
342  << " [" << m_filterStages.size() << "]"
343  << " sig: [" << sigEnd - sigBw / 2.0f << ":" << sigEnd << "]";
345  m_stageSamples.push_back(s);
346  return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd);
347  }
348 
349  // check if it fits into the center
350  // Was: if(signalContainsChannel(sigStart + rot + safetyMargin, sigStart + rot + sigBw / 2.0f - safetyMargin, chanStart, chanEnd)) {
351  if(signalContainsChannel(sigStart + rot, sigEnd - rot, chanStart, chanEnd))
352  {
353  qDebug() << "UpChannelizer::createFilterChain: take center half (decimate by 2):"
354  << " [" << m_filterStages.size() << "]"
355  << " sig: [" << sigStart + rot << ":" << sigEnd - rot << "]";
357  m_stageSamples.push_back(s);
358  // Was: return createFilterChain(sigStart + rot, sigStart + sigBw / 2.0f + rot, chanStart, chanEnd);
359  return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd);
360  }
361 
362  Real ofs = ((chanEnd - chanStart) / 2.0 + chanStart) - ((sigEnd - sigStart) / 2.0 + sigStart);
363 
364  qDebug() << "UpChannelizer::createFilterChain: complete:"
365  << " #stages: " << m_filterStages.size()
366  << " BW: " << sigBw
367  << " ofs: " << ofs;
368 
369  return ofs;
370 }
371 
372 double UpChannelizer::setFilterChain(const std::vector<unsigned int>& stageIndexes)
373 {
374  // filters are described from lower to upper level but the chain is constructed the other way round
375  std::vector<unsigned int>::const_reverse_iterator rit = stageIndexes.rbegin();
376  double ofs = 0.0, ofs_stage = 0.25;
377  Sample s;
378 
379  // Each index is a base 3 number with 0 = low, 1 = center, 2 = high
380  // Functions at upper level will convert a number to base 3 to describe the filter chain. Common converting
381  // algorithms will go from LSD to MSD. This explains the reverse order.
382  for (; rit != stageIndexes.rend(); ++rit)
383  {
384  if (*rit == 0)
385  {
387  m_stageSamples.push_back(s);
388  ofs -= ofs_stage;
389  }
390  else if (*rit == 1)
391  {
393  m_stageSamples.push_back(s);
394  }
395  else if (*rit == 2)
396  {
398  m_stageSamples.push_back(s);
399  ofs += ofs_stage;
400  }
401 
402  ofs_stage /= 2;
403  }
404 
405  return ofs;
406 }
407 
409 {
410  for(FilterStages::iterator it = m_filterStages.begin(); it != m_filterStages.end(); ++it)
411  delete *it;
412  m_filterStages.clear();
413  m_stageSamples.clear();
414 }
415 
416 
417 
418 
FilterStages m_filterStages
virtual void pull(Sample &sample)
void push(Message *message, bool emitSignal=true)
Push message onto queue.
double setFilterChain(const std::vector< unsigned int > &stageIndexes)
returns offset in ratio of sample rate
unsigned int getFilterChainHash() const
Definition: upchannelizer.h:77
int m_requestedInputSampleRate
int m_currentCenterFrequency
int getSampleRate() const
Definition: dspcommands.h:367
BasebandSampleSource * m_sampleSource
Modulator.
static double convertToIndexes(unsigned int log2, unsigned int chainHash, std::vector< unsigned int > &chainIndexes)
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
IntHalfbandFilterDB< qint32, UPCHANNELIZER_HB_FILTER_ORDER > * m_filter
unsigned int getLog2Interp() const
Definition: upchannelizer.h:76
virtual void stop()=0
Real createFilterChain(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd)
void set(MessageQueue *messageQueue, unsigned int log2Interp, unsigned int filterChainHash)
virtual void start()=0
static MsgChannelizerNotification * create(int basebandSampleRate, int samplerate, qint64 frequencyOffset)
Definition: upchannelizer.h:55
void applySetting(unsigned int log2Decim, unsigned int filterChainHash)
void outputSampleRateChanged()
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
virtual void pull(Sample &sample)=0
int getCenterFrequency() const
Definition: dspcommands.h:368
virtual ~UpChannelizer()
void freeFilterChain()
static bool match(const Message *message)
Definition: message.cpp:45
SampleVector m_sampleBuffer
virtual bool handleMessage(const Message &cmd)
Processing of a message. Returns true if message has actually been processed.
bool m_filterChainSetMode
int m_requestedCenterFrequency
int m_currentInputSampleRate
bool signalContainsChannel(Real sigStart, Real sigEnd, Real chanStart, Real chanEnd) const
int getSampleRate() const
Definition: dspcommands.h:328
virtual const char * getIdentifier() const
Definition: message.cpp:35
void applyConfiguration()
virtual void start()
#define UPCHANNELIZER_HB_FILTER_ORDER
Definition: upchannelizer.h:33
float Real
Definition: dsptypes.h:42
virtual void stop()
std::vector< Sample > m_stageSamples
void configure(MessageQueue *messageQueue, int sampleRate, int centerFrequency)