Experimental waterfall zoom
This commit is contained in:
parent
4f43f65065
commit
ce75eed995
|
@ -79,6 +79,7 @@ AppFrame::AppFrame() :
|
||||||
demodWaterfallCanvas->Setup(1024, 256);
|
demodWaterfallCanvas->Setup(1024, 256);
|
||||||
demodWaterfallCanvas->SetView(DEFAULT_FREQ, 300000);
|
demodWaterfallCanvas->SetView(DEFAULT_FREQ, 300000);
|
||||||
demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas);
|
demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas);
|
||||||
|
demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas);
|
||||||
demodVisuals->Add(demodWaterfallCanvas, 3, wxEXPAND | wxALL, 0);
|
demodVisuals->Add(demodWaterfallCanvas, 3, wxEXPAND | wxALL, 0);
|
||||||
|
|
||||||
demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0);
|
demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0);
|
||||||
|
@ -103,6 +104,7 @@ AppFrame::AppFrame() :
|
||||||
waterfallCanvas = new WaterfallCanvas(this, NULL);
|
waterfallCanvas = new WaterfallCanvas(this, NULL);
|
||||||
waterfallCanvas->Setup(2048, 512);
|
waterfallCanvas->Setup(2048, 512);
|
||||||
waterfallCanvas->attachSpectrumCanvas(spectrumCanvas);
|
waterfallCanvas->attachSpectrumCanvas(spectrumCanvas);
|
||||||
|
spectrumCanvas->attachWaterfallCanvas(waterfallCanvas);
|
||||||
vbox->Add(waterfallCanvas, 4, wxEXPAND | wxALL, 0);
|
vbox->Add(waterfallCanvas, 4, wxEXPAND | wxALL, 0);
|
||||||
|
|
||||||
this->SetSizer(vbox);
|
this->SetSizer(vbox);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "AppFrame.h"
|
#include "AppFrame.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <wx/numformatter.h>
|
#include <wx/numformatter.h>
|
||||||
|
#include "WaterfallCanvas.h"
|
||||||
|
|
||||||
wxBEGIN_EVENT_TABLE(SpectrumCanvas, wxGLCanvas) EVT_PAINT(SpectrumCanvas::OnPaint)
|
wxBEGIN_EVENT_TABLE(SpectrumCanvas, wxGLCanvas) EVT_PAINT(SpectrumCanvas::OnPaint)
|
||||||
EVT_IDLE(SpectrumCanvas::OnIdle)
|
EVT_IDLE(SpectrumCanvas::OnIdle)
|
||||||
|
@ -27,7 +28,8 @@ wxEND_EVENT_TABLE()
|
||||||
|
|
||||||
SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) :
|
SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) :
|
||||||
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
|
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
|
||||||
wxFULL_REPAINT_ON_RESIZE), parent(parent), fft_size(0), in(NULL), out(NULL), plan(NULL), center_freq(0), bandwidth(0), isView(0) {
|
wxFULL_REPAINT_ON_RESIZE), parent(parent), fft_size(0), in(NULL), out(NULL), plan(NULL), waterfallCanvas(NULL), center_freq(0), bandwidth(0), isView(
|
||||||
|
0) {
|
||||||
|
|
||||||
glContext = new SpectrumContext(this, &wxGetApp().GetContext(this));
|
glContext = new SpectrumContext(this, &wxGetApp().GetContext(this));
|
||||||
|
|
||||||
|
@ -57,7 +59,6 @@ void SpectrumCanvas::Setup(int fft_size_in) {
|
||||||
}
|
}
|
||||||
plan = fftw_plan_dft_1d(fft_size, in, out, FFTW_FORWARD, FFTW_MEASURE);
|
plan = fftw_plan_dft_1d(fft_size, in, out, FFTW_FORWARD, FFTW_MEASURE);
|
||||||
|
|
||||||
|
|
||||||
fft_ceil_ma = fft_ceil_maa = 100.0;
|
fft_ceil_ma = fft_ceil_maa = 100.0;
|
||||||
fft_floor_ma = fft_floor_maa = 0.0;
|
fft_floor_ma = fft_floor_maa = 0.0;
|
||||||
}
|
}
|
||||||
|
@ -171,8 +172,6 @@ void SpectrumCanvas::setData(DemodulatorThreadIQData *input) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SpectrumCanvas::SetView(int center_freq_in, int bandwidth_in) {
|
void SpectrumCanvas::SetView(int center_freq_in, int bandwidth_in) {
|
||||||
isView = true;
|
isView = true;
|
||||||
center_freq = center_freq_in;
|
center_freq = center_freq_in;
|
||||||
|
@ -181,7 +180,10 @@ void SpectrumCanvas::SetView(int center_freq_in, int bandwidth_in) {
|
||||||
|
|
||||||
void SpectrumCanvas::DisableView() {
|
void SpectrumCanvas::DisableView() {
|
||||||
isView = false;
|
isView = false;
|
||||||
|
center_freq = wxGetApp().getFrequency();
|
||||||
|
bandwidth = SRATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectrumCanvas::SetCenterFrequency(unsigned int center_freq_in) {
|
void SpectrumCanvas::SetCenterFrequency(unsigned int center_freq_in) {
|
||||||
center_freq = center_freq_in;
|
center_freq = center_freq_in;
|
||||||
}
|
}
|
||||||
|
@ -217,13 +219,33 @@ void SpectrumCanvas::mouseMoved(wxMouseEvent& event) {
|
||||||
|
|
||||||
if (freqChange != 0) {
|
if (freqChange != 0) {
|
||||||
int freq = wxGetApp().getFrequency();
|
int freq = wxGetApp().getFrequency();
|
||||||
|
|
||||||
|
if (isView) {
|
||||||
|
center_freq -= freqChange;
|
||||||
|
if (waterfallCanvas) {
|
||||||
|
waterfallCanvas->SetCenterFrequency(center_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SRATE/2 < (abs(freq-center_freq)+bandwidth/2)) {
|
||||||
|
// if (center_freq < freq) {
|
||||||
|
// freqChange = -((center_freq - (freq - bandwidth / 2)) - (SRATE/2));
|
||||||
|
// } else {
|
||||||
|
// freqChange = ((freq + bandwidth / 2) - center_freq - (SRATE/2));
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
freqChange = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (freqChange) {
|
||||||
freq -= freqChange;
|
freq -= freqChange;
|
||||||
wxGetApp().setFrequency(freq);
|
wxGetApp().setFrequency(freq);
|
||||||
|
|
||||||
((wxFrame*) parent)->GetStatusBar()->SetStatusText(
|
((wxFrame*) parent)->GetStatusBar()->SetStatusText(
|
||||||
wxString::Format(wxT("Set center frequency: %s"),
|
wxString::Format(wxT("Set center frequency: %s"),
|
||||||
wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep)));
|
wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,6 +268,9 @@ void SpectrumCanvas::mouseLeftWindow(wxMouseEvent& event) {
|
||||||
SetCursor(wxCURSOR_SIZEWE);
|
SetCursor(wxCURSOR_SIZEWE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpectrumCanvas::attachWaterfallCanvas(WaterfallCanvas* canvas_in) {
|
||||||
|
waterfallCanvas = canvas_in;
|
||||||
|
}
|
||||||
//void SpectrumCanvas::rightClick(wxMouseEvent& event) {}
|
//void SpectrumCanvas::rightClick(wxMouseEvent& event) {}
|
||||||
//void SpectrumCanvas::keyPressed(wxKeyEvent& event) {}
|
//void SpectrumCanvas::keyPressed(wxKeyEvent& event) {}
|
||||||
//void SpectrumCanvas::keyReleased(wxKeyEvent& event) {}
|
//void SpectrumCanvas::keyReleased(wxKeyEvent& event) {}
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include "fftw3.h"
|
#include "fftw3.h"
|
||||||
#include "MouseTracker.h"
|
#include "MouseTracker.h"
|
||||||
|
|
||||||
|
class WaterfallCanvas;
|
||||||
|
|
||||||
class SpectrumCanvas: public wxGLCanvas {
|
class SpectrumCanvas: public wxGLCanvas {
|
||||||
public:
|
public:
|
||||||
std::vector<float> spectrum_points;
|
std::vector<float> spectrum_points;
|
||||||
|
@ -30,6 +32,8 @@ public:
|
||||||
void SetBandwidth(unsigned int bandwidth_in);
|
void SetBandwidth(unsigned int bandwidth_in);
|
||||||
unsigned int GetBandwidth();
|
unsigned int GetBandwidth();
|
||||||
|
|
||||||
|
void attachWaterfallCanvas(WaterfallCanvas *canvas_in);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnPaint(wxPaintEvent& event);
|
void OnPaint(wxPaintEvent& event);
|
||||||
|
|
||||||
|
@ -56,6 +60,7 @@ private:
|
||||||
std::vector<double> fft_result_maa;
|
std::vector<double> fft_result_maa;
|
||||||
|
|
||||||
SpectrumContext *glContext;
|
SpectrumContext *glContext;
|
||||||
|
WaterfallCanvas *waterfallCanvas;
|
||||||
int fft_size;
|
int fft_size;
|
||||||
|
|
||||||
unsigned int center_freq;
|
unsigned int center_freq;
|
||||||
|
|
|
@ -35,7 +35,7 @@ WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
|
||||||
wxFULL_REPAINT_ON_RESIZE), parent(parent), spectrumCanvas(NULL), activeDemodulatorBandwidth(0), activeDemodulatorFrequency(0), dragState(
|
wxFULL_REPAINT_ON_RESIZE), parent(parent), spectrumCanvas(NULL), activeDemodulatorBandwidth(0), activeDemodulatorFrequency(0), dragState(
|
||||||
WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), shiftDown(false), altDown(false), ctrlDown(false), fft_size(0), waterfall_lines(0), plan(
|
WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), shiftDown(false), altDown(false), ctrlDown(false), fft_size(0), waterfall_lines(0), plan(
|
||||||
NULL), in(NULL), out(NULL), center_freq(0), bandwidth(0), isView(false), resampler(NULL), resample_ratio(0), last_bandwidth(0), last_input_bandwidth(
|
NULL), in(NULL), out(NULL), center_freq(0), bandwidth(0), isView(false), resampler(NULL), resample_ratio(0), last_bandwidth(0), last_input_bandwidth(
|
||||||
0) {
|
0), zoom(0) {
|
||||||
|
|
||||||
glContext = new WaterfallContext(this, &wxGetApp().GetContext(this));
|
glContext = new WaterfallContext(this, &wxGetApp().GetContext(this));
|
||||||
|
|
||||||
|
@ -62,6 +62,9 @@ void WaterfallCanvas::SetView(int center_freq_in, int bandwidth_in) {
|
||||||
|
|
||||||
void WaterfallCanvas::DisableView() {
|
void WaterfallCanvas::DisableView() {
|
||||||
isView = false;
|
isView = false;
|
||||||
|
center_freq = wxGetApp().getFrequency();
|
||||||
|
bandwidth = SRATE;
|
||||||
|
last_bandwidth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterfallCanvas::Setup(int fft_size_in, int waterfall_lines_in) {
|
void WaterfallCanvas::Setup(int fft_size_in, int waterfall_lines_in) {
|
||||||
|
@ -221,8 +224,14 @@ void WaterfallCanvas::OnKeyUp(wxKeyEvent& event) {
|
||||||
shiftDown = event.ShiftDown();
|
shiftDown = event.ShiftDown();
|
||||||
altDown = event.AltDown();
|
altDown = event.AltDown();
|
||||||
ctrlDown = event.ControlDown();
|
ctrlDown = event.ControlDown();
|
||||||
// switch (event.GetKeyCode()) {
|
switch (event.GetKeyCode()) {
|
||||||
// }
|
case 'A':
|
||||||
|
zoom = 0;
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
zoom = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
|
void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
|
||||||
|
@ -235,8 +244,14 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
|
||||||
DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
|
DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
|
||||||
|
|
||||||
unsigned int freq;
|
unsigned int freq;
|
||||||
if (!isView) {
|
unsigned int bw;
|
||||||
switch (event.GetKeyCode()) {
|
switch (event.GetKeyCode()) {
|
||||||
|
case 'A':
|
||||||
|
zoom = 1;
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
zoom = -1;
|
||||||
|
break;
|
||||||
case WXK_RIGHT:
|
case WXK_RIGHT:
|
||||||
freq = wxGetApp().getFrequency();
|
freq = wxGetApp().getFrequency();
|
||||||
if (shiftDown) {
|
if (shiftDown) {
|
||||||
|
@ -290,23 +305,55 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void WaterfallCanvas::setData(DemodulatorThreadIQData *input) {
|
void WaterfallCanvas::setData(DemodulatorThreadIQData *input) {
|
||||||
if (!input) {
|
if (!input) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int bw;
|
||||||
|
if (zoom) {
|
||||||
|
if (zoom > 0) {
|
||||||
|
center_freq = GetCenterFrequency();
|
||||||
|
bw = GetBandwidth();
|
||||||
|
bw = (unsigned int) ceil((float) bw * 0.95);
|
||||||
|
if (bw < 80000) {
|
||||||
|
bw = 80000;
|
||||||
|
}
|
||||||
|
SetView(center_freq, bw);
|
||||||
|
if (spectrumCanvas) {
|
||||||
|
spectrumCanvas->SetView(center_freq, bw);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isView) {
|
||||||
|
bw = GetBandwidth();
|
||||||
|
bw = (unsigned int) ceil((float) bw * 1.05);
|
||||||
|
if ((int) bw >= SRATE) {
|
||||||
|
bw = (unsigned int) SRATE;
|
||||||
|
DisableView();
|
||||||
|
if (spectrumCanvas) {
|
||||||
|
spectrumCanvas->DisableView();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SetView(GetCenterFrequency(), bw);
|
||||||
|
if (spectrumCanvas) {
|
||||||
|
spectrumCanvas->SetView(center_freq, bw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<liquid_float_complex> *data = &input->data;
|
std::vector<liquid_float_complex> *data = &input->data;
|
||||||
|
|
||||||
if (data && data->size()) {
|
if (data && data->size()) {
|
||||||
if (fft_size != data->size() && !isView) {
|
// if (fft_size != data->size() && !isView) {
|
||||||
Setup(data->size(), waterfall_lines);
|
// Setup(data->size(), waterfall_lines);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (last_bandwidth != bandwidth && !isView) {
|
// if (last_bandwidth != bandwidth && !isView) {
|
||||||
Setup(bandwidth, waterfall_lines);
|
// Setup(bandwidth, waterfall_lines);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (spectrum_points.size() < fft_size * 2) {
|
if (spectrum_points.size() < fft_size * 2) {
|
||||||
spectrum_points.resize(fft_size * 2);
|
spectrum_points.resize(fft_size * 2);
|
||||||
|
@ -356,7 +403,7 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) {
|
||||||
last_input_bandwidth = input->bandwidth;
|
last_input_bandwidth = input->bandwidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
int out_size = ceil((double) (input->data.size()) * resample_ratio) + 32;
|
int out_size = ceil((double) (input->data.size()) * resample_ratio) + 512;
|
||||||
|
|
||||||
if (resampler_buffer.size() != out_size) {
|
if (resampler_buffer.size() != out_size) {
|
||||||
if (resampler_buffer.capacity() < out_size) {
|
if (resampler_buffer.capacity() < out_size) {
|
||||||
|
|
|
@ -95,6 +95,8 @@ private:
|
||||||
int last_input_bandwidth;
|
int last_input_bandwidth;
|
||||||
int last_bandwidth;
|
int last_bandwidth;
|
||||||
|
|
||||||
|
int zoom;
|
||||||
|
|
||||||
std::vector<liquid_float_complex> shift_buffer;
|
std::vector<liquid_float_complex> shift_buffer;
|
||||||
std::vector<liquid_float_complex> resampler_buffer;
|
std::vector<liquid_float_complex> resampler_buffer;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue