| 
									
										
										
										
											2020-12-20 01:53:03 +01:00
										 |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // Copyright (C) 2020 Edouard Griffiths, F4EXB                                   //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // This program is free software; you can redistribute it and/or modify          //
 | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by          //
 | 
					
						
							|  |  |  | // the Free Software Foundation as version 3 of the License, or                  //
 | 
					
						
							|  |  |  | // (at your option) any later version.                                           //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful,               //
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | 
					
						
							|  |  |  | // GNU General Public License V3 for more details.                               //
 | 
					
						
							|  |  |  | //                                                                               //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU General Public License             //
 | 
					
						
							|  |  |  | // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef INCLUDE_DEMODALYZERWORKER_H
 | 
					
						
							|  |  |  | #define INCLUDE_DEMODALYZERWORKER_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-20 11:51:38 +01:00
										 |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-20 01:53:03 +01:00
										 |  |  | #include <QObject>
 | 
					
						
							|  |  |  | #include <QMutex>
 | 
					
						
							|  |  |  | #include <QByteArray>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "dsp/dsptypes.h"
 | 
					
						
							| 
									
										
										
										
											2020-12-20 11:51:38 +01:00
										 |  |  | #include "dsp/decimators.h"
 | 
					
						
							| 
									
										
										
										
											2021-06-30 19:40:04 +02:00
										 |  |  | #include "dsp/datafifo.h"
 | 
					
						
							| 
									
										
										
										
											2020-12-20 01:53:03 +01:00
										 |  |  | #include "util/movingaverage.h"
 | 
					
						
							|  |  |  | #include "util/message.h"
 | 
					
						
							|  |  |  | #include "util/messagequeue.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "demodanalyzersettings.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BasebandSampleSink; | 
					
						
							| 
									
										
										
										
											2021-06-05 19:26:26 +02:00
										 |  |  | class ScopeVis; | 
					
						
							| 
									
										
										
										
											2020-12-20 01:53:03 +01:00
										 |  |  | class ChannelAPI; | 
					
						
							|  |  |  | class Feature; | 
					
						
							|  |  |  | class DemodAnalyzerWorker : public QObject { | 
					
						
							|  |  |  |     Q_OBJECT | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     class MsgConfigureDemodAnalyzerWorker : public Message { | 
					
						
							|  |  |  |         MESSAGE_CLASS_DECLARATION | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         const DemodAnalyzerSettings& getSettings() const { return m_settings; } | 
					
						
							|  |  |  |         bool getForce() const { return m_force; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         static MsgConfigureDemodAnalyzerWorker* create(const DemodAnalyzerSettings& settings, bool force) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             return new MsgConfigureDemodAnalyzerWorker(settings, force); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private: | 
					
						
							|  |  |  |         DemodAnalyzerSettings m_settings; | 
					
						
							|  |  |  |         bool m_force; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         MsgConfigureDemodAnalyzerWorker(const DemodAnalyzerSettings& settings, bool force) : | 
					
						
							|  |  |  |             Message(), | 
					
						
							|  |  |  |             m_settings(settings), | 
					
						
							|  |  |  |             m_force(force) | 
					
						
							|  |  |  |         { } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class MsgConnectFifo : public Message { | 
					
						
							|  |  |  |         MESSAGE_CLASS_DECLARATION | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         DataFifo *getFifo() { return m_fifo; } | 
					
						
							|  |  |  |         bool getConnect() const { return m_connect; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         static MsgConnectFifo* create(DataFifo *fifo, bool connect) { | 
					
						
							|  |  |  |             return new MsgConnectFifo(fifo, connect); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     private: | 
					
						
							|  |  |  |         DataFifo *m_fifo; | 
					
						
							|  |  |  |         bool m_connect; | 
					
						
							|  |  |  |         MsgConnectFifo(DataFifo *fifo, bool connect) : | 
					
						
							|  |  |  |             Message(), | 
					
						
							|  |  |  |             m_fifo(fifo), | 
					
						
							|  |  |  |             m_connect(connect) | 
					
						
							|  |  |  |         { } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     DemodAnalyzerWorker(); | 
					
						
							|  |  |  | 	~DemodAnalyzerWorker(); | 
					
						
							|  |  |  |     void reset(); | 
					
						
							|  |  |  |     bool startWork(); | 
					
						
							|  |  |  |     void stopWork(); | 
					
						
							|  |  |  |     bool isRunning() const { return m_running; } | 
					
						
							|  |  |  |     MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } | 
					
						
							|  |  |  |     void setMessageQueueToFeature(MessageQueue *messageQueue) { m_msgQueueToFeature = messageQueue; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-30 19:40:04 +02:00
										 |  |  |     void feedPart( | 
					
						
							|  |  |  |         const QByteArray::const_iterator& begin, | 
					
						
							|  |  |  |         const QByteArray::const_iterator& end, | 
					
						
							|  |  |  |         DataFifo::DataType dataType | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2020-12-20 01:53:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     void applySampleRate(int sampleRate); | 
					
						
							|  |  |  | 	void applySettings(const DemodAnalyzerSettings& settings, bool force = false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	double getMagSq() const { return m_magsq; } | 
					
						
							|  |  |  | 	double getMagSqAvg() const { return (double) m_channelPowerAvg; } | 
					
						
							| 
									
										
										
										
											2021-06-05 19:26:26 +02:00
										 |  |  |     void setScopeVis(ScopeVis* scopeVis) { m_scopeVis = scopeVis; } | 
					
						
							| 
									
										
										
										
											2020-12-20 01:53:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     static const unsigned int m_corrFFTLen; | 
					
						
							|  |  |  |     static const unsigned int m_ssbFftLen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     DataFifo *m_dataFifo; | 
					
						
							|  |  |  |     int m_channelSampleRate; | 
					
						
							|  |  |  |     int m_sinkSampleRate; | 
					
						
							|  |  |  | 	MessageQueue m_inputMessageQueue;  //!< Queue for asynchronous inbound communication
 | 
					
						
							|  |  |  |     MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object
 | 
					
						
							|  |  |  |     DemodAnalyzerSettings m_settings; | 
					
						
							|  |  |  | 	double m_magsq; | 
					
						
							|  |  |  | 	SampleVector m_sampleBuffer; | 
					
						
							| 
									
										
										
										
											2020-12-20 11:51:38 +01:00
										 |  |  |     std::vector<qint16> m_convBuffer; | 
					
						
							|  |  |  |     Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16, true> m_decimators; | 
					
						
							| 
									
										
										
										
											2020-12-20 01:53:03 +01:00
										 |  |  |     int m_sampleBufferSize; | 
					
						
							|  |  |  | 	MovingAverageUtil<double, double, 480> m_channelPowerAvg; | 
					
						
							| 
									
										
										
										
											2021-06-05 19:26:26 +02:00
										 |  |  |     ScopeVis* m_scopeVis; | 
					
						
							| 
									
										
										
										
											2020-12-20 01:53:03 +01:00
										 |  |  |     bool m_running; | 
					
						
							|  |  |  |     QMutex m_mutex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool handleMessage(const Message& cmd); | 
					
						
							| 
									
										
										
										
											2020-12-20 11:51:38 +01:00
										 |  |  |     void decimate(int countSamples); | 
					
						
							| 
									
										
										
										
											2020-12-20 01:53:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-30 19:40:04 +02:00
										 |  |  |     inline void processSample( | 
					
						
							|  |  |  |         DataFifo::DataType dataType, | 
					
						
							|  |  |  |         const QByteArray::const_iterator& begin, | 
					
						
							|  |  |  |         int countSamples, | 
					
						
							|  |  |  |         int i | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         switch(dataType) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             case DataFifo::DataTypeI16: { | 
					
						
							|  |  |  |                 int16_t *s = (int16_t*) begin; | 
					
						
							|  |  |  |                 double re = s[i] / (double) std::numeric_limits<int16_t>::max(); | 
					
						
							|  |  |  |                 m_magsq = re*re; | 
					
						
							|  |  |  |                 m_channelPowerAvg(m_magsq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (m_settings.m_log2Decim == 0) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     m_sampleBuffer[i].setReal(re * SDR_RX_SCALEF); | 
					
						
							|  |  |  |                     m_sampleBuffer[i].setImag(0); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     m_convBuffer[2*i] = s[i]; | 
					
						
							|  |  |  |                     m_convBuffer[2*i+1] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if (i == countSamples - 1) { | 
					
						
							|  |  |  |                         decimate(countSamples); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |             case DataFifo::DataTypeCI16: { | 
					
						
							|  |  |  |                 int16_t *s = (int16_t*) begin; | 
					
						
							|  |  |  |                 double re = s[2*i]   / (double) std::numeric_limits<int16_t>::max(); | 
					
						
							|  |  |  |                 double im = s[2*i+1] / (double) std::numeric_limits<int16_t>::max(); | 
					
						
							|  |  |  |                 m_magsq = re*re + im*im; | 
					
						
							|  |  |  |                 m_channelPowerAvg(m_magsq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (m_settings.m_log2Decim == 0) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     m_sampleBuffer[i].setReal(re * SDR_RX_SCALEF); | 
					
						
							|  |  |  |                     m_sampleBuffer[i].setImag(im * SDR_RX_SCALEF); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     m_convBuffer[2*i]   = s[2*i]; | 
					
						
							|  |  |  |                     m_convBuffer[2*i+1] = s[2*i+1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if (i == countSamples - 1) { | 
					
						
							|  |  |  |                         decimate(countSamples); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-20 01:53:03 +01:00
										 |  |  | private slots: | 
					
						
							|  |  |  |     void handleInputMessages(); | 
					
						
							|  |  |  |     void handleData(); //!< Handle data when samples have to be processed
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif // INCLUDE_DEMODALYZERWORKER_H
 |