diff --git a/plugins/channelrx/chanalyzerng/chanalyzerng.cpp b/plugins/channelrx/chanalyzerng/chanalyzerng.cpp index 5e6e8a7c8..63994c9c0 100644 --- a/plugins/channelrx/chanalyzerng/chanalyzerng.cpp +++ b/plugins/channelrx/chanalyzerng/chanalyzerng.cpp @@ -1,279 +1,280 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 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 // -// // -// 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 . // -/////////////////////////////////////////////////////////////////////////////////// - -#include "chanalyzerng.h" - -#include -#include -#include - -#include "device/devicesourceapi.h" -#include "audio/audiooutput.h" -#include "dsp/threadedbasebandsamplesink.h" -#include "dsp/downchannelizer.h" - -MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelAnalyzer, Message) -MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelizer, Message) -MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgReportChannelSampleRateChanged, Message) - -const QString ChannelAnalyzerNG::m_channelIdURI = "sdrangel.channel.chanalyzerng"; -const QString ChannelAnalyzerNG::m_channelId = "ChannelAnalyzerNG"; - -ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) : - ChannelSinkAPI(m_channelIdURI), - m_deviceAPI(deviceAPI), - m_sampleSink(0), - m_settingsMutex(QMutex::Recursive) -{ - setObjectName(m_channelId); - - m_undersampleCount = 0; - m_sum = 0; - m_usb = true; - m_magsq = 0; - m_useInterpolator = false; - m_interpolatorDistance = 1.0f; - m_interpolatorDistanceRemain = 0.0f; - SSBFilter = new fftfilt(m_config.m_LowCutoff / m_config.m_inputSampleRate, m_config.m_Bandwidth / m_config.m_inputSampleRate, ssbFftLen); - DSBFilter = new fftfilt(m_config.m_Bandwidth / m_config.m_inputSampleRate, 2*ssbFftLen); - m_pll.computeCoefficients(0.05f, 0.707f, 1000.0f); // bandwidth, damping factor, loop gain - - apply(true); - - m_channelizer = new DownChannelizer(this); - m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); - m_deviceAPI->addThreadedSink(m_threadedChannelizer); - m_deviceAPI->addChannelAPI(this); -} - -ChannelAnalyzerNG::~ChannelAnalyzerNG() -{ - m_deviceAPI->removeChannelAPI(this); - m_deviceAPI->removeThreadedSink(m_threadedChannelizer); - delete m_threadedChannelizer; - delete m_channelizer; - delete SSBFilter; - delete DSBFilter; -} - -void ChannelAnalyzerNG::configure(MessageQueue* messageQueue, - int channelSampleRate, - Real Bandwidth, - Real LowCutoff, - int spanLog2, - bool ssb, - bool pll, - unsigned int pllPskOrder) -{ - Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb, pll, pllPskOrder); - messageQueue->push(cmd); -} - -void ChannelAnalyzerNG::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly __attribute__((unused))) -{ - fftfilt::cmplx *sideband = 0; - Complex ci; - - m_settingsMutex.lock(); - - for(SampleVector::const_iterator it = begin; it < end; ++it) - { - Complex c(it->real(), it->imag()); - c *= m_nco.nextIQ(); - - if (m_useInterpolator) - { - if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci)) - { - processOneSample(ci, sideband); - m_interpolatorDistanceRemain += m_interpolatorDistance; - } - } - else - { - processOneSample(c, sideband); - } - } - - if(m_sampleSink != 0) - { - m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_running.m_ssb); // m_ssb = positive only - } - - m_sampleBuffer.clear(); - - m_settingsMutex.unlock(); -} - -void ChannelAnalyzerNG::start() -{ -} - -void ChannelAnalyzerNG::stop() -{ -} - -bool ChannelAnalyzerNG::handleMessage(const Message& cmd) -{ - qDebug() << "ChannelAnalyzerNG::handleMessage: " << cmd.getIdentifier(); - - if (DownChannelizer::MsgChannelizerNotification::match(cmd)) - { - DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; - - m_config.m_inputSampleRate = notif.getSampleRate(); - m_config.m_frequency = notif.getFrequencyOffset(); - - qDebug() << "ChannelAnalyzerNG::handleMessage: MsgChannelizerNotification:" - << " m_sampleRate: " << m_config.m_inputSampleRate - << " frequencyOffset: " << m_config.m_frequency; - - apply(); - - if (getMessageQueueToGUI()) - { - MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create(); - getMessageQueueToGUI()->push(msg); - } - - return true; - } - else if (MsgConfigureChannelizer::match(cmd)) - { - MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; - m_channelizer->configure(m_channelizer->getInputMessageQueue(), - cfg.getSampleRate(), - cfg.getCenterFrequency()); - return true; - } - else if (MsgConfigureChannelAnalyzer::match(cmd)) - { - MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd; - - m_config.m_channelSampleRate = cfg.getChannelSampleRate(); - m_config.m_Bandwidth = cfg.getBandwidth(); - m_config.m_LowCutoff = cfg.getLoCutoff(); - m_config.m_spanLog2 = cfg.getSpanLog2(); - m_config.m_ssb = cfg.getSSB(); - m_config.m_pll = cfg.getPLL(); - m_config.m_pllPskOrder = cfg.getPLLPSKOrder(); - - qDebug() << "ChannelAnalyzerNG::handleMessage: MsgConfigureChannelAnalyzer:" - << " m_channelSampleRate: " << m_config.m_channelSampleRate - << " m_Bandwidth: " << m_config.m_Bandwidth - << " m_LowCutoff: " << m_config.m_LowCutoff - << " m_spanLog2: " << m_config.m_spanLog2 - << " m_ssb: " << m_config.m_ssb - << " m_pll: " << m_config.m_pll - << " m_pllPskOrder: " << m_config.m_pllPskOrder; - - apply(); - return true; - } - else - { - if (m_sampleSink != 0) - { - return m_sampleSink->handleMessage(cmd); - } - else - { - return false; - } - } -} - - - -void ChannelAnalyzerNG::apply(bool force) -{ - if ((m_running.m_frequency != m_config.m_frequency) || - (m_running.m_inputSampleRate != m_config.m_inputSampleRate) || - force) - { - m_nco.setFreq(-m_config.m_frequency, m_config.m_inputSampleRate); - } - - if ((m_running.m_inputSampleRate != m_config.m_inputSampleRate) || - (m_running.m_channelSampleRate != m_config.m_channelSampleRate) || - force) - { - m_settingsMutex.lock(); - m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_inputSampleRate / 2.2); - m_interpolatorDistanceRemain = 0.0f; - m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_channelSampleRate; - m_useInterpolator = (m_config.m_inputSampleRate != m_config.m_channelSampleRate); // optim - m_settingsMutex.unlock(); - } - - if ((m_running.m_channelSampleRate != m_config.m_channelSampleRate) || - (m_running.m_Bandwidth != m_config.m_Bandwidth) || - (m_running.m_LowCutoff != m_config.m_LowCutoff) || - force) - { - float bandwidth = m_config.m_Bandwidth; - float lowCutoff = m_config.m_LowCutoff; - - if (bandwidth < 0) - { - bandwidth = -bandwidth; - lowCutoff = -lowCutoff; - m_usb = false; - } - else - { - m_usb = true; - } - - if (bandwidth < 100.0f) - { - bandwidth = 100.0f; - lowCutoff = 0; - } - - m_settingsMutex.lock(); - - SSBFilter->create_filter(lowCutoff / m_config.m_channelSampleRate, bandwidth / m_config.m_channelSampleRate); - DSBFilter->create_dsb_filter(bandwidth / m_config.m_channelSampleRate); - - m_settingsMutex.unlock(); - } - - if (m_running.m_pll != m_config.m_pll || force) - { - if (m_config.m_pll) { - m_pll.reset(); - } - } - - if (m_running.m_pll != m_config.m_pll || force) - { - m_pll.setPskOrder(m_config.m_pllPskOrder); - } - - m_running.m_frequency = m_config.m_frequency; - m_running.m_channelSampleRate = m_config.m_channelSampleRate; - m_running.m_inputSampleRate = m_config.m_inputSampleRate; - m_running.m_Bandwidth = m_config.m_Bandwidth; - m_running.m_LowCutoff = m_config.m_LowCutoff; - - //m_settingsMutex.lock(); - m_running.m_spanLog2 = m_config.m_spanLog2; - m_running.m_ssb = m_config.m_ssb; - m_running.m_pll = m_config.m_pll; - m_running.m_pllPskOrder = m_config.m_pllPskOrder; - //m_settingsMutex.unlock(); -} +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "chanalyzerng.h" + +#include +#include +#include + +#include "device/devicesourceapi.h" +#include "audio/audiooutput.h" +#include "dsp/threadedbasebandsamplesink.h" +#include "dsp/downchannelizer.h" + +MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelAnalyzer, Message) +MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelizer, Message) +MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgReportChannelSampleRateChanged, Message) + +const QString ChannelAnalyzerNG::m_channelIdURI = "sdrangel.channel.chanalyzerng"; +const QString ChannelAnalyzerNG::m_channelId = "ChannelAnalyzerNG"; + +ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) : + ChannelSinkAPI(m_channelIdURI), + m_deviceAPI(deviceAPI), + m_sampleSink(0), + m_settingsMutex(QMutex::Recursive) +{ + setObjectName(m_channelId); + + m_undersampleCount = 0; + m_sum = 0; + m_usb = true; + m_magsq = 0; + m_useInterpolator = false; + m_interpolatorDistance = 1.0f; + m_interpolatorDistanceRemain = 0.0f; + SSBFilter = new fftfilt(m_config.m_LowCutoff / m_config.m_inputSampleRate, m_config.m_Bandwidth / m_config.m_inputSampleRate, ssbFftLen); + DSBFilter = new fftfilt(m_config.m_Bandwidth / m_config.m_inputSampleRate, 2*ssbFftLen); + //m_pll.computeCoefficients(0.05f, 0.707f, 1000.0f); // bandwidth, damping factor, loop gain + m_pll.computeCoefficients(0.002f, 0.5f, 10.0f); // bandwidth, damping factor, loop gain + + apply(true); + + m_channelizer = new DownChannelizer(this); + m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); + m_deviceAPI->addThreadedSink(m_threadedChannelizer); + m_deviceAPI->addChannelAPI(this); +} + +ChannelAnalyzerNG::~ChannelAnalyzerNG() +{ + m_deviceAPI->removeChannelAPI(this); + m_deviceAPI->removeThreadedSink(m_threadedChannelizer); + delete m_threadedChannelizer; + delete m_channelizer; + delete SSBFilter; + delete DSBFilter; +} + +void ChannelAnalyzerNG::configure(MessageQueue* messageQueue, + int channelSampleRate, + Real Bandwidth, + Real LowCutoff, + int spanLog2, + bool ssb, + bool pll, + unsigned int pllPskOrder) +{ + Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb, pll, pllPskOrder); + messageQueue->push(cmd); +} + +void ChannelAnalyzerNG::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly __attribute__((unused))) +{ + fftfilt::cmplx *sideband = 0; + Complex ci; + + m_settingsMutex.lock(); + + for(SampleVector::const_iterator it = begin; it < end; ++it) + { + Complex c(it->real(), it->imag()); + c *= m_nco.nextIQ(); + + if (m_useInterpolator) + { + if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci)) + { + processOneSample(ci, sideband); + m_interpolatorDistanceRemain += m_interpolatorDistance; + } + } + else + { + processOneSample(c, sideband); + } + } + + if(m_sampleSink != 0) + { + m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_running.m_ssb); // m_ssb = positive only + } + + m_sampleBuffer.clear(); + + m_settingsMutex.unlock(); +} + +void ChannelAnalyzerNG::start() +{ +} + +void ChannelAnalyzerNG::stop() +{ +} + +bool ChannelAnalyzerNG::handleMessage(const Message& cmd) +{ + qDebug() << "ChannelAnalyzerNG::handleMessage: " << cmd.getIdentifier(); + + if (DownChannelizer::MsgChannelizerNotification::match(cmd)) + { + DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; + + m_config.m_inputSampleRate = notif.getSampleRate(); + m_config.m_frequency = notif.getFrequencyOffset(); + + qDebug() << "ChannelAnalyzerNG::handleMessage: MsgChannelizerNotification:" + << " m_sampleRate: " << m_config.m_inputSampleRate + << " frequencyOffset: " << m_config.m_frequency; + + apply(); + + if (getMessageQueueToGUI()) + { + MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create(); + getMessageQueueToGUI()->push(msg); + } + + return true; + } + else if (MsgConfigureChannelizer::match(cmd)) + { + MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; + m_channelizer->configure(m_channelizer->getInputMessageQueue(), + cfg.getSampleRate(), + cfg.getCenterFrequency()); + return true; + } + else if (MsgConfigureChannelAnalyzer::match(cmd)) + { + MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd; + + m_config.m_channelSampleRate = cfg.getChannelSampleRate(); + m_config.m_Bandwidth = cfg.getBandwidth(); + m_config.m_LowCutoff = cfg.getLoCutoff(); + m_config.m_spanLog2 = cfg.getSpanLog2(); + m_config.m_ssb = cfg.getSSB(); + m_config.m_pll = cfg.getPLL(); + m_config.m_pllPskOrder = cfg.getPLLPSKOrder(); + + qDebug() << "ChannelAnalyzerNG::handleMessage: MsgConfigureChannelAnalyzer:" + << " m_channelSampleRate: " << m_config.m_channelSampleRate + << " m_Bandwidth: " << m_config.m_Bandwidth + << " m_LowCutoff: " << m_config.m_LowCutoff + << " m_spanLog2: " << m_config.m_spanLog2 + << " m_ssb: " << m_config.m_ssb + << " m_pll: " << m_config.m_pll + << " m_pllPskOrder: " << m_config.m_pllPskOrder; + + apply(); + return true; + } + else + { + if (m_sampleSink != 0) + { + return m_sampleSink->handleMessage(cmd); + } + else + { + return false; + } + } +} + + + +void ChannelAnalyzerNG::apply(bool force) +{ + if ((m_running.m_frequency != m_config.m_frequency) || + (m_running.m_inputSampleRate != m_config.m_inputSampleRate) || + force) + { + m_nco.setFreq(-m_config.m_frequency, m_config.m_inputSampleRate); + } + + if ((m_running.m_inputSampleRate != m_config.m_inputSampleRate) || + (m_running.m_channelSampleRate != m_config.m_channelSampleRate) || + force) + { + m_settingsMutex.lock(); + m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_inputSampleRate / 2.2); + m_interpolatorDistanceRemain = 0.0f; + m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_channelSampleRate; + m_useInterpolator = (m_config.m_inputSampleRate != m_config.m_channelSampleRate); // optim + m_settingsMutex.unlock(); + } + + if ((m_running.m_channelSampleRate != m_config.m_channelSampleRate) || + (m_running.m_Bandwidth != m_config.m_Bandwidth) || + (m_running.m_LowCutoff != m_config.m_LowCutoff) || + force) + { + float bandwidth = m_config.m_Bandwidth; + float lowCutoff = m_config.m_LowCutoff; + + if (bandwidth < 0) + { + bandwidth = -bandwidth; + lowCutoff = -lowCutoff; + m_usb = false; + } + else + { + m_usb = true; + } + + if (bandwidth < 100.0f) + { + bandwidth = 100.0f; + lowCutoff = 0; + } + + m_settingsMutex.lock(); + + SSBFilter->create_filter(lowCutoff / m_config.m_channelSampleRate, bandwidth / m_config.m_channelSampleRate); + DSBFilter->create_dsb_filter(bandwidth / m_config.m_channelSampleRate); + + m_settingsMutex.unlock(); + } + + if (m_running.m_pll != m_config.m_pll || force) + { + if (m_config.m_pll) { + m_pll.reset(); + } + } + + if (m_running.m_pll != m_config.m_pll || force) + { + m_pll.setPskOrder(m_config.m_pllPskOrder); + } + + m_running.m_frequency = m_config.m_frequency; + m_running.m_channelSampleRate = m_config.m_channelSampleRate; + m_running.m_inputSampleRate = m_config.m_inputSampleRate; + m_running.m_Bandwidth = m_config.m_Bandwidth; + m_running.m_LowCutoff = m_config.m_LowCutoff; + + //m_settingsMutex.lock(); + m_running.m_spanLog2 = m_config.m_spanLog2; + m_running.m_ssb = m_config.m_ssb; + m_running.m_pll = m_config.m_pll; + m_running.m_pllPskOrder = m_config.m_pllPskOrder; + //m_settingsMutex.unlock(); +}