cudaSDR/Source/src/QtDSP/qtdsp_dspEngine.cpp

396 lines
8.9 KiB
C++

/**
* @file qtdsp_dspEngine.cpp
* @brief QtDSP DSP engine class
* @author Hermann von Hasseln, DL3HVH
* @version 0.1
* @date 2012-04-07
*/
/*
* Copyright (C) 2007, 2008, 2009, 2010 Philip A Covington, N8VB
*
* adapted for QtDSP by (C) 2012 Hermann von Hasseln, DL3HVH
*
* The ProcessFrequencyShift method is adpated from cuteSDR by (C) Moe Wheatley, AE4JY.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License version 2 as
* published by the Free Software Foundation
*
* 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 for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define LOG_DSP_ENGINE
// use: DSP_ENGINE_DEBUG << "debug message";
#include "qtdsp_dspEngine.h"
double myLog(double x, double base) {
return log(x) / log(base);
}
QDSPEngine::QDSPEngine(QObject *parent, int rx, int size)
: QObject(parent)
, set(Settings::instance())
, m_qtdspOn(false)
, m_rx(rx)
, m_size(size)
, m_samplerate(set->getSampleRate())
, m_fftMultiplier(1)
, m_volume(0.0f)
{
qRegisterMetaType<QVector<cpx> >();
qRegisterMetaType<CPX>();
fft = new QFFT(m_size); // m_size = 1024
filter = new QFilter(this, m_size, 2, 12);//8);
wpagc = new QWPAGC(this, m_size);
//spectrum = new PowerSpectrum(this, m_size*2);
/*QString str = "Initializing DSP engine for rx %1: 8k FFT ...please wait";
set->setSystemMessage(str.arg(m_rx), 0);
if (m_rx == 0) {
spectrum2 = new PowerSpectrum(this, m_size*4);
str = "Initializing DSP engine for rx %1: 16k FFT ...please wait";
set->setSystemMessage(str.arg(m_rx), 0);
spectrum4 = new PowerSpectrum(this, m_size*8);
str = "Initializing DSP engine for rx %1: 32k FFT ...please wait";
set->setSystemMessage(str.arg(m_rx), 0);
spectrum8 = new PowerSpectrum(this, m_size*16);
str = "Initializing DSP engine for rx %1: 64k FFT ...please wait";
set->setSystemMessage(str.arg(m_rx), 0);
spectrum16 = new PowerSpectrum(this, m_size*32);
}*/
int factor = 2;
while (factor <= 128) {
PowerSpectrum* spec = new PowerSpectrum(this, m_size*factor);
powerSpectraList << spec;
factor *= 2;
}
m_spectrumSize = m_size*4;
signalmeter = new SignalMeter(this, m_size);
demod = new Demodulation(this, m_size);
m_rxData = set->getReceiverDataList().at(rx);
m_agcMode = m_rxData.agcMode;
wpagc->setReceiver(m_rx);
InitCPX(tmp1CPX, m_size, 0.0f);
InitCPX(tmp2CPX, m_size, 0.0f);
osc1cpx.re = 1.0f;
osc1cpx.im = 0.0f;
m_NcoInc = 0.0;
m_NcoTime = 0.0;
m_NcoFreq = 0.0;
m_CWoffset = 0.0;
//DSP_ENGINE_DEBUG << "set NCO to " << m_rxData.vfoFrequency - m_rxData.ctrFrequency;
setNCOFrequency(m_rx, m_rxData.vfoFrequency - m_rxData.ctrFrequency);
DSP_ENGINE_DEBUG << "init DSPEngine with size: " << m_size;
SleeperThread::msleep(100);
setupConnections();
}
QDSPEngine::~QDSPEngine() {
tmp1CPX.clear();
tmp2CPX.clear();
//if (agc)
// delete agc;
if (fft)
delete fft;
if (filter)
delete filter;
if (wpagc)
delete wpagc;
//if (spectrum)
// delete spectrum;
if (!powerSpectraList.empty()) {
powerSpectraList.clear();
}
if (signalmeter)
delete signalmeter;
if (demod)
delete demod;
}
void QDSPEngine::setupConnections() {
CHECKED_CONNECT(
set,
SIGNAL(ncoFrequencyChanged(int, long)),
this,
SLOT(setNCOFrequency(int, long)));
CHECKED_CONNECT(
set,
SIGNAL(sampleSizeChanged(int, int)),
this,
SLOT(setSampleSize(int, int)));
CHECKED_CONNECT(
wpagc,
SIGNAL(agcMaximumGainChanged(qreal)),
this,
SLOT(setAGCMaximumGain(qreal)));
CHECKED_CONNECT(
wpagc,
SIGNAL(agcHangThresholdChanged(qreal)),
this,
SLOT(setAGCHangThreshold(qreal)));
// CHECKED_CONNECT(
// wpagc,
// SIGNAL(hangLeveldBLineChanged(qreal)),
// this,
// SLOT(setAGCHangLeveldBLine(qreal)));
//
// CHECKED_CONNECT(
// wpagc,
// SIGNAL(minimumVoltageChanged(QObject *, int, qreal)),
// this,
// SLOT(setAGCThresholdLine(QObject *, int, qreal)));
CHECKED_CONNECT(
wpagc,
SIGNAL(displayValues(QObject *, int, qreal, qreal)),
this,
SLOT(setAGCLineValues(QObject *, int, qreal, qreal)));
}
void QDSPEngine::processDSP(CPX &in, CPX &out, int size) {
m_mutex.lock();
/*switch (m_fftMultiplcator) {
case 1:
spectrum->ProcessSpectrum(in, size*2, 1);
break;
case 2:
spectrum2->ProcessSpectrum(in, size*4, 3);
break;
case 4:
spectrum4->ProcessSpectrum(in, size*8, 7);
break;
case 8:
spectrum8->ProcessSpectrum(in, size*16, 15);
break;
case 16:
spectrum16->ProcessSpectrum(in, size*32, 31);
break;
}*/
int idx = (int)(myLog(m_fftMultiplier, 2));
powerSpectraList.at(idx)->ProcessSpectrum(in, size * m_fftMultiplier * 2, m_fftMultiplier*2-1);
if (m_NcoFreq != 0)
ProcessFrequencyShift(in, in, size);
filter->ProcessFilter(in, tmp1CPX, size);
signalmeter->ProcessBlock(tmp1CPX, size);
wpagc->ProcessAGC(tmp1CPX, tmp2CPX, size);
demod->ProcessBlock(tmp2CPX, out, size);
//memcpy(out.data(), in.data(), size * sizeof(cpx));
//out = in;
for (int i = 0; i < size; i++) {
out[i] = ScaleCPX(out.at(i), m_volume);
}
m_mutex.unlock();
}
int QDSPEngine::getSpectrum(qVectorFloat &buffer, int mult) {
m_fftMultiplier = mult;
int idx = (int)(myLog(m_fftMultiplier, 2));
return powerSpectraList.at(idx)->spectrumResult(buffer, m_size * m_fftMultiplier * 2 - 2048);
}
float QDSPEngine::getSMeterInstValue() {
return signalmeter->getInstFValue();
}
void QDSPEngine::setVolume(float value) {
if (m_volume == value) return;
m_volume = value;
}
void QDSPEngine::setQtDSPStatus(bool value) {
m_qtdspOn = value;
}
void QDSPEngine::setDSPMode(DSPMode mode) {
demod->setDemodMode(mode);
}
void QDSPEngine::setAGCMode(AGCMode mode) {
wpagc->setMode(mode);
}
void QDSPEngine::setAGCMaximumGain(qreal value) {
qreal maxGain = 20.0 * log10(value);
set->setAGCMaximumGain_dB(this, m_rx, maxGain);
}
void QDSPEngine::setAGCHangThreshold(qreal value) {
set->setAGCHangThresholdSlider(this, m_rx, value);
}
void QDSPEngine::setAGCLineValues(QObject *sender, int rx, qreal thresh, qreal hang) {
if (m_rx != rx) return;
qreal noiseOffset = 10.0 * log10(qAbs(filter->filterHi() - filter->filterLo()) * 2 * m_size / m_samplerate);
qreal threshold = 20.0 * log10(thresh) - noiseOffset + AGCOFFSET;
set->setAGCLineLevels(sender, m_rx, threshold, hang + AGCOFFSET);
}
void QDSPEngine::setSampleRate(QObject *sender, int value) {
Q_UNUSED(sender)
if (m_samplerate == value) return;
m_mutex.lock();
switch (value) {
case 48000:
m_samplerate = value;
break;
case 96000:
m_samplerate = value;
break;
case 192000:
m_samplerate = value;
break;
case 384000:
m_samplerate = value;
break;
default:
DSP_ENGINE_DEBUG << "invalid sample rate (possible values are: 48, 96, 192, or 384 kHz)!\n";
break;
}
//DSP_ENGINE_DEBUG << "set sample rate to " << m_samplerate;
//setNCOFrequency(m_rx, m_rxData.vfoFrequency - m_rxData.ctrFrequency);
m_NcoInc = TWOPI * m_NcoFreq/m_samplerate;
m_OscCos = qCos(m_NcoInc);
m_OscSin = qSin(m_NcoInc);
filter->setSampleRate(this, m_samplerate);
demod->setSampleRate(this, m_samplerate);
wpagc->setSampleRate(this, m_samplerate);
m_mutex.unlock();
}
void QDSPEngine::setNCOFrequency(int rx, long ncoFreq) {
if (m_rx != rx) return;
qreal tmp = ncoFreq + m_CWoffset;
m_NcoFreq = tmp;
m_NcoInc = TWOPI * m_NcoFreq/m_samplerate;
m_OscCos = qCos(m_NcoInc);
m_OscSin = qSin(m_NcoInc);
//DSP_ENGINE_DEBUG << "NCO: " << m_NcoFreq;
}
void QDSPEngine::setSampleSize(int rx, int size) {
if (m_rx == rx) {
m_mutex.lock();
m_spectrumSize = size;
m_mutex.unlock();
}
}
void QDSPEngine::ProcessFrequencyShift(CPX &in, CPX &out, int size) {
cpx tmp;
CPX Osc;
Osc.resize(size);
for (int i = 0; i < size; i++) {
tmp = in.at(i);
qreal OscGn;
Osc[i].re = osc1cpx.re * m_OscCos - osc1cpx.im * m_OscSin;
Osc[i].im = osc1cpx.im * m_OscCos + osc1cpx.re * m_OscSin;
OscGn = 1.95 - (osc1cpx.re * osc1cpx.re + osc1cpx.im * osc1cpx.im);
osc1cpx.re = OscGn * Osc.at(i).re;
osc1cpx.im = OscGn * Osc.at(i).im;
//Cpx multiply by shift frequency
out[i].re = ((tmp.re * Osc.at(i).re) - (tmp.im * Osc.at(i).im));
out[i].im = ((tmp.re * Osc.at(i).im) + (tmp.im * Osc.at(i).re));
}
}