1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-09-08 08:07:54 -04:00

ChannelAnalyzer: set trace length to FFT length when auto-correlation by IFFT is used

This commit is contained in:
f4exb 2019-10-27 22:25:05 +01:00
parent 47e80ad8d1
commit 077a083336
9 changed files with 56 additions and 218 deletions

View File

@ -31,6 +31,7 @@ MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgReportChannelSampleRateChanged, Mes
const QString ChannelAnalyzer::m_channelIdURI = "sdrangel.channel.chanalyzer"; const QString ChannelAnalyzer::m_channelIdURI = "sdrangel.channel.chanalyzer";
const QString ChannelAnalyzer::m_channelId = "ChannelAnalyzer"; const QString ChannelAnalyzer::m_channelId = "ChannelAnalyzer";
const unsigned int ChannelAnalyzer::m_corrFFTLen = 4*ssbFftLen;
ChannelAnalyzer::ChannelAnalyzer(DeviceAPI *deviceAPI) : ChannelAnalyzer::ChannelAnalyzer(DeviceAPI *deviceAPI) :
ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink), ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
@ -52,7 +53,7 @@ ChannelAnalyzer::ChannelAnalyzer(DeviceAPI *deviceAPI) :
SSBFilter = new fftfilt(m_settings.m_lowCutoff / m_inputSampleRate, m_settings.m_bandwidth / m_inputSampleRate, ssbFftLen); SSBFilter = new fftfilt(m_settings.m_lowCutoff / m_inputSampleRate, m_settings.m_bandwidth / m_inputSampleRate, ssbFftLen);
DSBFilter = new fftfilt(m_settings.m_bandwidth / m_inputSampleRate, 2*ssbFftLen); DSBFilter = new fftfilt(m_settings.m_bandwidth / m_inputSampleRate, 2*ssbFftLen);
RRCFilter = new fftfilt(m_settings.m_bandwidth / m_inputSampleRate, 2*ssbFftLen); RRCFilter = new fftfilt(m_settings.m_bandwidth / m_inputSampleRate, 2*ssbFftLen);
m_corr = new fftcorr2(8*ssbFftLen); // 8k for 4k effective samples m_corr = new fftcorr(2*m_corrFFTLen); // 8k for 4k effective samples
m_pll.computeCoefficients(0.002f, 0.5f, 10.0f); // bandwidth, damping factor, loop gain m_pll.computeCoefficients(0.002f, 0.5f, 10.0f); // bandwidth, damping factor, loop gain
applyChannelSettings(m_inputSampleRate, m_inputFrequencyOffset, true); applyChannelSettings(m_inputSampleRate, m_inputFrequencyOffset, true);

View File

@ -25,7 +25,7 @@
#include "channel/channelapi.h" #include "channel/channelapi.h"
#include "dsp/interpolator.h" #include "dsp/interpolator.h"
#include "dsp/ncof.h" #include "dsp/ncof.h"
#include "dsp/fftcorr2.h" #include "dsp/fftcorr.h"
#include "dsp/fftfilt.h" #include "dsp/fftfilt.h"
#include "dsp/phaselockcomplex.h" #include "dsp/phaselockcomplex.h"
#include "dsp/freqlockcomplex.h" #include "dsp/freqlockcomplex.h"
@ -156,6 +156,7 @@ public:
static const QString m_channelIdURI; static const QString m_channelIdURI;
static const QString m_channelId; static const QString m_channelId;
static const unsigned int m_corrFFTLen;
private: private:
DeviceAPI *m_deviceAPI; DeviceAPI *m_deviceAPI;
@ -181,7 +182,7 @@ private:
fftfilt* SSBFilter; fftfilt* SSBFilter;
fftfilt* DSBFilter; fftfilt* DSBFilter;
fftfilt* RRCFilter; fftfilt* RRCFilter;
fftcorr2* m_corr; fftcorr* m_corr;
BasebandSampleSink* m_sampleSink; BasebandSampleSink* m_sampleSink;
SampleVector m_sampleBuffer; SampleVector m_sampleBuffer;

View File

@ -292,6 +292,14 @@ int ChannelAnalyzerGUI::getRequestedChannelSampleRate()
void ChannelAnalyzerGUI::on_signalSelect_currentIndexChanged(int index) void ChannelAnalyzerGUI::on_signalSelect_currentIndexChanged(int index)
{ {
m_settings.m_inputType = (ChannelAnalyzerSettings::InputType) index; m_settings.m_inputType = (ChannelAnalyzerSettings::InputType) index;
if (m_settings.m_inputType == ChannelAnalyzerSettings::InputAutoCorr) {
m_scopeVis->setTraceChunkSize(ChannelAnalyzer::m_corrFFTLen);
} else {
m_scopeVis->setTraceChunkSize(ScopeVis::m_traceChunkDefaultSize);
}
ui->scopeGUI->traceLengthChange();
applySettings(); applySettings();
} }

View File

@ -25,7 +25,7 @@
const PluginDescriptor ChannelAnalyzerPlugin::m_pluginDescriptor = { const PluginDescriptor ChannelAnalyzerPlugin::m_pluginDescriptor = {
QString("Channel Analyzer"), QString("Channel Analyzer"),
QString("4.11.6"), QString("4.11.12"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, true,

View File

@ -79,7 +79,6 @@ set(sdrbase_SOURCES
dsp/dspdevicesinkengine.cpp dsp/dspdevicesinkengine.cpp
dsp/dspdevicemimoengine.cpp dsp/dspdevicemimoengine.cpp
dsp/fftcorr.cpp dsp/fftcorr.cpp
dsp/fftcorr2.cpp
dsp/fftengine.cpp dsp/fftengine.cpp
dsp/fftfilt.cpp dsp/fftfilt.cpp
dsp/fftwindow.cpp dsp/fftwindow.cpp
@ -201,7 +200,6 @@ set(sdrbase_HEADERS
dsp/dspdevicemimoengine.h dsp/dspdevicemimoengine.h
dsp/dsptypes.h dsp/dsptypes.h
dsp/fftcorr.h dsp/fftcorr.h
dsp/fftcorr2.h
dsp/fftengine.h dsp/fftengine.h
dsp/fftfilt.h dsp/fftfilt.h
dsp/fftwengine.h dsp/fftwengine.h

View File

@ -1,13 +1,8 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 F4EXB // // Copyright (C) 2019 F4EXB //
// written by Edouard Griffiths // // written by Edouard Griffiths //
// // // //
// FFT based cross correlation // // FFT based cross correlation. Uses FFTW/Kiss engine. //
// //
// See: http://liquidsdr.org/blog/pll-howto/ //
// Fixed filter registers saturation //
// Added order for PSK locking. This brilliant idea actually comes from this //
// post: https://www.dsprelated.com/showthread/comp.dsp/36356-1.php //
// // // //
// This program is free software; you can redistribute it and/or modify // // 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 // // it under the terms of the GNU General Public License as published by //
@ -24,17 +19,21 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#include <algorithm> #include <algorithm>
#include "dsp/fftengine.h"
#include "fftcorr.h" #include "fftcorr.h"
void fftcorr::init_fft() void fftcorr::init_fft()
{ {
fftA = new g_fft<float>(flen); fftA->configure(flen, false);
fftB = new g_fft<float>(flen); fftB->configure(flen, false);
fftInvA->configure(flen, true);
m_window.create(FFTWindow::Hanning, flen);
dataA = new cmplx[flen]; dataA = new cmplx[flen];
dataB = new cmplx[flen]; dataB = new cmplx[flen];
dataBj = new cmplx[flen]; dataBj = new cmplx[flen];
dataP = new cmplx[flen]; dataP = new cmplx[flen];
std::fill(dataA, dataA+flen, 0); std::fill(dataA, dataA+flen, 0);
std::fill(dataB, dataB+flen, 0); std::fill(dataB, dataB+flen, 0);
@ -44,7 +43,12 @@ void fftcorr::init_fft()
outptr = 0; outptr = 0;
} }
fftcorr::fftcorr(int len) : flen(len), flen2(len>>1) fftcorr::fftcorr(int len) :
flen(len),
flen2(len>>1),
fftA(FFTEngine::create()),
fftB(FFTEngine::create()),
fftInvA(FFTEngine::create())
{ {
init_fft(); init_fft();
} }
@ -71,21 +75,25 @@ int fftcorr::run(const cmplx& inA, const cmplx* inB, cmplx **out)
return 0; return 0;
} }
fftA->ComplexFFT(dataA); m_window.apply(dataA, fftA->in());
fftA->transform();
if (inB) { if (inB)
fftB->ComplexFFT(dataB); {
m_window.apply(dataB, fftB->in());
fftB->transform();
} }
if (inB) { if (inB) {
std::transform(dataB, dataB+flen, dataBj, [](const cmplx& c) -> cmplx { return std::conj(c); }); std::transform(fftB->out(), fftB->out()+flen, dataBj, [](const cmplx& c) -> cmplx { return std::conj(c); });
} else { } else {
std::transform(dataA, dataA+flen, dataBj, [](const cmplx& c) -> cmplx { return std::conj(c); }); std::transform(fftA->out(), fftA->out()+flen, dataBj, [](const cmplx& c) -> cmplx { return std::conj(c); });
} }
std::transform(dataA, dataA+flen, dataBj, dataP, [](const cmplx& a, const cmplx& b) -> cmplx { return a*b; }); std::transform(fftA->out(), fftA->out()+flen, dataBj, fftInvA->in(), [](const cmplx& a, const cmplx& b) -> cmplx { return a*b; });
fftA->InverseComplexFFT(dataP); fftInvA->transform();
std::copy(fftInvA->out(), fftInvA->out()+flen, dataP);
std::fill(dataA, dataA+flen, 0); std::fill(dataA, dataA+flen, 0);
inptrA = 0; inptrA = 0;

View File

@ -1,13 +1,8 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 F4EXB // // Copyright (C) 2019 F4EXB //
// written by Edouard Griffiths // // written by Edouard Griffiths //
// // // //
// FFT based cross correlation // // FFT based cross correlation. Uses FFTW/Kiss engine. //
// //
// See: http://liquidsdr.org/blog/pll-howto/ //
// Fixed filter registers saturation //
// Added order for PSK locking. This brilliant idea actually comes from this //
// post: https://www.dsprelated.com/showthread/comp.dsp/36356-1.php //
// // // //
// This program is free software; you can redistribute it and/or modify // // 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 // // it under the terms of the GNU General Public License as published by //
@ -23,13 +18,16 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRBASE_DSP_FFTCORR_H_ #ifndef SDRBASE_DSP_FFTCORR2_H_
#define SDRBASE_DSP_FFTCORR_H_ #define SDRBASE_DSP_FFTCORR2_H_
#include <complex> #include <complex>
#include "gfft.h"
#include "dsp/fftwindow.h"
#include "export.h" #include "export.h"
class FFTEngine;
class SDRBASE_API fftcorr { class SDRBASE_API fftcorr {
public: public:
typedef std::complex<float> cmplx; typedef std::complex<float> cmplx;
@ -43,8 +41,10 @@ private:
void init_fft(); void init_fft();
int flen; //!< FFT length int flen; //!< FFT length
int flen2; //!< half FFT length int flen2; //!< half FFT length
g_fft<float> *fftA; FFTEngine *fftA;
g_fft<float> *fftB; FFTEngine *fftB;
FFTEngine *fftInvA;
FFTWindow m_window;
cmplx *dataA; // from A input cmplx *dataA; // from A input
cmplx *dataB; // from B input cmplx *dataB; // from B input
cmplx *dataBj; // conjugate of B cmplx *dataBj; // conjugate of B
@ -55,4 +55,4 @@ private:
}; };
#endif /* SDRBASE_DSP_FFTCORR_H_ */ #endif /* SDRBASE_DSP_FFTCORR2_H_ */

View File

@ -1,120 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 F4EXB //
// written by Edouard Griffiths //
// //
// FFT based cross correlation. Uses FFTW/Kiss engine. //
// //
// 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/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include "dsp/fftengine.h"
#include "fftcorr2.h"
void fftcorr2::init_fft()
{
fftA->configure(flen, false);
fftB->configure(flen, false);
fftInvA->configure(flen, true);
m_window.create(FFTWindow::Hamming, flen);
dataA = new cmplx[flen];
dataB = new cmplx[flen];
dataBj = new cmplx[flen];
dataP = new cmplx[flen];
std::fill(dataA, dataA+flen, 0);
std::fill(dataB, dataB+flen, 0);
inptrA = 0;
inptrB = 0;
outptr = 0;
}
fftcorr2::fftcorr2(int len) :
flen(len),
flen2(len>>1),
fftA(FFTEngine::create()),
fftB(FFTEngine::create()),
fftInvA(FFTEngine::create())
{
init_fft();
}
fftcorr2::~fftcorr2()
{
delete fftA;
delete fftB;
delete[] dataA;
delete[] dataB;
delete[] dataBj;
delete[] dataP;
}
int fftcorr2::run(const cmplx& inA, const cmplx* inB, cmplx **out)
{
dataA[inptrA++] = inA;
if (inB) {
dataB[inptrB++] = *inB;
}
if (inptrA < flen2) {
return 0;
}
m_window.apply(dataA, fftA->in());
fftA->transform();
if (inB)
{
m_window.apply(dataB, fftB->in());
fftB->transform();
}
if (inB) {
std::transform(fftB->out(), fftB->out()+flen, dataBj, [](const cmplx& c) -> cmplx { return std::conj(c); });
} else {
std::transform(fftA->out(), fftA->out()+flen, dataBj, [](const cmplx& c) -> cmplx { return std::conj(c); });
}
std::transform(fftA->out(), fftA->out()+flen, dataBj, fftInvA->in(), [](const cmplx& a, const cmplx& b) -> cmplx { return a*b; });
fftInvA->transform();
std::copy(fftInvA->out(), fftInvA->out()+flen, dataP);
std::fill(dataA, dataA+flen, 0);
inptrA = 0;
if (inB)
{
std::fill(dataB, dataB+flen, 0);
inptrB = 0;
}
*out = dataP;
return flen2;
}
const fftcorr2::cmplx& fftcorr2::run(const cmplx& inA, const cmplx* inB)
{
cmplx *dummy;
if (run(inA, inB, &dummy)) {
outptr = 0;
}
return dataP[outptr++];
}

View File

@ -1,58 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 F4EXB //
// written by Edouard Griffiths //
// //
// FFT based cross correlation. Uses FFTW/Kiss engine. //
// //
// 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 SDRBASE_DSP_FFTCORR2_H_
#define SDRBASE_DSP_FFTCORR2_H_
#include <complex>
#include "dsp/fftwindow.h"
#include "export.h"
class FFTEngine;
class SDRBASE_API fftcorr2 {
public:
typedef std::complex<float> cmplx;
fftcorr2(int len);
~fftcorr2();
int run(const cmplx& inA, const cmplx* inB, cmplx **out); //!< if inB = 0 then run auto-correlation
const cmplx& run(const cmplx& inA, const cmplx* inB);
private:
void init_fft();
int flen; //!< FFT length
int flen2; //!< half FFT length
FFTEngine *fftA;
FFTEngine *fftB;
FFTEngine *fftInvA;
FFTWindow m_window;
cmplx *dataA; // from A input
cmplx *dataB; // from B input
cmplx *dataBj; // conjugate of B
cmplx *dataP; // product of A with conjugate of B
int inptrA;
int inptrB;
int outptr;
};
#endif /* SDRBASE_DSP_FFTCORR2_H_ */