Experimenting with max speed waterfall (no dropped FFTs :)

- FFT Detail from zoomed-in views is greatly improved with the
additional data
This commit is contained in:
Charles J. Cliffe 2015-08-11 00:50:43 -04:00
parent dfd02c1b12
commit 0802f7b756
9 changed files with 195 additions and 104 deletions

View File

@ -120,12 +120,18 @@ AppFrame::AppFrame() :
vbox->AddSpacer(1);
wxGetApp().getSpectrumProcesor()->attachOutput(spectrumCanvas->getVisualDataQueue());
wxGetApp().getWaterfallProcesor()->setup(2048);
waterfallCanvas = new WaterfallCanvas(this, attribList);
waterfallCanvas->setup(2048, 512);
waterfallCanvas->attachSpectrumCanvas(spectrumCanvas);
spectrumCanvas->attachWaterfallCanvas(waterfallCanvas);
vbox->Add(waterfallCanvas, 20, wxEXPAND | wxALL, 0);
wxGetApp().getSpectrumProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue());
// wxGetApp().getSpectrumProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue());
fftDistrib.setInput(wxGetApp().getWaterfallVisualQueue());
fftDistrib.attachOutput(&fftQueue);
wxGetApp().getWaterfallProcesor()->setInput(&fftQueue);
wxGetApp().getWaterfallProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue());
/*
vbox->AddSpacer(1);
testCanvas = new UITestCanvas(this, attribList);
@ -690,9 +696,9 @@ void AppFrame::OnTimer(wxTimerEvent& event) {
SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcesor();
proc->setView(waterfallCanvas->getViewState());
proc->setBandwidth(waterfallCanvas->getBandwidth());
proc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
proc->setView(spectrumCanvas->getViewState());
proc->setBandwidth(spectrumCanvas->getBandwidth());
proc->setCenterFrequency(spectrumCanvas->getCenterFrequency());
proc->run();
@ -704,6 +710,27 @@ void AppFrame::OnTimer(wxTimerEvent& event) {
dproc->run();
SpectrumVisualProcessor *wproc = wxGetApp().getWaterfallProcesor();
int fftSize = wproc->getDesiredInputSize();
if (fftSize) {
fftDistrib.setFFTSize(fftSize);
} else {
fftDistrib.setFFTSize(DEFAULT_FFT_SIZE);
}
fftDistrib.run();
wproc->setView(waterfallCanvas->getViewState());
wproc->setBandwidth(waterfallCanvas->getBandwidth());
wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
while (!wproc->isInputEmpty()) {
wproc->run();
}
scopeCanvas->Refresh();
waterfallCanvas->Refresh();

View File

@ -96,5 +96,8 @@ private:
std::string currentSessionFile;
wxTimer frame_timer;
FFTDataDistributor fftDistrib;
DemodulatorThreadInputQueue fftQueue;
wxDECLARE_EVENT_TABLE();
};

View File

@ -63,6 +63,8 @@ bool CubicSDR::OnInit() {
pipeSpectrumIQVisualData = new DemodulatorThreadInputQueue();
pipeIQVisualData->set_max_num_items(1);
pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue();
spectrumDistributor.attachOutput(pipeDemodIQVisualData);
spectrumDistributor.attachOutput(pipeSpectrumIQVisualData);
@ -85,8 +87,9 @@ bool CubicSDR::OnInit() {
sdrPostThread = new SDRPostThread();
sdrPostThread->setNumVisSamples(16384 * 2);
sdrPostThread->setInputQueue("IQDataInput", pipeSDRIQData);
sdrPostThread->setOutputQueue("IQVisualDataOut", pipeIQVisualData);
sdrPostThread->setOutputQueue("IQVisualDataOutput", pipeIQVisualData);
sdrPostThread->setOutputQueue("IQDataOutput", pipeWaterfallIQVisualData);
std::vector<SDRDeviceInfo *>::iterator devs_i;
SDRThread::enumerate_rtl(&devs);
@ -276,6 +279,10 @@ SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcesor() {
return &demodSpectrumProcessor;
}
SpectrumVisualProcessor *CubicSDR::getWaterfallProcesor() {
return &waterfallProcessor;
}
VisualDataDistributor<DemodulatorThreadIQData> *CubicSDR::getSpectrumDistributor() {
return &spectrumDistributor;
}
@ -289,6 +296,10 @@ DemodulatorThreadInputQueue* CubicSDR::getIQVisualQueue() {
return pipeIQVisualData;
}
DemodulatorThreadInputQueue* CubicSDR::getWaterfallVisualQueue() {
return pipeWaterfallIQVisualData;
}
DemodulatorMgr &CubicSDR::getDemodMgr() {
return demodMgr;
}

View File

@ -58,10 +58,12 @@ public:
ScopeVisualProcessor *getScopeProcessor();
SpectrumVisualProcessor *getSpectrumProcesor();
SpectrumVisualProcessor *getDemodSpectrumProcesor();
SpectrumVisualProcessor *getWaterfallProcesor();
VisualDataDistributor<DemodulatorThreadIQData> *getSpectrumDistributor();
DemodulatorThreadOutputQueue* getAudioVisualQueue();
DemodulatorThreadInputQueue* getIQVisualQueue();
DemodulatorThreadInputQueue* getWaterfallVisualQueue();
DemodulatorMgr &getDemodMgr();
void bindDemodulator(DemodulatorInstance *demod);
@ -101,9 +103,11 @@ private:
DemodulatorThreadOutputQueue* pipeAudioVisualData;
DemodulatorThreadInputQueue* pipeDemodIQVisualData;
DemodulatorThreadInputQueue* pipeSpectrumIQVisualData;
DemodulatorThreadInputQueue* pipeWaterfallIQVisualData;
ScopeVisualProcessor scopeProcessor;
SpectrumVisualProcessor spectrumProcessor;
SpectrumVisualProcessor waterfallProcessor;
SpectrumVisualProcessor demodSpectrumProcessor;
VisualDataDistributor<DemodulatorThreadIQData> spectrumDistributor;

View File

@ -14,6 +14,7 @@ SpectrumVisualProcessor::SpectrumVisualProcessor() : lastInputBandwidth(0), last
fft_ceil_ma = fft_ceil_maa = 100.0;
fft_floor_ma = fft_floor_maa = 0.0;
desiredInputSize = 0;
}
SpectrumVisualProcessor::~SpectrumVisualProcessor() {
@ -45,8 +46,13 @@ long SpectrumVisualProcessor::getBandwidth() {
return bandwidth.load();
}
int SpectrumVisualProcessor::getDesiredInputSize() {
return desiredInputSize;
}
void SpectrumVisualProcessor::setup(int fftSize_in) {
fftSize = fftSize_in;
desiredInputSize = fftSize;
if (fftwInput) {
free(fftwInput);
@ -103,6 +109,8 @@ void SpectrumVisualProcessor::process() {
int desired_input_size = fftSize / resamplerRatio;
this->desiredInputSize = desired_input_size;
if (iqData->data.size() < desired_input_size) {
// std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl;
desired_input_size = iqData->data.size();
@ -280,5 +288,7 @@ void SpectrumVisualProcessor::process() {
distribute(output);
}
iqData->decRefCount();
}

View File

@ -26,6 +26,8 @@ public:
void setBandwidth(long bandwidth_in);
long getBandwidth();
int getDesiredInputSize();
void setup(int fftSize);
protected:
@ -59,4 +61,39 @@ private:
std::vector<liquid_float_complex> shiftBuffer;
std::vector<liquid_float_complex> resampleBuffer;
int desiredInputSize;
};
class FFTDataDistributor : public VisualProcessor<DemodulatorThreadIQData, DemodulatorThreadIQData> {
public:
void setFFTSize(int fftSize) {
this->fftSize = fftSize;
}
protected:
void process() {
while (!input->empty()) {
if (!isAnyOutputEmpty()) {
return;
}
DemodulatorThreadIQData *inp;
input->pop(inp);
if (inp) {
if (inp->data.size() >= fftSize) {
for (int i = 0, iMax = inp->data.size()-fftSize; i < iMax; i += fftSize) {
DemodulatorThreadIQData *outp = outputBuffers.getBuffer();
outp->frequency = inp->frequency;
outp->sampleRate = inp->sampleRate;
outp->data.assign(inp->data.begin()+i,inp->data.begin()+i+fftSize);
distribute(outp);
}
}
inp->decRefCount();
}
}
}
ReBuffer<DemodulatorThreadIQData> outputBuffers;
int fftSize;
};

View File

@ -11,6 +11,28 @@ public:
virtual ~VisualProcessor() {
}
bool isInputEmpty() {
return input->empty();
}
bool isOutputEmpty() {
for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) {
if ((*outputs_i)->full()) {
return false;
}
}
return true;
}
bool isAnyOutputEmpty() {
for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) {
if (!(*outputs_i)->full()) {
return true;
}
}
return false;
}
void setInput(ThreadQueue<InputDataType *> *vis_in) {
busy_update.lock();
@ -60,24 +82,6 @@ protected:
}
}
}
bool isOutputEmpty() {
for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) {
if (!(*outputs_i)->empty()) {
return false;
}
}
return true;
}
bool isAnyOutputEmpty() {
for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) {
if ((*outputs_i)->empty()) {
return true;
}
}
return false;
}
ThreadQueue<InputDataType *> *input;
std::vector<ThreadQueue<OutputDataType *> *> outputs;
@ -90,10 +94,10 @@ template<class OutputDataType = ReferenceCounter>
class VisualDataDistributor : public VisualProcessor<OutputDataType, OutputDataType> {
protected:
void process() {
if (!VisualProcessor<OutputDataType, OutputDataType>::isOutputEmpty()) {
return;
}
while (!VisualProcessor<OutputDataType, OutputDataType>::input->empty()) {
if (!VisualProcessor<OutputDataType, OutputDataType>::isAnyOutputEmpty()) {
return;
}
OutputDataType *inp;
VisualProcessor<OutputDataType, OutputDataType>::input->pop(inp);
if (inp) {

View File

@ -82,18 +82,18 @@ void SDRPostThread::run() {
iqDataInQueue = (SDRThreadIQDataQueue*)getInputQueue("IQDataInput");
iqDataOutQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQDataOutput");
iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOut");
iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOutput");
ReBuffer<DemodulatorThreadIQData> buffers;
std::vector<liquid_float_complex> fpData;
std::vector<liquid_float_complex> dataOut;
while (!terminated) {
SDRThreadIQData *data_in;
iqDataInQueue->pop(data_in);
// std::lock_guard < std::mutex > lock(data_in->m_mutex);
// std::lock_guard < std::mutex > lock(data_in->m_mutex);
if (data_in && data_in->data.size()) {
int dataSize = data_in->data.size()/2;
if (dataSize > fpData.capacity()) {
@ -104,7 +104,7 @@ void SDRPostThread::run() {
fpData.resize(dataSize);
dataOut.resize(dataSize);
}
if (swapIQ) {
for (int i = 0; i < dataSize; i++) {
fpData[i] = _lut_swap[*((uint16_t*)&data_in->data[2*i])];
@ -114,106 +114,101 @@ void SDRPostThread::run() {
fpData[i] = _lut[*((uint16_t*)&data_in->data[2*i])];
}
}
iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]);
if (iqDataOutQueue != NULL) {
DemodulatorThreadIQData *pipeDataOut = new DemodulatorThreadIQData;
pipeDataOut->frequency = data_in->frequency;
pipeDataOut->sampleRate = data_in->sampleRate;
pipeDataOut->data.assign(dataOut.begin(), dataOut.end());
iqDataOutQueue->push(pipeDataOut);
}
if (iqVisualQueue != NULL && iqVisualQueue->empty()) {
visualDataOut->busy_rw.lock();
if (visualDataOut->data.size() < num_vis_samples) {
if (visualDataOut->data.capacity() < num_vis_samples) {
visualDataOut->data.reserve(num_vis_samples);
}
visualDataOut->data.resize(num_vis_samples);
}
visualDataOut->frequency = data_in->frequency;
visualDataOut->sampleRate = data_in->sampleRate;
visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples);
iqVisualQueue->push(visualDataOut);
visualDataOut->busy_rw.unlock();
}
busy_demod.lock();
int activeDemods = 0;
bool pushedData = false;
if (demodulators.size()) {
std::vector<DemodulatorInstance *>::iterator i;
for (i = demodulators.begin(); i != demodulators.end(); i++) {
DemodulatorInstance *demod = *i;
if (demodulators.size() || iqDataOutQueue != NULL) {
std::vector<DemodulatorInstance *>::iterator demod_i;
for (demod_i = demodulators.begin(); demod_i != demodulators.end(); demod_i++) {
DemodulatorInstance *demod = *demod_i;
if (demod->getFrequency() != data_in->frequency
&& abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
&& abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
continue;
}
activeDemods++;
}
if (demodulators.size()) {
DemodulatorThreadIQData *demodDataOut = buffers.getBuffer();
// std::lock_guard < std::mutex > lock(demodDataOut->m_mutex);
demodDataOut->frequency = data_in->frequency;
demodDataOut->sampleRate = data_in->sampleRate;
demodDataOut->setRefCount(activeDemods);
demodDataOut->data.assign(dataOut.begin(), dataOut.end());
std::vector<DemodulatorInstance *>::iterator i;
for (i = demodulators.begin(); i != demodulators.end(); i++) {
DemodulatorInstance *demod = *i;
DemodulatorThreadInputQueue *demodQueue = demod->getIQInputDataPipe();
if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) {
demod->setActive(false);
DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData;
dummyDataOut->frequency = data_in->frequency;
dummyDataOut->sampleRate = data_in->sampleRate;
demodQueue->push(dummyDataOut);
}
if (demod->isFollow() && wxGetApp().getFrequency() != demod->getFrequency()) {
wxGetApp().setFrequency(demod->getFrequency());
}
} else if (!demod->isActive()) {
demod->setActive(true);
if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) {
wxGetApp().getDemodMgr().setActiveDemodulator(demod);
}
if (iqDataOutQueue != NULL) {
activeDemods++;
}
DemodulatorThreadIQData *demodDataOut = buffers.getBuffer();
// std::lock_guard < std::mutex > lock(demodDataOut->m_mutex);
demodDataOut->frequency = data_in->frequency;
demodDataOut->sampleRate = data_in->sampleRate;
demodDataOut->setRefCount(activeDemods);
demodDataOut->data.assign(dataOut.begin(), dataOut.end());
for (demod_i = demodulators.begin(); demod_i != demodulators.end(); demod_i++) {
DemodulatorInstance *demod = *demod_i;
DemodulatorThreadInputQueue *demodQueue = demod->getIQInputDataPipe();
if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) {
demod->setActive(false);
DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData;
dummyDataOut->frequency = data_in->frequency;
dummyDataOut->sampleRate = data_in->sampleRate;
demodQueue->push(dummyDataOut);
}
if (!demod->isActive()) {
continue;
if (demod->isFollow() && wxGetApp().getFrequency() != demod->getFrequency()) {
wxGetApp().setFrequency(demod->getFrequency());
}
if (demod->isFollow()) {
demod->setFollow(false);
} else if (!demod->isActive()) {
demod->setActive(true);
if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) {
wxGetApp().getDemodMgr().setActiveDemodulator(demod);
}
demodQueue->push(demodDataOut);
pushedData = true;
}
if (!pushedData) {
demodDataOut->setRefCount(0);
if (!demod->isActive()) {
continue;
}
if (demod->isFollow()) {
demod->setFollow(false);
}
demodQueue->push(demodDataOut);
pushedData = true;
}
if (iqDataOutQueue != NULL) {
iqDataOutQueue->push(demodDataOut);
pushedData = true;
}
if (!pushedData && iqDataOutQueue == NULL) {
demodDataOut->setRefCount(0);
}
}
busy_demod.unlock();
}
data_in->decRefCount();

View File

@ -140,7 +140,7 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
initGLExtensions();
glViewport(0, 0, ClientSize.x, ClientSize.y);
if (!visualDataQueue.empty()) {
while (!visualDataQueue.empty()) {
SpectrumVisualData *vData;
visualDataQueue.pop(vData);