mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-05-24 11:12:27 -04: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 float Real;
|
||||||
typedef std::complex<Real> Complex;
|
typedef std::complex<Real> Complex;
|
||||||
|
typedef std::vector<Complex> ComplexVector;
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct Sample
|
struct Sample
|
||||||
|
@ -70,6 +70,7 @@ ScopeVis::ScopeVis() :
|
|||||||
{
|
{
|
||||||
setObjectName("ScopeVis");
|
setObjectName("ScopeVis");
|
||||||
m_traceDiscreteMemory.resize(GLScopeSettings::m_traceChunkDefaultSize); // arbitrary
|
m_traceDiscreteMemory.resize(GLScopeSettings::m_traceChunkDefaultSize); // arbitrary
|
||||||
|
m_convertBuffers.resize(GLScopeSettings::m_traceChunkDefaultSize);
|
||||||
|
|
||||||
for (int i = 0; i < (int) Projector::nbProjectionTypes; i++) {
|
for (int i = 0; i < (int) Projector::nbProjectionTypes; i++) {
|
||||||
m_projectorCache[i] = 0.0;
|
m_projectorCache[i] = 0.0;
|
||||||
@ -140,6 +141,7 @@ void ScopeVis::setNbStreams(uint32_t nbStreams)
|
|||||||
if (m_nbStreams != nbStreams)
|
if (m_nbStreams != nbStreams)
|
||||||
{
|
{
|
||||||
m_traceDiscreteMemory.setNbStreams(nbStreams);
|
m_traceDiscreteMemory.setNbStreams(nbStreams);
|
||||||
|
m_convertBuffers.setNbStreams(nbStreams);
|
||||||
m_nbStreams = 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)
|
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) {
|
if (vbegin.size() == 0) {
|
||||||
return;
|
return;
|
||||||
@ -447,11 +474,11 @@ void ScopeVis::feed(const std::vector<SampleVector::const_iterator>& vbegin, int
|
|||||||
m_triggerLocation = nbSamples;
|
m_triggerLocation = nbSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
SampleVector::const_iterator begin(vbegin[0]);
|
ComplexVector::const_iterator begin(vbegin[0]);
|
||||||
//const SampleVector::const_iterator end = vbegin[0] + nbSamples;
|
//const SampleVector::const_iterator end = vbegin[0] + nbSamples;
|
||||||
int triggerPointToEnd;
|
int triggerPointToEnd;
|
||||||
int remainder = nbSamples;
|
int remainder = nbSamples;
|
||||||
std::vector<SampleVector::const_iterator> nvbegin(vbegin);
|
std::vector<ComplexVector::const_iterator> nvbegin(vbegin);
|
||||||
|
|
||||||
//while (begin < end)
|
//while (begin < end)
|
||||||
while (remainder > 0)
|
while (remainder > 0)
|
||||||
@ -495,11 +522,11 @@ void ScopeVis::processMemoryTrace()
|
|||||||
traceMemoryIndex += GLScopeSettings::m_nbTraceMemories;
|
traceMemoryIndex += GLScopeSettings::m_nbTraceMemories;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SampleVector::const_iterator> mend;
|
std::vector<ComplexVector::const_iterator> mend;
|
||||||
m_traceDiscreteMemory.getEndPointAt(traceMemoryIndex, 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);
|
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);
|
TraceBackDiscreteMemory::moveIt(mbegin, mbegin_tb, -m_maxTraceDelay);
|
||||||
m_nbSamples = m_traceSize + 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;
|
int firstRemainder = length;
|
||||||
|
|
||||||
// memory storage
|
// memory storage
|
||||||
@ -579,7 +606,7 @@ void ScopeVis::processTrace(const std::vector<SampleVector::const_iterator>& vcb
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t triggerStreamIndex = triggerCondition->m_triggerData.m_streamIndex;
|
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
|
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 remainder;
|
||||||
int count = firstRemainder; // number of samples in traceback buffer past the current point
|
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);
|
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);
|
TraceBackDiscreteMemory::moveIt(mend, mbegin, -count);
|
||||||
|
|
||||||
if (m_traceStart) // start of trace processing
|
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)
|
if (m_maxTraceDelay > 0)
|
||||||
{ // trace back
|
{ // 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);
|
TraceBackDiscreteMemory::moveIt(mbegin, tbegin, - m_preTriggerDelay - m_maxTraceDelay);
|
||||||
processTraces(tbegin, m_maxTraceDelay, true);
|
processTraces(tbegin, m_maxTraceDelay, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_preTriggerDelay > 0)
|
if (m_preTriggerDelay > 0)
|
||||||
{ // pre-trigger
|
{ // pre-trigger
|
||||||
std::vector<SampleVector::const_iterator> tbegin(mbegin.size());
|
std::vector<ComplexVector::const_iterator> tbegin(mbegin.size());
|
||||||
TraceBackDiscreteMemory::moveIt(mbegin, tbegin, -m_preTriggerDelay);
|
TraceBackDiscreteMemory::moveIt(mbegin, tbegin, -m_preTriggerDelay);
|
||||||
processTraces(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 shift = (m_timeOfsProMill / 1000.0) * m_traceSize;
|
||||||
uint32_t length = m_traceSize / m_timeBase;
|
uint32_t length = m_traceSize / m_timeBase;
|
||||||
int remainder = ilength;
|
int remainder = ilength;
|
||||||
|
m_spectrumVis->feed(vcbegin[0], vcbegin[0] + ilength, false);
|
||||||
if (m_spectrumVis) {
|
|
||||||
m_spectrumVis->feed(vcbegin[0], vcbegin[0] + ilength, false); // TODO: use spectrum stream index
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((remainder > 0) && (m_nbSamples > 0))
|
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)
|
else if (projectionType == Projector::ProjectionMagDB)
|
||||||
{
|
{
|
||||||
Real re = vbegin[streamIndex]->m_real / SDR_RX_SCALEF;
|
Real re = vbegin[streamIndex]->real();
|
||||||
Real im = vbegin[streamIndex]->m_imag / SDR_RX_SCALEF;
|
Real im = vbegin[streamIndex]->imag();
|
||||||
double magsq = re*re + im*im;
|
double magsq = re*re + im*im;
|
||||||
float pdB = log10f(magsq) * 10.0f;
|
float pdB = log10f(magsq) * 10.0f;
|
||||||
float p = pdB - (100.0f * itData->m_ofs);
|
float p = pdB - (100.0f * itData->m_ofs);
|
||||||
|
@ -432,6 +432,7 @@ public:
|
|||||||
uint32_t getNbTraces() const { return m_traces.size(); }
|
uint32_t getNbTraces() const { return m_traces.size(); }
|
||||||
|
|
||||||
void feed(const std::vector<SampleVector::const_iterator>& vbegin, int nbSamples);
|
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 start();
|
||||||
//virtual void stop();
|
//virtual void stop();
|
||||||
bool handleMessage(const Message& message);
|
bool handleMessage(const Message& message);
|
||||||
@ -510,7 +511,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Complex trace stuff
|
* Complex trace stuff
|
||||||
*/
|
*/
|
||||||
typedef DoubleBufferSimple<Sample> TraceBuffer;
|
typedef DoubleBufferSimple<Complex> TraceBuffer;
|
||||||
|
|
||||||
struct TraceBackBuffer
|
struct TraceBackBuffer
|
||||||
{
|
{
|
||||||
@ -528,7 +529,7 @@ private:
|
|||||||
m_traceBuffer.reset();
|
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);
|
m_traceBuffer.write(begin, nbSamples);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,7 +537,7 @@ private:
|
|||||||
return m_traceBuffer.absoluteFill();
|
return m_traceBuffer.absoluteFill();
|
||||||
}
|
}
|
||||||
|
|
||||||
void current(SampleVector::iterator& it) {
|
void current(ComplexVector::iterator& it) {
|
||||||
m_traceBuffer.getCurrent(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;
|
m_endPoint = endPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
SampleVector::const_iterator getEndPoint() {
|
ComplexVector::const_iterator getEndPoint() {
|
||||||
return m_endPoint;
|
return m_endPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getEndPoint(SampleVector::const_iterator& it) {
|
void getEndPoint(ComplexVector::const_iterator& it) {
|
||||||
it = m_endPoint;
|
it = m_endPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SampleVector::const_iterator m_endPoint;
|
ComplexVector::const_iterator m_endPoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<TraceBackBuffer> TraceBackBufferStream;
|
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
|
struct TraceBackDiscreteMemory
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -747,20 +781,20 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Get current point at current memory position (first stream)
|
* Get current point at current memory position (first stream)
|
||||||
*/
|
*/
|
||||||
void getCurrent(SampleVector::iterator& it) {
|
void getCurrent(ComplexVector::iterator& it) {
|
||||||
current().current(it);
|
current().current(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current points at current memory position
|
* 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();
|
vit.clear();
|
||||||
|
|
||||||
for (unsigned int is = 0; is < m_traceBackBuffersStreams.size(); is++)
|
for (unsigned int is = 0; is < m_traceBackBuffersStreams.size(); is++)
|
||||||
{
|
{
|
||||||
SampleVector::iterator it;
|
ComplexVector::iterator it;
|
||||||
current(is).current(it);
|
current(is).current(it);
|
||||||
vit.push_back(it);
|
vit.push_back(it);
|
||||||
}
|
}
|
||||||
@ -769,14 +803,14 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Set end point at current memory position (first stream)
|
* Set end point at current memory position (first stream)
|
||||||
*/
|
*/
|
||||||
void setCurrentEndPoint(const SampleVector::iterator& it) {
|
void setCurrentEndPoint(const ComplexVector::iterator& it) {
|
||||||
current().setEndPoint(it);
|
current().setEndPoint(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set end points at current memory position
|
* 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++)
|
for (unsigned int is = 0; is < vit.size(); is++)
|
||||||
{
|
{
|
||||||
@ -791,20 +825,20 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Get end point at given memory position (first stream)
|
* 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);
|
at(index).getEndPoint(mend);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get end points at given memory position
|
* 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();
|
vend.clear();
|
||||||
|
|
||||||
for (unsigned int is = 0; is < m_traceBackBuffersStreams.size(); is++)
|
for (unsigned int is = 0; is < m_traceBackBuffersStreams.size(); is++)
|
||||||
{
|
{
|
||||||
SampleVector::const_iterator mend;
|
ComplexVector::const_iterator mend;
|
||||||
at(index, is).getEndPoint(mend);
|
at(index, is).getEndPoint(mend);
|
||||||
vend.push_back(mend);
|
vend.push_back(mend);
|
||||||
}
|
}
|
||||||
@ -813,14 +847,14 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Write trace at current memory position (first stream)
|
* 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);
|
current().write(begin, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write traces at current memory position
|
* 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++) {
|
for (unsigned int i = 0; i < vbegin.size(); i++) {
|
||||||
current().write(vbegin[i], length);
|
current().write(vbegin[i], length);
|
||||||
@ -830,14 +864,14 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Move buffer iterator by a certain amount (first stream)
|
* 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;
|
y = x + amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move buffers iterators by a certain 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++)
|
for (unsigned int i = 0; i < vx.size(); i++)
|
||||||
{
|
{
|
||||||
@ -1083,7 +1117,7 @@ private:
|
|||||||
computeLevels();
|
computeLevels();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool triggered(const Sample& s, TriggerCondition& triggerCondition)
|
bool triggered(const Complex& s, TriggerCondition& triggerCondition)
|
||||||
{
|
{
|
||||||
if (triggerCondition.m_triggerData.m_triggerLevel != m_level)
|
if (triggerCondition.m_triggerData.m_triggerLevel != m_level)
|
||||||
{
|
{
|
||||||
@ -1194,7 +1228,8 @@ private:
|
|||||||
int m_triggerLocation; //!< Trigger location from end point
|
int m_triggerLocation; //!< Trigger location from end point
|
||||||
int m_sampleRate; //!< Actual sample rate being used
|
int m_sampleRate; //!< Actual sample rate being used
|
||||||
int m_liveSampleRate; //!< Sample rate in live mode
|
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)
|
bool m_freeRun; //!< True if free running (trigger globally disabled)
|
||||||
int m_maxTraceDelay; //!< Maximum trace delay
|
int m_maxTraceDelay; //!< Maximum trace delay
|
||||||
TriggerComparator m_triggerComparator; //!< Compares sample level to trigger level
|
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)
|
* 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
|
* 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 finished it returns the number of unprocessed samples left in the buffer
|
||||||
* - if not finished it returns -1
|
* - 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
|
* Get maximum trace delay
|
||||||
|
@ -317,6 +317,56 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length)
|
|||||||
m_mutex.unlock();
|
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)
|
void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleVector::const_iterator& end, bool positiveOnly)
|
||||||
{
|
{
|
||||||
if (!m_running) {
|
if (!m_running) {
|
||||||
@ -333,10 +383,6 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
|
|||||||
}
|
}
|
||||||
|
|
||||||
SampleVector::const_iterator begin(cbegin);
|
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)
|
while (begin < end)
|
||||||
{
|
{
|
||||||
@ -348,316 +394,11 @@ void SpectrumVis::feed(const SampleVector::const_iterator& cbegin, const SampleV
|
|||||||
// fill up the buffer
|
// fill up the buffer
|
||||||
std::vector<Complex>::iterator it = m_fftBuffer.begin() + m_fftBufferFill;
|
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);
|
*it++ = Complex(begin->real() / m_scalef, begin->imag() / m_scalef);
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply fft window (and copy from m_fftBuffer to m_fftIn)
|
processFFT(positiveOnly);
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// advance buffer respecting the fft overlap factor
|
// advance buffer respecting the fft overlap factor
|
||||||
std::copy(m_fftBuffer.begin() + m_refillSize, m_fftBuffer.end(), m_fftBuffer.begin());
|
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
|
else
|
||||||
{
|
{
|
||||||
// not enough samples for FFT - just fill in new data and return
|
// 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);
|
*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
|
void SpectrumVis::getZoomedPSDCopy(std::vector<Real>& copy) const
|
||||||
|
@ -151,6 +151,7 @@ public:
|
|||||||
void getZoomedPSDCopy(std::vector<Real>& copy) const;
|
void getZoomedPSDCopy(std::vector<Real>& copy) const;
|
||||||
|
|
||||||
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
|
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
|
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);
|
void feedTriggered(const SampleVector::const_iterator& triggerPoint, const SampleVector::const_iterator& end, bool positiveOnly);
|
||||||
virtual void start();
|
virtual void start();
|
||||||
@ -243,6 +244,7 @@ private:
|
|||||||
|
|
||||||
QMutex m_mutex;
|
QMutex m_mutex;
|
||||||
|
|
||||||
|
void processFFT(bool positiveOnly);
|
||||||
void setRunning(bool running) { m_running = running; }
|
void setRunning(bool running) { m_running = running; }
|
||||||
void applySettings(const SpectrumSettings& settings, bool force = false);
|
void applySettings(const SpectrumSettings& settings, bool force = false);
|
||||||
void handleConfigureDSP(uint64_t centerFrequency, int sampleRate);
|
void handleConfigureDSP(uint64_t centerFrequency, int sampleRate);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user