mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-22 08:04:49 -05:00
Scope on complex<float>: implementation
This commit is contained in:
parent
04170f2648
commit
dc205bc8e2
@ -41,6 +41,7 @@ typedef qint16 FixReal;
|
||||
|
||||
typedef float Real;
|
||||
typedef std::complex<Real> Complex;
|
||||
typedef std::vector<Complex> ComplexVector;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Sample
|
||||
|
@ -70,6 +70,7 @@ ScopeVis::ScopeVis() :
|
||||
{
|
||||
setObjectName("ScopeVis");
|
||||
m_traceDiscreteMemory.resize(GLScopeSettings::m_traceChunkDefaultSize); // arbitrary
|
||||
m_convertBuffers.resize(GLScopeSettings::m_traceChunkDefaultSize);
|
||||
|
||||
for (int i = 0; i < (int) Projector::nbProjectionTypes; i++) {
|
||||
m_projectorCache[i] = 0.0;
|
||||
@ -140,6 +141,7 @@ void ScopeVis::setNbStreams(uint32_t nbStreams)
|
||||
if (m_nbStreams != nbStreams)
|
||||
{
|
||||
m_traceDiscreteMemory.setNbStreams(nbStreams);
|
||||
m_convertBuffers.setNbStreams(nbStreams);
|
||||
m_nbStreams = nbStreams;
|
||||
}
|
||||
}
|
||||
@ -414,6 +416,31 @@ void ScopeVis::setMemoryIndex(uint32_t memoryIndex)
|
||||
}
|
||||
|
||||
void ScopeVis::feed(const std::vector<SampleVector::const_iterator>& vbegin, int nbSamples)
|
||||
{
|
||||
std::vector<ComplexVector::const_iterator> vcbegin;
|
||||
std::vector<ComplexVector>& convertBuffers = m_convertBuffers.getBuffers();
|
||||
|
||||
if (nbSamples > (int) m_convertBuffers.size()) {
|
||||
m_convertBuffers.resize(nbSamples);
|
||||
}
|
||||
|
||||
for (unsigned int s = 0; s < vbegin.size(); s++)
|
||||
{
|
||||
std::transform(
|
||||
vbegin[s],
|
||||
vbegin[s] + nbSamples,
|
||||
convertBuffers[s].begin(),
|
||||
[](const Sample& s) -> Complex {
|
||||
return Complex{s.m_real / SDR_RX_SCALEF, s.m_imag / SDR_RX_SCALEF};
|
||||
}
|
||||
);
|
||||
vcbegin.push_back(convertBuffers[s].begin());
|
||||
}
|
||||
|
||||
feed(vcbegin, nbSamples);
|
||||
}
|
||||
|
||||
void ScopeVis::feed(const std::vector<ComplexVector::const_iterator>& vbegin, int nbSamples)
|
||||
{
|
||||
if (vbegin.size() == 0) {
|
||||
return;
|
||||
@ -447,11 +474,11 @@ void ScopeVis::feed(const std::vector<SampleVector::const_iterator>& vbegin, int
|
||||
m_triggerLocation = nbSamples;
|
||||
}
|
||||
|
||||
SampleVector::const_iterator begin(vbegin[0]);
|
||||
ComplexVector::const_iterator begin(vbegin[0]);
|
||||
//const SampleVector::const_iterator end = vbegin[0] + nbSamples;
|
||||
int triggerPointToEnd;
|
||||
int remainder = nbSamples;
|
||||
std::vector<SampleVector::const_iterator> nvbegin(vbegin);
|
||||
std::vector<ComplexVector::const_iterator> nvbegin(vbegin);
|
||||
|
||||
//while (begin < end)
|
||||
while (remainder > 0)
|
||||
@ -495,11 +522,11 @@ void ScopeVis::processMemoryTrace()
|
||||
traceMemoryIndex += GLScopeSettings::m_nbTraceMemories;
|
||||
}
|
||||
|
||||
std::vector<SampleVector::const_iterator> mend;
|
||||
std::vector<ComplexVector::const_iterator> mend;
|
||||
m_traceDiscreteMemory.getEndPointAt(traceMemoryIndex, mend);
|
||||
std::vector<SampleVector::const_iterator> mbegin(mend.size());
|
||||
std::vector<ComplexVector::const_iterator> mbegin(mend.size());
|
||||
TraceBackDiscreteMemory::moveIt(mend, mbegin, -m_traceSize);
|
||||
std::vector<SampleVector::const_iterator> mbegin_tb(mbegin.size());
|
||||
std::vector<ComplexVector::const_iterator> mbegin_tb(mbegin.size());
|
||||
TraceBackDiscreteMemory::moveIt(mbegin, mbegin_tb, -m_maxTraceDelay);
|
||||
m_nbSamples = m_traceSize + m_maxTraceDelay;
|
||||
|
||||
@ -508,9 +535,9 @@ void ScopeVis::processMemoryTrace()
|
||||
}
|
||||
}
|
||||
|
||||
void ScopeVis::processTrace(const std::vector<SampleVector::const_iterator>& vcbegin, int length, int& triggerPointToEnd)
|
||||
void ScopeVis::processTrace(const std::vector<ComplexVector::const_iterator>& vcbegin, int length, int& triggerPointToEnd)
|
||||
{
|
||||
std::vector<SampleVector::const_iterator> vbegin(vcbegin);
|
||||
std::vector<ComplexVector::const_iterator> vbegin(vcbegin);
|
||||
int firstRemainder = length;
|
||||
|
||||
// memory storage
|
||||
@ -579,7 +606,7 @@ void ScopeVis::processTrace(const std::vector<SampleVector::const_iterator>& vcb
|
||||
}
|
||||
|
||||
uint32_t triggerStreamIndex = triggerCondition->m_triggerData.m_streamIndex;
|
||||
const Sample& s = *vbegin[triggerStreamIndex];
|
||||
const Complex& s = *vbegin[triggerStreamIndex];
|
||||
|
||||
if (m_triggerComparator.triggered(s, *triggerCondition)) // matched the current trigger
|
||||
{
|
||||
@ -625,9 +652,9 @@ void ScopeVis::processTrace(const std::vector<SampleVector::const_iterator>& vcb
|
||||
{
|
||||
int remainder;
|
||||
int count = firstRemainder; // number of samples in traceback buffer past the current point
|
||||
std::vector<SampleVector::const_iterator> mend;
|
||||
std::vector<ComplexVector::const_iterator> mend;
|
||||
m_traceDiscreteMemory.getCurrent(mend);
|
||||
std::vector<SampleVector::const_iterator> mbegin(mend.size());
|
||||
std::vector<ComplexVector::const_iterator> mbegin(mend.size());
|
||||
TraceBackDiscreteMemory::moveIt(mend, mbegin, -count);
|
||||
|
||||
if (m_traceStart) // start of trace processing
|
||||
@ -644,14 +671,14 @@ void ScopeVis::processTrace(const std::vector<SampleVector::const_iterator>& vcb
|
||||
|
||||
if (m_maxTraceDelay > 0)
|
||||
{ // trace back
|
||||
std::vector<SampleVector::const_iterator> tbegin(mbegin.size());
|
||||
std::vector<ComplexVector::const_iterator> tbegin(mbegin.size());
|
||||
TraceBackDiscreteMemory::moveIt(mbegin, tbegin, - m_preTriggerDelay - m_maxTraceDelay);
|
||||
processTraces(tbegin, m_maxTraceDelay, true);
|
||||
}
|
||||
|
||||
if (m_preTriggerDelay > 0)
|
||||
{ // pre-trigger
|
||||
std::vector<SampleVector::const_iterator> tbegin(mbegin.size());
|
||||
std::vector<ComplexVector::const_iterator> tbegin(mbegin.size());
|
||||
TraceBackDiscreteMemory::moveIt(mbegin, tbegin, -m_preTriggerDelay);
|
||||
processTraces(tbegin, m_preTriggerDelay);
|
||||
}
|
||||
@ -727,16 +754,13 @@ bool ScopeVis::nextTrigger()
|
||||
}
|
||||
}
|
||||
|
||||
int ScopeVis::processTraces(const std::vector<SampleVector::const_iterator>& vcbegin, int ilength, bool traceBack)
|
||||
int ScopeVis::processTraces(const std::vector<ComplexVector::const_iterator>& vcbegin, int ilength, bool traceBack)
|
||||
{
|
||||
std::vector<SampleVector::const_iterator> vbegin(vcbegin);
|
||||
std::vector<ComplexVector::const_iterator> vbegin(vcbegin);
|
||||
uint32_t shift = (m_timeOfsProMill / 1000.0) * m_traceSize;
|
||||
uint32_t length = m_traceSize / m_timeBase;
|
||||
int remainder = ilength;
|
||||
|
||||
if (m_spectrumVis) {
|
||||
m_spectrumVis->feed(vcbegin[0], vcbegin[0] + ilength, false); // TODO: use spectrum stream index
|
||||
}
|
||||
m_spectrumVis->feed(vcbegin[0], vcbegin[0] + ilength, false);
|
||||
|
||||
while ((remainder > 0) && (m_nbSamples > 0))
|
||||
{
|
||||
@ -797,8 +821,8 @@ int ScopeVis::processTraces(const std::vector<SampleVector::const_iterator>& vcb
|
||||
}
|
||||
else if (projectionType == Projector::ProjectionMagDB)
|
||||
{
|
||||
Real re = vbegin[streamIndex]->m_real / SDR_RX_SCALEF;
|
||||
Real im = vbegin[streamIndex]->m_imag / SDR_RX_SCALEF;
|
||||
Real re = vbegin[streamIndex]->real();
|
||||
Real im = vbegin[streamIndex]->imag();
|
||||
double magsq = re*re + im*im;
|
||||
float pdB = log10f(magsq) * 10.0f;
|
||||
float p = pdB - (100.0f * itData->m_ofs);
|
||||
|
@ -432,6 +432,7 @@ public:
|
||||
uint32_t getNbTraces() const { return m_traces.size(); }
|
||||
|
||||
void feed(const std::vector<SampleVector::const_iterator>& vbegin, int nbSamples);
|
||||
void feed(const std::vector<ComplexVector::const_iterator>& vbegin, int nbSamples);
|
||||
//virtual void start();
|
||||
//virtual void stop();
|
||||
bool handleMessage(const Message& message);
|
||||
@ -510,7 +511,7 @@ private:
|
||||
/**
|
||||
* Complex trace stuff
|
||||
*/
|
||||
typedef DoubleBufferSimple<Sample> TraceBuffer;
|
||||
typedef DoubleBufferSimple<Complex> TraceBuffer;
|
||||
|
||||
struct TraceBackBuffer
|
||||
{
|
||||
@ -528,7 +529,7 @@ private:
|
||||
m_traceBuffer.reset();
|
||||
}
|
||||
|
||||
void write(const SampleVector::const_iterator begin, int nbSamples) {
|
||||
void write(const ComplexVector::const_iterator begin, int nbSamples) {
|
||||
m_traceBuffer.write(begin, nbSamples);
|
||||
}
|
||||
|
||||
@ -536,7 +537,7 @@ private:
|
||||
return m_traceBuffer.absoluteFill();
|
||||
}
|
||||
|
||||
void current(SampleVector::iterator& it) {
|
||||
void current(ComplexVector::iterator& it) {
|
||||
m_traceBuffer.getCurrent(it);
|
||||
}
|
||||
|
||||
@ -578,24 +579,57 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void setEndPoint(const SampleVector::const_iterator& endPoint) {
|
||||
void setEndPoint(const ComplexVector::const_iterator& endPoint) {
|
||||
m_endPoint = endPoint;
|
||||
}
|
||||
|
||||
SampleVector::const_iterator getEndPoint() {
|
||||
ComplexVector::const_iterator getEndPoint() {
|
||||
return m_endPoint;
|
||||
}
|
||||
|
||||
void getEndPoint(SampleVector::const_iterator& it) {
|
||||
void getEndPoint(ComplexVector::const_iterator& it) {
|
||||
it = m_endPoint;
|
||||
}
|
||||
|
||||
private:
|
||||
SampleVector::const_iterator m_endPoint;
|
||||
ComplexVector::const_iterator m_endPoint;
|
||||
};
|
||||
|
||||
typedef std::vector<TraceBackBuffer> TraceBackBufferStream;
|
||||
|
||||
struct ConvertBuffers
|
||||
{
|
||||
ConvertBuffers(uint32_t nbStreams = 1) :
|
||||
m_convertBuffers(nbStreams)
|
||||
{}
|
||||
|
||||
void setNbStreams(uint32_t nbStreams)
|
||||
{
|
||||
m_convertBuffers.resize(nbStreams);
|
||||
resize(m_size);
|
||||
}
|
||||
|
||||
void resize(unsigned int size)
|
||||
{
|
||||
for (unsigned int s = 0; s < m_convertBuffers.size(); s++) {
|
||||
m_convertBuffers[s].resize(size);
|
||||
}
|
||||
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
unsigned int size() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
std::vector<ComplexVector>& getBuffers() {
|
||||
return m_convertBuffers;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int m_size;
|
||||
std::vector<ComplexVector> m_convertBuffers;
|
||||
};
|
||||
struct TraceBackDiscreteMemory
|
||||
{
|
||||
/**
|
||||
@ -747,20 +781,20 @@ private:
|
||||
/**
|
||||
* Get current point at current memory position (first stream)
|
||||
*/
|
||||
void getCurrent(SampleVector::iterator& it) {
|
||||
void getCurrent(ComplexVector::iterator& it) {
|
||||
current().current(it);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current points at current memory position
|
||||
*/
|
||||
void getCurrent(std::vector<SampleVector::const_iterator>& vit)
|
||||
void getCurrent(std::vector<ComplexVector::const_iterator>& vit)
|
||||
{
|
||||
vit.clear();
|
||||
|
||||
for (unsigned int is = 0; is < m_traceBackBuffersStreams.size(); is++)
|
||||
{
|
||||
SampleVector::iterator it;
|
||||
ComplexVector::iterator it;
|
||||
current(is).current(it);
|
||||
vit.push_back(it);
|
||||
}
|
||||
@ -769,14 +803,14 @@ private:
|
||||
/**
|
||||
* Set end point at current memory position (first stream)
|
||||
*/
|
||||
void setCurrentEndPoint(const SampleVector::iterator& it) {
|
||||
void setCurrentEndPoint(const ComplexVector::iterator& it) {
|
||||
current().setEndPoint(it);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set end points at current memory position
|
||||
*/
|
||||
void setCurrentEndPoint(const std::vector<SampleVector::const_iterator>& vit)
|
||||
void setCurrentEndPoint(const std::vector<ComplexVector::const_iterator>& vit)
|
||||
{
|
||||
for (unsigned int is = 0; is < vit.size(); is++)
|
||||
{
|
||||
@ -791,20 +825,20 @@ private:
|
||||
/**
|
||||
* Get end point at given memory position (first stream)
|
||||
*/
|
||||
void getEndPointAt(int index, SampleVector::const_iterator& mend) {
|
||||
void getEndPointAt(int index, ComplexVector::const_iterator& mend) {
|
||||
at(index).getEndPoint(mend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get end points at given memory position
|
||||
*/
|
||||
void getEndPointAt(int index, std::vector<SampleVector::const_iterator>& vend)
|
||||
void getEndPointAt(int index, std::vector<ComplexVector::const_iterator>& vend)
|
||||
{
|
||||
vend.clear();
|
||||
|
||||
for (unsigned int is = 0; is < m_traceBackBuffersStreams.size(); is++)
|
||||
{
|
||||
SampleVector::const_iterator mend;
|
||||
ComplexVector::const_iterator mend;
|
||||
at(index, is).getEndPoint(mend);
|
||||
vend.push_back(mend);
|
||||
}
|
||||
@ -813,14 +847,14 @@ private:
|
||||
/**
|
||||
* Write trace at current memory position (first stream)
|
||||
*/
|
||||
void writeCurrent(const SampleVector::const_iterator& begin, int length) {
|
||||
void writeCurrent(const ComplexVector::const_iterator& begin, int length) {
|
||||
current().write(begin, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write traces at current memory position
|
||||
*/
|
||||
void writeCurrent(const std::vector<SampleVector::const_iterator>& vbegin, int length)
|
||||
void writeCurrent(const std::vector<ComplexVector::const_iterator>& vbegin, int length)
|
||||
{
|
||||
for (unsigned int i = 0; i < vbegin.size(); i++) {
|
||||
current().write(vbegin[i], length);
|
||||
@ -830,14 +864,14 @@ private:
|
||||
/**
|
||||
* Move buffer iterator by a certain amount (first stream)
|
||||
*/
|
||||
static void moveIt(const SampleVector::const_iterator& x, SampleVector::const_iterator& y, int amount) {
|
||||
static void moveIt(const ComplexVector::const_iterator& x, ComplexVector::const_iterator& y, int amount) {
|
||||
y = x + amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move buffers iterators by a certain amount
|
||||
*/
|
||||
static void moveIt(const std::vector<SampleVector::const_iterator>& vx, std::vector<SampleVector::const_iterator>& vy, int amount)
|
||||
static void moveIt(const std::vector<ComplexVector::const_iterator>& vx, std::vector<ComplexVector::const_iterator>& vy, int amount)
|
||||
{
|
||||
for (unsigned int i = 0; i < vx.size(); i++)
|
||||
{
|
||||
@ -1083,7 +1117,7 @@ private:
|
||||
computeLevels();
|
||||
}
|
||||
|
||||
bool triggered(const Sample& s, TriggerCondition& triggerCondition)
|
||||
bool triggered(const Complex& s, TriggerCondition& triggerCondition)
|
||||
{
|
||||
if (triggerCondition.m_triggerData.m_triggerLevel != m_level)
|
||||
{
|
||||
@ -1194,7 +1228,8 @@ private:
|
||||
int m_triggerLocation; //!< Trigger location from end point
|
||||
int m_sampleRate; //!< Actual sample rate being used
|
||||
int m_liveSampleRate; //!< Sample rate in live mode
|
||||
TraceBackDiscreteMemory m_traceDiscreteMemory; //!< Complex trace memory for triggered states TODO: vectorize when more than on input is allowed
|
||||
TraceBackDiscreteMemory m_traceDiscreteMemory; //!< Complex trace memory
|
||||
ConvertBuffers m_convertBuffers; //!< Sample to Complex conversions
|
||||
bool m_freeRun; //!< True if free running (trigger globally disabled)
|
||||
int m_maxTraceDelay; //!< Maximum trace delay
|
||||
TriggerComparator m_triggerComparator; //!< Compares sample level to trigger level
|
||||
@ -1227,7 +1262,7 @@ private:
|
||||
/**
|
||||
* Process a sample trace which length is at most the trace length (m_traceSize)
|
||||
*/
|
||||
void processTrace(const std::vector<SampleVector::const_iterator>& vbegin, int length, int& triggerPointToEnd);
|
||||
void processTrace(const std::vector<ComplexVector::const_iterator>& vbegin, int length, int& triggerPointToEnd);
|
||||
|
||||
/**
|
||||
* process a trace in memory at current trace index in memory
|
||||
@ -1239,7 +1274,7 @@ private:
|
||||
* - if finished it returns the number of unprocessed samples left in the buffer
|
||||
* - if not finished it returns -1
|
||||
*/
|
||||
int processTraces(const std::vector<SampleVector::const_iterator>& vbegin, int length, bool traceBack = false);
|
||||
int processTraces(const std::vector<ComplexVector::const_iterator>& vbegin, int length, bool traceBack = false);
|
||||
|
||||
/**
|
||||
* Get maximum trace delay
|
||||
|
@ -317,6 +317,56 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length)
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void SpectrumVis::feed(const ComplexVector::const_iterator& cbegin, const ComplexVector::const_iterator& end, bool positiveOnly)
|
||||
{
|
||||
if (!m_running) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if no visualisation is set, send the samples to /dev/null
|
||||
if (!m_glSpectrum && !m_wsSpectrum.socketOpened()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_mutex.tryLock(0)) { // prevent conflicts with configuration process
|
||||
return;
|
||||
}
|
||||
|
||||
ComplexVector::const_iterator begin(cbegin);
|
||||
|
||||
while (begin < end)
|
||||
{
|
||||
std::size_t todo = end - begin;
|
||||
std::size_t samplesNeeded = m_refillSize - m_fftBufferFill;
|
||||
|
||||
if (todo >= samplesNeeded)
|
||||
{
|
||||
// fill up the buffer
|
||||
std::copy(begin, begin + samplesNeeded, m_fftBuffer.begin() + m_fftBufferFill);
|
||||
begin += samplesNeeded;
|
||||
|
||||
processFFT(positiveOnly);
|
||||
|
||||
// advance buffer respecting the fft overlap factor
|
||||
std::copy(m_fftBuffer.begin() + m_refillSize, m_fftBuffer.end(), m_fftBuffer.begin());
|
||||
|
||||
// start over
|
||||
m_fftBufferFill = m_overlapSize;
|
||||
m_needMoreSamples = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not enough samples for FFT - just fill in new data and return
|
||||
std::copy(begin, end, m_fftBuffer.begin() + m_fftBufferFill);
|
||||
begin = end;
|
||||
m_fftBufferFill += todo;
|
||||
m_needMoreSamples = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleVector::const_iterator& end, bool positiveOnly)
|
||||
{
|
||||
if (!m_running) {
|
||||
@ -333,10 +383,6 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
|
||||
}
|
||||
|
||||
SampleVector::const_iterator begin(cbegin);
|
||||
int fftMin = (m_frequencyZoomFactor == 1.0f) ?
|
||||
0 : (m_frequencyZoomPos - (0.5f / m_frequencyZoomFactor)) * m_settings.m_fftSize;
|
||||
int fftMax = (m_frequencyZoomFactor == 1.0f) ?
|
||||
m_settings.m_fftSize : (m_frequencyZoomPos + (0.5f / m_frequencyZoomFactor)) * m_settings.m_fftSize;
|
||||
|
||||
while (begin < end)
|
||||
{
|
||||
@ -348,316 +394,11 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
|
||||
// fill up the buffer
|
||||
std::vector<Complex>::iterator it = m_fftBuffer.begin() + m_fftBufferFill;
|
||||
|
||||
for (std::size_t i = 0; i < samplesNeeded; ++i, ++begin)
|
||||
{
|
||||
for (std::size_t i = 0; i < samplesNeeded; ++i, ++begin) {
|
||||
*it++ = Complex(begin->real() / m_scalef, begin->imag() / m_scalef);
|
||||
}
|
||||
|
||||
// apply fft window (and copy from m_fftBuffer to m_fftIn)
|
||||
m_window.apply(&m_fftBuffer[0], m_fft->in());
|
||||
|
||||
// calculate FFT
|
||||
m_fft->transform();
|
||||
|
||||
// extract power spectrum and reorder buckets
|
||||
const Complex* fftOut = m_fft->out();
|
||||
Complex c;
|
||||
Real v;
|
||||
std::size_t halfSize = m_settings.m_fftSize / 2;
|
||||
|
||||
if (m_settings.m_averagingMode == SpectrumSettings::AvgModeNone)
|
||||
{
|
||||
m_specMax = 0.0f;
|
||||
|
||||
if ( positiveOnly )
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
m_psd[i] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i * 2] = v;
|
||||
m_powerSpectrum[i * 2 + 1] = v;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i + halfSize];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
m_psd[i] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i] = v;
|
||||
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
m_psd[i + halfSize] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i + halfSize] = v;
|
||||
}
|
||||
}
|
||||
|
||||
// send new data to visualisation
|
||||
if (m_glSpectrum)
|
||||
{
|
||||
m_glSpectrum->newSpectrum(
|
||||
&m_powerSpectrum.data()[fftMin],
|
||||
fftMax - fftMin,
|
||||
m_settings.m_fftSize
|
||||
);
|
||||
}
|
||||
|
||||
// web socket spectrum connections
|
||||
if (m_wsSpectrum.socketOpened())
|
||||
{
|
||||
m_wsSpectrum.newSpectrum(
|
||||
m_powerSpectrum,
|
||||
m_settings.m_fftSize,
|
||||
m_centerFrequency,
|
||||
m_sampleRate,
|
||||
m_settings.m_linear,
|
||||
m_settings.m_ssb,
|
||||
m_settings.m_usb
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (m_settings.m_averagingMode == SpectrumSettings::AvgModeMoving)
|
||||
{
|
||||
m_specMax = 0.0f;
|
||||
|
||||
if ( positiveOnly )
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
v = m_movingAverage.storeAndGetAvg(v, i);
|
||||
m_psd[i] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i * 2] = v;
|
||||
m_powerSpectrum[i * 2 + 1] = v;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i + halfSize];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
v = m_movingAverage.storeAndGetAvg(v, i+halfSize);
|
||||
m_psd[i] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i] = v;
|
||||
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
v = m_movingAverage.storeAndGetAvg(v, i);
|
||||
m_psd[i + halfSize] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i + halfSize] = v;
|
||||
}
|
||||
}
|
||||
|
||||
// send new data to visualisation
|
||||
if (m_glSpectrum)
|
||||
{
|
||||
m_glSpectrum->newSpectrum(
|
||||
&m_powerSpectrum.data()[fftMin],
|
||||
fftMax - fftMin,
|
||||
m_settings.m_fftSize
|
||||
);
|
||||
}
|
||||
|
||||
// web socket spectrum connections
|
||||
if (m_wsSpectrum.socketOpened())
|
||||
{
|
||||
m_wsSpectrum.newSpectrum(
|
||||
m_powerSpectrum,
|
||||
m_settings.m_fftSize,
|
||||
m_centerFrequency,
|
||||
m_sampleRate,
|
||||
m_settings.m_linear,
|
||||
m_settings.m_ssb,
|
||||
m_settings.m_usb
|
||||
);
|
||||
}
|
||||
|
||||
m_movingAverage.nextAverage();
|
||||
}
|
||||
else if (m_settings.m_averagingMode == SpectrumSettings::AvgModeFixed)
|
||||
{
|
||||
double avg;
|
||||
Real specMax = 0.0f;
|
||||
|
||||
if ( positiveOnly )
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_fixedAverage.storeAndGetAvg(avg, v, i))
|
||||
{
|
||||
m_psd[i] = avg/m_powFFTDiv;
|
||||
specMax = avg > specMax ? avg : specMax;
|
||||
avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
|
||||
m_powerSpectrum[i * 2] = avg;
|
||||
m_powerSpectrum[i * 2 + 1] = avg;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i + halfSize];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_fixedAverage.storeAndGetAvg(avg, v, i+halfSize))
|
||||
{
|
||||
m_psd[i] = avg/m_powFFTDiv;
|
||||
specMax = avg > specMax ? avg : specMax;
|
||||
avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
|
||||
m_powerSpectrum[i] = avg;
|
||||
}
|
||||
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_fixedAverage.storeAndGetAvg(avg, v, i))
|
||||
{
|
||||
m_psd[i + halfSize] = avg/m_powFFTDiv;
|
||||
specMax = avg > specMax ? avg : specMax;
|
||||
avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
|
||||
m_powerSpectrum[i + halfSize] = avg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// result available
|
||||
if (m_fixedAverage.nextAverage())
|
||||
{
|
||||
m_specMax = specMax;
|
||||
|
||||
// send new data to visualisation
|
||||
if (m_glSpectrum)
|
||||
{
|
||||
m_glSpectrum->newSpectrum(
|
||||
&m_powerSpectrum.data()[fftMin],
|
||||
fftMax - fftMin,
|
||||
m_settings.m_fftSize
|
||||
);
|
||||
}
|
||||
|
||||
// web socket spectrum connections
|
||||
if (m_wsSpectrum.socketOpened())
|
||||
{
|
||||
m_wsSpectrum.newSpectrum(
|
||||
m_powerSpectrum,
|
||||
m_settings.m_fftSize,
|
||||
m_centerFrequency,
|
||||
m_sampleRate,
|
||||
m_settings.m_linear,
|
||||
m_settings.m_ssb,
|
||||
m_settings.m_usb
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_settings.m_averagingMode == SpectrumSettings::AvgModeMax)
|
||||
{
|
||||
double max;
|
||||
Real specMax = 0.0f;
|
||||
|
||||
if ( positiveOnly )
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_max.storeAndGetMax(max, v, i))
|
||||
{
|
||||
m_psd[i] = max/m_powFFTDiv;
|
||||
specMax = max > specMax ? max : specMax;
|
||||
max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs;
|
||||
m_powerSpectrum[i * 2] = max;
|
||||
m_powerSpectrum[i * 2 + 1] = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i + halfSize];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_max.storeAndGetMax(max, v, i+halfSize))
|
||||
{
|
||||
m_psd[i] = max/m_powFFTDiv;
|
||||
specMax = max > specMax ? max : specMax;
|
||||
max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs;
|
||||
m_powerSpectrum[i] = max;
|
||||
}
|
||||
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_max.storeAndGetMax(max, v, i))
|
||||
{
|
||||
m_psd[i + halfSize] = max/m_powFFTDiv;
|
||||
specMax = max > specMax ? max : specMax;
|
||||
max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs;
|
||||
m_powerSpectrum[i + halfSize] = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// result available
|
||||
if (m_max.nextMax())
|
||||
{
|
||||
m_specMax = specMax;
|
||||
|
||||
// send new data to visualisation
|
||||
if (m_glSpectrum)
|
||||
{
|
||||
m_glSpectrum->newSpectrum(
|
||||
&m_powerSpectrum.data()[fftMin],
|
||||
fftMax - fftMin,
|
||||
m_settings.m_fftSize
|
||||
);
|
||||
}
|
||||
|
||||
// web socket spectrum connections
|
||||
if (m_wsSpectrum.socketOpened())
|
||||
{
|
||||
m_wsSpectrum.newSpectrum(
|
||||
m_powerSpectrum,
|
||||
m_settings.m_fftSize,
|
||||
m_centerFrequency,
|
||||
m_sampleRate,
|
||||
m_settings.m_linear,
|
||||
m_settings.m_ssb,
|
||||
m_settings.m_usb
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
processFFT(positiveOnly);
|
||||
|
||||
// advance buffer respecting the fft overlap factor
|
||||
std::copy(m_fftBuffer.begin() + m_refillSize, m_fftBuffer.end(), m_fftBuffer.begin());
|
||||
@ -669,8 +410,7 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
|
||||
else
|
||||
{
|
||||
// not enough samples for FFT - just fill in new data and return
|
||||
for(std::vector<Complex>::iterator it = m_fftBuffer.begin() + m_fftBufferFill; begin < end; ++begin)
|
||||
{
|
||||
for (std::vector<Complex>::iterator it = m_fftBuffer.begin() + m_fftBufferFill; begin < end; ++begin) {
|
||||
*it++ = Complex(begin->real() / m_scalef, begin->imag() / m_scalef);
|
||||
}
|
||||
|
||||
@ -679,7 +419,321 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
|
||||
}
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void SpectrumVis::processFFT(bool positiveOnly)
|
||||
{
|
||||
int fftMin = (m_frequencyZoomFactor == 1.0f) ?
|
||||
0 : (m_frequencyZoomPos - (0.5f / m_frequencyZoomFactor)) * m_settings.m_fftSize;
|
||||
int fftMax = (m_frequencyZoomFactor == 1.0f) ?
|
||||
m_settings.m_fftSize : (m_frequencyZoomPos + (0.5f / m_frequencyZoomFactor)) * m_settings.m_fftSize;
|
||||
|
||||
// apply fft window (and copy from m_fftBuffer to m_fftIn)
|
||||
m_window.apply(&m_fftBuffer[0], m_fft->in());
|
||||
|
||||
// calculate FFT
|
||||
m_fft->transform();
|
||||
|
||||
// extract power spectrum and reorder buckets
|
||||
const Complex* fftOut = m_fft->out();
|
||||
Complex c;
|
||||
Real v;
|
||||
std::size_t halfSize = m_settings.m_fftSize / 2;
|
||||
|
||||
if (m_settings.m_averagingMode == SpectrumSettings::AvgModeNone)
|
||||
{
|
||||
m_specMax = 0.0f;
|
||||
|
||||
if ( positiveOnly )
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
m_psd[i] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i * 2] = v;
|
||||
m_powerSpectrum[i * 2 + 1] = v;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i + halfSize];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
m_psd[i] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i] = v;
|
||||
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
m_psd[i + halfSize] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i + halfSize] = v;
|
||||
}
|
||||
}
|
||||
|
||||
// send new data to visualisation
|
||||
if (m_glSpectrum)
|
||||
{
|
||||
m_glSpectrum->newSpectrum(
|
||||
&m_powerSpectrum.data()[fftMin],
|
||||
fftMax - fftMin,
|
||||
m_settings.m_fftSize
|
||||
);
|
||||
}
|
||||
|
||||
// web socket spectrum connections
|
||||
if (m_wsSpectrum.socketOpened())
|
||||
{
|
||||
m_wsSpectrum.newSpectrum(
|
||||
m_powerSpectrum,
|
||||
m_settings.m_fftSize,
|
||||
m_centerFrequency,
|
||||
m_sampleRate,
|
||||
m_settings.m_linear,
|
||||
m_settings.m_ssb,
|
||||
m_settings.m_usb
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (m_settings.m_averagingMode == SpectrumSettings::AvgModeMoving)
|
||||
{
|
||||
m_specMax = 0.0f;
|
||||
|
||||
if ( positiveOnly )
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
v = m_movingAverage.storeAndGetAvg(v, i);
|
||||
m_psd[i] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i * 2] = v;
|
||||
m_powerSpectrum[i * 2 + 1] = v;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i + halfSize];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
v = m_movingAverage.storeAndGetAvg(v, i+halfSize);
|
||||
m_psd[i] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i] = v;
|
||||
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
v = m_movingAverage.storeAndGetAvg(v, i);
|
||||
m_psd[i + halfSize] = v/m_powFFTDiv;
|
||||
m_specMax = v > m_specMax ? v : m_specMax;
|
||||
v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs;
|
||||
m_powerSpectrum[i + halfSize] = v;
|
||||
}
|
||||
}
|
||||
|
||||
// send new data to visualisation
|
||||
if (m_glSpectrum)
|
||||
{
|
||||
m_glSpectrum->newSpectrum(
|
||||
&m_powerSpectrum.data()[fftMin],
|
||||
fftMax - fftMin,
|
||||
m_settings.m_fftSize
|
||||
);
|
||||
}
|
||||
|
||||
// web socket spectrum connections
|
||||
if (m_wsSpectrum.socketOpened())
|
||||
{
|
||||
m_wsSpectrum.newSpectrum(
|
||||
m_powerSpectrum,
|
||||
m_settings.m_fftSize,
|
||||
m_centerFrequency,
|
||||
m_sampleRate,
|
||||
m_settings.m_linear,
|
||||
m_settings.m_ssb,
|
||||
m_settings.m_usb
|
||||
);
|
||||
}
|
||||
|
||||
m_movingAverage.nextAverage();
|
||||
}
|
||||
else if (m_settings.m_averagingMode == SpectrumSettings::AvgModeFixed)
|
||||
{
|
||||
double avg;
|
||||
Real specMax = 0.0f;
|
||||
|
||||
if ( positiveOnly )
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_fixedAverage.storeAndGetAvg(avg, v, i))
|
||||
{
|
||||
m_psd[i] = avg/m_powFFTDiv;
|
||||
specMax = avg > specMax ? avg : specMax;
|
||||
avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
|
||||
m_powerSpectrum[i * 2] = avg;
|
||||
m_powerSpectrum[i * 2 + 1] = avg;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i + halfSize];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_fixedAverage.storeAndGetAvg(avg, v, i+halfSize))
|
||||
{
|
||||
m_psd[i] = avg/m_powFFTDiv;
|
||||
specMax = avg > specMax ? avg : specMax;
|
||||
avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
|
||||
m_powerSpectrum[i] = avg;
|
||||
}
|
||||
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_fixedAverage.storeAndGetAvg(avg, v, i))
|
||||
{
|
||||
m_psd[i + halfSize] = avg/m_powFFTDiv;
|
||||
specMax = avg > specMax ? avg : specMax;
|
||||
avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs;
|
||||
m_powerSpectrum[i + halfSize] = avg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// result available
|
||||
if (m_fixedAverage.nextAverage())
|
||||
{
|
||||
m_specMax = specMax;
|
||||
|
||||
// send new data to visualisation
|
||||
if (m_glSpectrum)
|
||||
{
|
||||
m_glSpectrum->newSpectrum(
|
||||
&m_powerSpectrum.data()[fftMin],
|
||||
fftMax - fftMin,
|
||||
m_settings.m_fftSize
|
||||
);
|
||||
}
|
||||
|
||||
// web socket spectrum connections
|
||||
if (m_wsSpectrum.socketOpened())
|
||||
{
|
||||
m_wsSpectrum.newSpectrum(
|
||||
m_powerSpectrum,
|
||||
m_settings.m_fftSize,
|
||||
m_centerFrequency,
|
||||
m_sampleRate,
|
||||
m_settings.m_linear,
|
||||
m_settings.m_ssb,
|
||||
m_settings.m_usb
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_settings.m_averagingMode == SpectrumSettings::AvgModeMax)
|
||||
{
|
||||
double max;
|
||||
Real specMax = 0.0f;
|
||||
|
||||
if ( positiveOnly )
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_max.storeAndGetMax(max, v, i))
|
||||
{
|
||||
m_psd[i] = max/m_powFFTDiv;
|
||||
specMax = max > specMax ? max : specMax;
|
||||
max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs;
|
||||
m_powerSpectrum[i * 2] = max;
|
||||
m_powerSpectrum[i * 2 + 1] = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < halfSize; i++)
|
||||
{
|
||||
c = fftOut[i + halfSize];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_max.storeAndGetMax(max, v, i+halfSize))
|
||||
{
|
||||
m_psd[i] = max/m_powFFTDiv;
|
||||
specMax = max > specMax ? max : specMax;
|
||||
max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs;
|
||||
m_powerSpectrum[i] = max;
|
||||
}
|
||||
|
||||
c = fftOut[i];
|
||||
v = c.real() * c.real() + c.imag() * c.imag();
|
||||
|
||||
// result available
|
||||
if (m_max.storeAndGetMax(max, v, i))
|
||||
{
|
||||
m_psd[i + halfSize] = max/m_powFFTDiv;
|
||||
specMax = max > specMax ? max : specMax;
|
||||
max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs;
|
||||
m_powerSpectrum[i + halfSize] = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// result available
|
||||
if (m_max.nextMax())
|
||||
{
|
||||
m_specMax = specMax;
|
||||
|
||||
// send new data to visualisation
|
||||
if (m_glSpectrum)
|
||||
{
|
||||
m_glSpectrum->newSpectrum(
|
||||
&m_powerSpectrum.data()[fftMin],
|
||||
fftMax - fftMin,
|
||||
m_settings.m_fftSize
|
||||
);
|
||||
}
|
||||
|
||||
// web socket spectrum connections
|
||||
if (m_wsSpectrum.socketOpened())
|
||||
{
|
||||
m_wsSpectrum.newSpectrum(
|
||||
m_powerSpectrum,
|
||||
m_settings.m_fftSize,
|
||||
m_centerFrequency,
|
||||
m_sampleRate,
|
||||
m_settings.m_linear,
|
||||
m_settings.m_ssb,
|
||||
m_settings.m_usb
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpectrumVis::getZoomedPSDCopy(std::vector<Real>& copy) const
|
||||
|
@ -151,6 +151,7 @@ public:
|
||||
void getZoomedPSDCopy(std::vector<Real>& copy) const;
|
||||
|
||||
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
|
||||
void feed(const ComplexVector::const_iterator& begin, const ComplexVector::const_iterator& end, bool positiveOnly);
|
||||
virtual void feed(const Complex *begin, unsigned int length); //!< direct FFT feed
|
||||
void feedTriggered(const SampleVector::const_iterator& triggerPoint, const SampleVector::const_iterator& end, bool positiveOnly);
|
||||
virtual void start();
|
||||
@ -243,6 +244,7 @@ private:
|
||||
|
||||
QMutex m_mutex;
|
||||
|
||||
void processFFT(bool positiveOnly);
|
||||
void setRunning(bool running) { m_running = running; }
|
||||
void applySettings(const SpectrumSettings& settings, bool force = false);
|
||||
void handleConfigureDSP(uint64_t centerFrequency, int sampleRate);
|
||||
|
Loading…
Reference in New Issue
Block a user