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

pull/442/head
f4exb 2019-10-27 22:25:05 +01:00
rodzic 47e80ad8d1
commit 077a083336
9 zmienionych plików z 56 dodań i 218 usunięć

Wyświetl plik

@ -31,6 +31,7 @@ MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgReportChannelSampleRateChanged, Mes
const QString ChannelAnalyzer::m_channelIdURI = "sdrangel.channel.chanalyzer";
const QString ChannelAnalyzer::m_channelId = "ChannelAnalyzer";
const unsigned int ChannelAnalyzer::m_corrFFTLen = 4*ssbFftLen;
ChannelAnalyzer::ChannelAnalyzer(DeviceAPI *deviceAPI) :
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);
DSBFilter = 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
applyChannelSettings(m_inputSampleRate, m_inputFrequencyOffset, true);

Wyświetl plik

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

Wyświetl plik

@ -292,6 +292,14 @@ int ChannelAnalyzerGUI::getRequestedChannelSampleRate()
void ChannelAnalyzerGUI::on_signalSelect_currentIndexChanged(int 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();
}

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -1,13 +1,8 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 F4EXB //
// Copyright (C) 2019 F4EXB //
// written by Edouard Griffiths //
// //
// FFT based cross correlation //
// //
// 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 //
// 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 //
@ -24,17 +19,21 @@
///////////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include "dsp/fftengine.h"
#include "fftcorr.h"
void fftcorr::init_fft()
{
fftA = new g_fft<float>(flen);
fftB = new g_fft<float>(flen);
fftA->configure(flen, false);
fftB->configure(flen, false);
fftInvA->configure(flen, true);
m_window.create(FFTWindow::Hanning, flen);
dataA = new cmplx[flen];
dataB = new cmplx[flen];
dataBj = new cmplx[flen];
dataP = new cmplx[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);
@ -44,7 +43,12 @@ void fftcorr::init_fft()
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();
}
@ -71,21 +75,25 @@ int fftcorr::run(const cmplx& inA, const cmplx* inB, cmplx **out)
return 0;
}
fftA->ComplexFFT(dataA);
m_window.apply(dataA, fftA->in());
fftA->transform();
if (inB) {
fftB->ComplexFFT(dataB);
if (inB)
{
m_window.apply(dataB, fftB->in());
fftB->transform();
}
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 {
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);
inptrA = 0;

Wyświetl plik

@ -1,13 +1,8 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 F4EXB //
// Copyright (C) 2019 F4EXB //
// written by Edouard Griffiths //
// //
// FFT based cross correlation //
// //
// 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 //
// 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 //
@ -23,13 +18,16 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRBASE_DSP_FFTCORR_H_
#define SDRBASE_DSP_FFTCORR_H_
#ifndef SDRBASE_DSP_FFTCORR2_H_
#define SDRBASE_DSP_FFTCORR2_H_
#include <complex>
#include "gfft.h"
#include "dsp/fftwindow.h"
#include "export.h"
class FFTEngine;
class SDRBASE_API fftcorr {
public:
typedef std::complex<float> cmplx;
@ -43,8 +41,10 @@ private:
void init_fft();
int flen; //!< FFT length
int flen2; //!< half FFT length
g_fft<float> *fftA;
g_fft<float> *fftB;
FFTEngine *fftA;
FFTEngine *fftB;
FFTEngine *fftInvA;
FFTWindow m_window;
cmplx *dataA; // from A input
cmplx *dataB; // from B input
cmplx *dataBj; // conjugate of B
@ -55,4 +55,4 @@ private:
};
#endif /* SDRBASE_DSP_FFTCORR_H_ */
#endif /* SDRBASE_DSP_FFTCORR2_H_ */

Wyświetl plik

@ -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++];
}

Wyświetl plik

@ -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_ */