mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2024-11-15 16:41:54 -05:00
Merge pull request #216 from cjcliffe/sproc_v2
SpectrumVisualProcessor Zoom rework
This commit is contained in:
commit
dbfedf56cb
@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 2.8)
|
|||||||
|
|
||||||
SET(CUBICSDR_VERSION_MAJOR "0")
|
SET(CUBICSDR_VERSION_MAJOR "0")
|
||||||
SET(CUBICSDR_VERSION_MINOR "1")
|
SET(CUBICSDR_VERSION_MINOR "1")
|
||||||
SET(CUBICSDR_VERSION_PATCH "18")
|
SET(CUBICSDR_VERSION_PATCH "19")
|
||||||
SET(CUBICSDR_VERSION_REL "alpha")
|
SET(CUBICSDR_VERSION_REL "alpha")
|
||||||
SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}-${CUBICSDR_VERSION_REL}")
|
SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}-${CUBICSDR_VERSION_REL}")
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ AppFrame::AppFrame() :
|
|||||||
scopeCanvas->setHelpTip("Audio Visuals, drag left/right to toggle Scope or Spectrum.");
|
scopeCanvas->setHelpTip("Audio Visuals, drag left/right to toggle Scope or Spectrum.");
|
||||||
scopeCanvas->SetMinSize(wxSize(128,-1));
|
scopeCanvas->SetMinSize(wxSize(128,-1));
|
||||||
demodScopeTray->Add(scopeCanvas, 8, wxEXPAND | wxALL, 0);
|
demodScopeTray->Add(scopeCanvas, 8, wxEXPAND | wxALL, 0);
|
||||||
wxGetApp().getScopeProcessor()->setup(2048);
|
wxGetApp().getScopeProcessor()->setup(1024);
|
||||||
wxGetApp().getScopeProcessor()->attachOutput(scopeCanvas->getInputQueue());
|
wxGetApp().getScopeProcessor()->attachOutput(scopeCanvas->getInputQueue());
|
||||||
|
|
||||||
demodScopeTray->AddSpacer(1);
|
demodScopeTray->AddSpacer(1);
|
||||||
@ -969,17 +969,22 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
|||||||
// basic demodulators
|
// basic demodulators
|
||||||
if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) {
|
if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) {
|
||||||
mgr->setLastDemodulatorType(dSelection);
|
mgr->setLastDemodulatorType(dSelection);
|
||||||
|
mgr->setLastBandwidth(Modem::getModemDefaultSampleRate(dSelection));
|
||||||
|
demodTuner->setHalfBand(dSelection=="USB" || dSelection=="LSB");
|
||||||
demodModeSelectorAdv->setSelection(-1);
|
demodModeSelectorAdv->setSelection(-1);
|
||||||
}
|
}
|
||||||
// advanced demodulators
|
// advanced demodulators
|
||||||
else if(dSelectionadv != "" && dSelectionadv != mgr->getLastDemodulatorType()) {
|
else if(dSelectionadv != "" && dSelectionadv != mgr->getLastDemodulatorType()) {
|
||||||
mgr->setLastDemodulatorType(dSelectionadv);
|
mgr->setLastDemodulatorType(dSelectionadv);
|
||||||
|
mgr->setLastBandwidth(Modem::getModemDefaultSampleRate(dSelectionadv));
|
||||||
|
demodTuner->setHalfBand(false);
|
||||||
demodModeSelector->setSelection(-1);
|
demodModeSelector->setSelection(-1);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// basic demodulators
|
// basic demodulators
|
||||||
if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) {
|
if (dSelection != "" && dSelection != mgr->getLastDemodulatorType()) {
|
||||||
mgr->setLastDemodulatorType(dSelection);
|
mgr->setLastDemodulatorType(dSelection);
|
||||||
|
demodTuner->setHalfBand(dSelection=="USB" || dSelection=="LSB");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
demodGainMeter->setLevel(mgr->getLastGain());
|
demodGainMeter->setLevel(mgr->getLastGain());
|
||||||
@ -1045,15 +1050,9 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
|||||||
GetStatusBar()->SetStatusText(wxString::Format(wxT("Spectrum averaging speed changed to %0.2f%%."),val*100.0));
|
GetStatusBar()->SetStatusText(wxString::Format(wxT("Spectrum averaging speed changed to %0.2f%%."),val*100.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
proc->setView(waterfallCanvas->getViewState());
|
|
||||||
proc->setBandwidth(waterfallCanvas->getBandwidth());
|
|
||||||
proc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
|
|
||||||
|
|
||||||
SpectrumVisualProcessor *dproc = wxGetApp().getDemodSpectrumProcessor();
|
SpectrumVisualProcessor *dproc = wxGetApp().getDemodSpectrumProcessor();
|
||||||
|
|
||||||
dproc->setView(demodWaterfallCanvas->getViewState());
|
dproc->setView(demodWaterfallCanvas->getViewState(), demodWaterfallCanvas->getCenterFrequency(),demodWaterfallCanvas->getBandwidth());
|
||||||
dproc->setBandwidth(demodWaterfallCanvas->getBandwidth());
|
|
||||||
dproc->setCenterFrequency(demodWaterfallCanvas->getCenterFrequency());
|
|
||||||
|
|
||||||
SpectrumVisualProcessor *wproc = waterfallDataThread->getProcessor();
|
SpectrumVisualProcessor *wproc = waterfallDataThread->getProcessor();
|
||||||
|
|
||||||
@ -1065,11 +1064,11 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
|||||||
GetStatusBar()->SetStatusText(wxString::Format(wxT("Waterfall max speed changed to %d lines per second."),(int)ceil(val*val)));
|
GetStatusBar()->SetStatusText(wxString::Format(wxT("Waterfall max speed changed to %d lines per second."),(int)ceil(val*val)));
|
||||||
}
|
}
|
||||||
|
|
||||||
wproc->setView(waterfallCanvas->getViewState());
|
wproc->setView(waterfallCanvas->getViewState(), waterfallCanvas->getCenterFrequency(), waterfallCanvas->getBandwidth());
|
||||||
wproc->setBandwidth(waterfallCanvas->getBandwidth());
|
|
||||||
wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency());
|
|
||||||
wxGetApp().getSDRPostThread()->setIQVisualRange(waterfallCanvas->getCenterFrequency(), waterfallCanvas->getBandwidth());
|
wxGetApp().getSDRPostThread()->setIQVisualRange(waterfallCanvas->getCenterFrequency(), waterfallCanvas->getBandwidth());
|
||||||
|
|
||||||
|
proc->setView(wproc->isView(), wproc->getCenterFrequency(), wproc->getBandwidth());
|
||||||
|
|
||||||
demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||||
|
|
||||||
if (modemPropertiesUpdated.load() && demod && demod->isModemInitialized()) {
|
if (modemPropertiesUpdated.load() && demod && demod->isModemInitialized()) {
|
||||||
|
@ -27,11 +27,12 @@ void FFTVisualDataThread::run() {
|
|||||||
DemodulatorThreadInputQueue *pipeIQDataIn = (DemodulatorThreadInputQueue *)getInputQueue("IQDataInput");
|
DemodulatorThreadInputQueue *pipeIQDataIn = (DemodulatorThreadInputQueue *)getInputQueue("IQDataInput");
|
||||||
SpectrumVisualDataQueue *pipeFFTDataOut = (SpectrumVisualDataQueue *)getOutputQueue("FFTDataOutput");
|
SpectrumVisualDataQueue *pipeFFTDataOut = (SpectrumVisualDataQueue *)getOutputQueue("FFTDataOutput");
|
||||||
|
|
||||||
|
pipeFFTDataOut->set_max_num_items(512);
|
||||||
fftDistrib.setInput(pipeIQDataIn);
|
fftDistrib.setInput(pipeIQDataIn);
|
||||||
fftDistrib.attachOutput(&fftQueue);
|
fftDistrib.attachOutput(&fftQueue);
|
||||||
wproc.setInput(&fftQueue);
|
wproc.setInput(&fftQueue);
|
||||||
wproc.attachOutput(pipeFFTDataOut);
|
wproc.attachOutput(pipeFFTDataOut);
|
||||||
wproc.setup(2048);
|
wproc.setup(DEFAULT_FFT_SIZE);
|
||||||
|
|
||||||
std::cout << "FFT visual data thread started." << std::endl;
|
std::cout << "FFT visual data thread started." << std::endl;
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ void FFTVisualDataThread::run() {
|
|||||||
if (fftSize) {
|
if (fftSize) {
|
||||||
fftDistrib.setFFTSize(fftSize);
|
fftDistrib.setFFTSize(fftSize);
|
||||||
} else {
|
} else {
|
||||||
fftDistrib.setFFTSize(DEFAULT_FFT_SIZE);
|
fftDistrib.setFFTSize(DEFAULT_FFT_SIZE * SPECTRUM_VZM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lpsChanged.load()) {
|
if (lpsChanged.load()) {
|
||||||
|
@ -18,6 +18,7 @@ SpectrumVisualProcessor::SpectrumVisualProcessor() : lastInputBandwidth(0), last
|
|||||||
desiredInputSize.store(0);
|
desiredInputSize.store(0);
|
||||||
fft_average_rate = 0.65;
|
fft_average_rate = 0.65;
|
||||||
scaleFactor.store(1.0);
|
scaleFactor.store(1.0);
|
||||||
|
lastView = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpectrumVisualProcessor::~SpectrumVisualProcessor() {
|
SpectrumVisualProcessor::~SpectrumVisualProcessor() {
|
||||||
@ -34,6 +35,15 @@ void SpectrumVisualProcessor::setView(bool bView) {
|
|||||||
busy_run.unlock();
|
busy_run.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpectrumVisualProcessor::setView(bool bView, long long centerFreq_in, long bandwidth_in) {
|
||||||
|
busy_run.lock();
|
||||||
|
is_view.store(bView);
|
||||||
|
bandwidth.store(bandwidth_in);
|
||||||
|
centerFreq.store(centerFreq_in);
|
||||||
|
busy_run.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SpectrumVisualProcessor::setFFTAverageRate(float fftAverageRate) {
|
void SpectrumVisualProcessor::setFFTAverageRate(float fftAverageRate) {
|
||||||
busy_run.lock();
|
busy_run.lock();
|
||||||
this->fft_average_rate.store(fftAverageRate);
|
this->fft_average_rate.store(fftAverageRate);
|
||||||
@ -72,28 +82,29 @@ void SpectrumVisualProcessor::setup(int fftSize_in) {
|
|||||||
busy_run.lock();
|
busy_run.lock();
|
||||||
|
|
||||||
fftSize = fftSize_in;
|
fftSize = fftSize_in;
|
||||||
desiredInputSize.store(fftSize);
|
fftSizeInternal = fftSize_in * SPECTRUM_VZM;
|
||||||
|
desiredInputSize.store(fftSizeInternal);
|
||||||
|
|
||||||
if (fftwInput) {
|
if (fftwInput) {
|
||||||
free(fftwInput);
|
free(fftwInput);
|
||||||
}
|
}
|
||||||
fftwInput = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
fftwInput = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSizeInternal);
|
||||||
if (fftInData) {
|
if (fftInData) {
|
||||||
free(fftInData);
|
free(fftInData);
|
||||||
}
|
}
|
||||||
fftInData = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
fftInData = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSizeInternal);
|
||||||
if (fftLastData) {
|
if (fftLastData) {
|
||||||
free(fftLastData);
|
free(fftLastData);
|
||||||
}
|
}
|
||||||
fftLastData = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
fftLastData = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSizeInternal);
|
||||||
if (fftwOutput) {
|
if (fftwOutput) {
|
||||||
free(fftwOutput);
|
free(fftwOutput);
|
||||||
}
|
}
|
||||||
fftwOutput = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
fftwOutput = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSizeInternal);
|
||||||
if (fftw_plan) {
|
if (fftw_plan) {
|
||||||
fftwf_destroy_plan(fftw_plan);
|
fftwf_destroy_plan(fftw_plan);
|
||||||
}
|
}
|
||||||
fftw_plan = fftwf_plan_dft_1d(fftSize, fftwInput, fftwOutput, FFTW_FORWARD, FFTW_ESTIMATE);
|
fftw_plan = fftwf_plan_dft_1d(fftSizeInternal, fftwInput, fftwOutput, FFTW_FORWARD, FFTW_ESTIMATE);
|
||||||
busy_run.unlock();
|
busy_run.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +142,16 @@ void SpectrumVisualProcessor::process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned int num_written;
|
unsigned int num_written;
|
||||||
|
long resampleBw = iqData->sampleRate;
|
||||||
|
bool newResampler = false;
|
||||||
|
int bwDiff;
|
||||||
|
|
||||||
|
// if (bandwidth > resampleBw) {
|
||||||
|
// iqData->decRefCount();
|
||||||
|
// iqData->busy_rw.unlock();
|
||||||
|
// busy_run.unlock();
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
if (is_view.load()) {
|
if (is_view.load()) {
|
||||||
if (!iqData->frequency || !iqData->sampleRate) {
|
if (!iqData->frequency || !iqData->sampleRate) {
|
||||||
@ -140,9 +161,14 @@ void SpectrumVisualProcessor::process() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
resamplerRatio = (double) (bandwidth) / (double) iqData->sampleRate;
|
// resamplerRatio = (double) (bandwidth) / (double) iqData->sampleRate;
|
||||||
|
while (resampleBw / SPECTRUM_VZM >= bandwidth) {
|
||||||
|
resampleBw /= SPECTRUM_VZM;
|
||||||
|
}
|
||||||
|
|
||||||
int desired_input_size = fftSize / resamplerRatio;
|
resamplerRatio = (double) (resampleBw) / (double) iqData->sampleRate;
|
||||||
|
|
||||||
|
int desired_input_size = fftSizeInternal / resamplerRatio;
|
||||||
|
|
||||||
this->desiredInputSize.store(desired_input_size);
|
this->desiredInputSize.store(desired_input_size);
|
||||||
|
|
||||||
@ -154,9 +180,29 @@ void SpectrumVisualProcessor::process() {
|
|||||||
if (centerFreq != iqData->frequency) {
|
if (centerFreq != iqData->frequency) {
|
||||||
if ((centerFreq - iqData->frequency) != shiftFrequency || lastInputBandwidth != iqData->sampleRate) {
|
if ((centerFreq - iqData->frequency) != shiftFrequency || lastInputBandwidth != iqData->sampleRate) {
|
||||||
if (abs(iqData->frequency - centerFreq) < (wxGetApp().getSampleRate() / 2)) {
|
if (abs(iqData->frequency - centerFreq) < (wxGetApp().getSampleRate() / 2)) {
|
||||||
|
long lastShiftFrequency = shiftFrequency;
|
||||||
shiftFrequency = centerFreq - iqData->frequency;
|
shiftFrequency = centerFreq - iqData->frequency;
|
||||||
nco_crcf_reset(freqShifter);
|
|
||||||
nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) iqData->sampleRate)));
|
nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) iqData->sampleRate)));
|
||||||
|
|
||||||
|
if (is_view.load()) {
|
||||||
|
long freqDiff = shiftFrequency - lastShiftFrequency;
|
||||||
|
|
||||||
|
if (lastBandwidth!=0) {
|
||||||
|
double binPerHz = double(lastBandwidth) / double(fftSizeInternal);
|
||||||
|
|
||||||
|
int numShift = floor(double(abs(freqDiff)) / binPerHz);
|
||||||
|
|
||||||
|
if (numShift < fftSizeInternal/2 && numShift) {
|
||||||
|
if (freqDiff > 0) {
|
||||||
|
memmove(&fft_result_ma[0], &fft_result_ma[numShift], (fftSizeInternal-numShift) * sizeof(double));
|
||||||
|
memmove(&fft_result_maa[0], &fft_result_maa[numShift], (fftSizeInternal-numShift) * sizeof(double));
|
||||||
|
} else {
|
||||||
|
memmove(&fft_result_ma[numShift], &fft_result_ma[0], (fftSizeInternal-numShift) * sizeof(double));
|
||||||
|
memmove(&fft_result_maa[numShift], &fft_result_maa[0], (fftSizeInternal-numShift) * sizeof(double));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,16 +222,19 @@ void SpectrumVisualProcessor::process() {
|
|||||||
shiftBuffer.assign(iqData->data.begin(), iqData->data.end());
|
shiftBuffer.assign(iqData->data.begin(), iqData->data.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resampler || bandwidth != lastBandwidth || lastInputBandwidth != iqData->sampleRate) {
|
if (!resampler || resampleBw != lastBandwidth || lastInputBandwidth != iqData->sampleRate) {
|
||||||
float As = 60.0f;
|
float As = 60.0f;
|
||||||
|
|
||||||
if (resampler) {
|
if (resampler) {
|
||||||
msresamp_crcf_destroy(resampler);
|
msresamp_crcf_destroy(resampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
resampler = msresamp_crcf_create(resamplerRatio, As);
|
resampler = msresamp_crcf_create(resamplerRatio, As);
|
||||||
|
|
||||||
lastBandwidth = bandwidth;
|
bwDiff = resampleBw-lastBandwidth;
|
||||||
|
lastBandwidth = resampleBw;
|
||||||
lastInputBandwidth = iqData->sampleRate;
|
lastInputBandwidth = iqData->sampleRate;
|
||||||
|
newResampler = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -201,36 +250,36 @@ void SpectrumVisualProcessor::process() {
|
|||||||
|
|
||||||
msresamp_crcf_execute(resampler, &shiftBuffer[0], desired_input_size, &resampleBuffer[0], &num_written);
|
msresamp_crcf_execute(resampler, &shiftBuffer[0], desired_input_size, &resampleBuffer[0], &num_written);
|
||||||
|
|
||||||
resampleBuffer.resize(fftSize);
|
resampleBuffer.resize(fftSizeInternal);
|
||||||
|
|
||||||
if (num_written < fftSize) {
|
if (num_written < fftSizeInternal) {
|
||||||
for (int i = 0; i < num_written; i++) {
|
for (int i = 0; i < num_written; i++) {
|
||||||
fftInData[i][0] = resampleBuffer[i].real;
|
fftInData[i][0] = resampleBuffer[i].real;
|
||||||
fftInData[i][1] = resampleBuffer[i].imag;
|
fftInData[i][1] = resampleBuffer[i].imag;
|
||||||
}
|
}
|
||||||
for (int i = num_written; i < fftSize; i++) {
|
for (int i = num_written; i < fftSizeInternal; i++) {
|
||||||
fftInData[i][0] = 0;
|
fftInData[i][0] = 0;
|
||||||
fftInData[i][1] = 0;
|
fftInData[i][1] = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < fftSize; i++) {
|
for (int i = 0; i < fftSizeInternal; i++) {
|
||||||
fftInData[i][0] = resampleBuffer[i].real;
|
fftInData[i][0] = resampleBuffer[i].real;
|
||||||
fftInData[i][1] = resampleBuffer[i].imag;
|
fftInData[i][1] = resampleBuffer[i].imag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
num_written = data->size();
|
num_written = data->size();
|
||||||
if (data->size() < fftSize) {
|
if (data->size() < fftSizeInternal) {
|
||||||
for (int i = 0, iMax = data->size(); i < iMax; i++) {
|
for (int i = 0, iMax = data->size(); i < iMax; i++) {
|
||||||
fftInData[i][0] = (*data)[i].real;
|
fftInData[i][0] = (*data)[i].real;
|
||||||
fftInData[i][1] = (*data)[i].imag;
|
fftInData[i][1] = (*data)[i].imag;
|
||||||
}
|
}
|
||||||
for (int i = data->size(); i < fftSize; i++) {
|
for (int i = data->size(); i < fftSizeInternal; i++) {
|
||||||
fftInData[i][0] = 0;
|
fftInData[i][0] = 0;
|
||||||
fftInData[i][1] = 0;
|
fftInData[i][1] = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < fftSize; i++) {
|
for (int i = 0; i < fftSizeInternal; i++) {
|
||||||
fftInData[i][0] = (*data)[i].real;
|
fftInData[i][0] = (*data)[i].real;
|
||||||
fftInData[i][1] = (*data)[i].imag;
|
fftInData[i][1] = (*data)[i].imag;
|
||||||
}
|
}
|
||||||
@ -239,24 +288,24 @@ void SpectrumVisualProcessor::process() {
|
|||||||
|
|
||||||
bool execute = false;
|
bool execute = false;
|
||||||
|
|
||||||
if (num_written >= fftSize) {
|
if (num_written >= fftSizeInternal) {
|
||||||
execute = true;
|
execute = true;
|
||||||
memcpy(fftwInput, fftInData, fftSize * sizeof(fftwf_complex));
|
memcpy(fftwInput, fftInData, fftSizeInternal * sizeof(fftwf_complex));
|
||||||
memcpy(fftLastData, fftwInput, fftSize * sizeof(fftwf_complex));
|
memcpy(fftLastData, fftwInput, fftSizeInternal * sizeof(fftwf_complex));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (lastDataSize + num_written < fftSize) { // priming
|
if (lastDataSize + num_written < fftSizeInternal) { // priming
|
||||||
unsigned int num_copy = fftSize - lastDataSize;
|
unsigned int num_copy = fftSizeInternal - lastDataSize;
|
||||||
if (num_written > num_copy) {
|
if (num_written > num_copy) {
|
||||||
num_copy = num_written;
|
num_copy = num_written;
|
||||||
}
|
}
|
||||||
memcpy(fftLastData, fftInData, num_copy * sizeof(fftwf_complex));
|
memcpy(fftLastData, fftInData, num_copy * sizeof(fftwf_complex));
|
||||||
lastDataSize += num_copy;
|
lastDataSize += num_copy;
|
||||||
} else {
|
} else {
|
||||||
unsigned int num_last = (fftSize - num_written);
|
unsigned int num_last = (fftSizeInternal - num_written);
|
||||||
memcpy(fftwInput, fftLastData + (lastDataSize - num_last), num_last * sizeof(fftwf_complex));
|
memcpy(fftwInput, fftLastData + (lastDataSize - num_last), num_last * sizeof(fftwf_complex));
|
||||||
memcpy(fftwInput + num_last, fftInData, num_written * sizeof(fftwf_complex));
|
memcpy(fftwInput + num_last, fftInData, num_written * sizeof(fftwf_complex));
|
||||||
memcpy(fftLastData, fftwInput, fftSize * sizeof(fftwf_complex));
|
memcpy(fftLastData, fftwInput, fftSizeInternal * sizeof(fftwf_complex));
|
||||||
execute = true;
|
execute = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,33 +315,69 @@ void SpectrumVisualProcessor::process() {
|
|||||||
|
|
||||||
float fft_ceil = 0, fft_floor = 1;
|
float fft_ceil = 0, fft_floor = 1;
|
||||||
|
|
||||||
if (fft_result.size() < fftSize) {
|
if (fft_result.size() < fftSizeInternal) {
|
||||||
fft_result.resize(fftSize);
|
fft_result.resize(fftSizeInternal);
|
||||||
fft_result_ma.resize(fftSize);
|
fft_result_ma.resize(fftSizeInternal);
|
||||||
fft_result_maa.resize(fftSize);
|
fft_result_maa.resize(fftSizeInternal);
|
||||||
|
fft_result_temp.resize(fftSizeInternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0, iMax = fftSize / 2; i < iMax; i++) {
|
for (int i = 0, iMax = fftSizeInternal / 2; i < iMax; i++) {
|
||||||
float a = fftwOutput[i][0];
|
float a = fftwOutput[i][0];
|
||||||
float b = fftwOutput[i][1];
|
float b = fftwOutput[i][1];
|
||||||
float c = sqrt(a * a + b * b);
|
float c = sqrt(a * a + b * b);
|
||||||
|
|
||||||
float x = fftwOutput[fftSize / 2 + i][0];
|
float x = fftwOutput[fftSizeInternal / 2 + i][0];
|
||||||
float y = fftwOutput[fftSize / 2 + i][1];
|
float y = fftwOutput[fftSizeInternal / 2 + i][1];
|
||||||
float z = sqrt(x * x + y * y);
|
float z = sqrt(x * x + y * y);
|
||||||
|
|
||||||
fft_result[i] = (z);
|
fft_result[i] = (z);
|
||||||
fft_result[fftSize / 2 + i] = (c);
|
fft_result[fftSizeInternal / 2 + i] = (c);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0, iMax = fftSize; i < iMax; i++) {
|
if (newResampler && lastView) {
|
||||||
if (is_view.load()) {
|
if (bwDiff < 0) {
|
||||||
fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
|
for (int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
|
||||||
fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate;
|
fft_result_temp[i] = fft_result_ma[(fftSizeInternal/4) + (i/2)];
|
||||||
} else {
|
|
||||||
fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
|
|
||||||
fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate;
|
|
||||||
}
|
}
|
||||||
|
for (int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
|
||||||
|
fft_result_ma[i] = fft_result_temp[i];
|
||||||
|
|
||||||
|
fft_result_temp[i] = fft_result_maa[(fftSizeInternal/4) + (i/2)];
|
||||||
|
}
|
||||||
|
for (int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
|
||||||
|
fft_result_maa[i] = fft_result_temp[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
|
||||||
|
if (i < fftSizeInternal/4) {
|
||||||
|
fft_result_temp[i] = fft_result_ma[fftSizeInternal/4];
|
||||||
|
} else if (i >= fftSizeInternal - fftSizeInternal/4) {
|
||||||
|
fft_result_temp[i] = fft_result_ma[fftSizeInternal - fftSizeInternal/4-1];
|
||||||
|
} else {
|
||||||
|
fft_result_temp[i] = fft_result_ma[(i-fftSizeInternal/4)*2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
|
||||||
|
fft_result_ma[i] = fft_result_temp[i];
|
||||||
|
|
||||||
|
if (i < fftSizeInternal/4) {
|
||||||
|
fft_result_temp[i] = fft_result_maa[fftSizeInternal/4];
|
||||||
|
} else if (i >= fftSizeInternal - fftSizeInternal/4) {
|
||||||
|
fft_result_temp[i] = fft_result_maa[fftSizeInternal - fftSizeInternal/4-1];
|
||||||
|
} else {
|
||||||
|
fft_result_temp[i] = fft_result_maa[(i-fftSizeInternal/4)*2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
|
||||||
|
fft_result_maa[i] = fft_result_temp[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
|
||||||
|
fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
|
||||||
|
fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate;
|
||||||
|
|
||||||
if (fft_result_maa[i] > fft_ceil) {
|
if (fft_result_maa[i] > fft_ceil) {
|
||||||
fft_ceil = fft_result_maa[i];
|
fft_ceil = fft_result_maa[i];
|
||||||
@ -310,10 +395,45 @@ void SpectrumVisualProcessor::process() {
|
|||||||
|
|
||||||
float sf = scaleFactor.load();
|
float sf = scaleFactor.load();
|
||||||
|
|
||||||
for (int i = 0, iMax = fftSize; i < iMax; i++) {
|
// for (int i = 0, iMax = fftSize; i < iMax; i++) {
|
||||||
float v = (log10(fft_result_maa[i]+0.25 - (fft_floor_maa-0.75)) / log10((fft_ceil_maa+0.25) - (fft_floor_maa-0.75)));
|
// float v = (log10(fft_result_maa[i*SPECTRUM_VZM]+0.25 - (fft_floor_maa-0.75)) / log10((fft_ceil_maa+0.25) - (fft_floor_maa-0.75)));
|
||||||
output->spectrum_points[i * 2] = ((float) i / (float) iMax);
|
// output->spectrum_points[i * 2] = ((float) i / (float) iMax);
|
||||||
output->spectrum_points[i * 2 + 1] = v*sf;
|
// output->spectrum_points[i * 2 + 1] = v*sf;
|
||||||
|
// }
|
||||||
|
double visualRatio = (double(bandwidth) / double(resampleBw));
|
||||||
|
double visualStart = (double(fftSizeInternal) / 2.0) - (double(fftSizeInternal) * (visualRatio / 2.0));
|
||||||
|
double visualAccum = 0;
|
||||||
|
double acc = 0, accCount = 0, i = 0;
|
||||||
|
|
||||||
|
for (int x = 0, xMax = output->spectrum_points.size() / 2; x < xMax; x++) {
|
||||||
|
visualAccum += visualRatio * double(SPECTRUM_VZM);
|
||||||
|
// while (visualAccum >= 1.0) {
|
||||||
|
// visualAccum -= 1.0;
|
||||||
|
// i++;
|
||||||
|
// }
|
||||||
|
// acc = (log10(fft_result_maa[visualStart+i]+0.25 - (fft_floor_maa-0.75)) / log10((fft_ceil_maa+0.25) - (fft_floor_maa-0.75)));
|
||||||
|
// output->spectrum_points[x * 2] = (float(x) / float(xMax));
|
||||||
|
// output->spectrum_points[x * 2 + 1] = acc*sf;
|
||||||
|
|
||||||
|
while (visualAccum >= 1.0) {
|
||||||
|
int idx = round(visualStart+i);
|
||||||
|
if (idx < 0) {
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
if (idx > fftSizeInternal) {
|
||||||
|
idx = fftSizeInternal;
|
||||||
|
}
|
||||||
|
acc += fft_result_maa[idx];
|
||||||
|
accCount += 1.0;
|
||||||
|
visualAccum -= 1.0;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (accCount) {
|
||||||
|
output->spectrum_points[x * 2] = ((float) x / (float) xMax);
|
||||||
|
output->spectrum_points[x * 2 + 1] = ((log10((acc/accCount)+0.25 - (fft_floor_maa-0.75)) / log10((fft_ceil_maa+0.25) - (fft_floor_maa-0.75))))*sf;
|
||||||
|
acc = 0.0;
|
||||||
|
accCount = 0.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hideDC.load()) { // DC-spike removal
|
if (hideDC.load()) { // DC-spike removal
|
||||||
@ -356,12 +476,16 @@ void SpectrumVisualProcessor::process() {
|
|||||||
output->fft_floor = fft_floor_maa;
|
output->fft_floor = fft_floor_maa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output->centerFreq = centerFreq;
|
||||||
|
output->bandwidth = bandwidth;
|
||||||
distribute(output);
|
distribute(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
iqData->decRefCount();
|
iqData->decRefCount();
|
||||||
iqData->busy_rw.unlock();
|
iqData->busy_rw.unlock();
|
||||||
busy_run.unlock();
|
busy_run.unlock();
|
||||||
|
|
||||||
|
lastView = is_view.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,10 +5,14 @@
|
|||||||
#include "fftw3.h"
|
#include "fftw3.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#define SPECTRUM_VZM 2
|
||||||
|
|
||||||
class SpectrumVisualData : public ReferenceCounter {
|
class SpectrumVisualData : public ReferenceCounter {
|
||||||
public:
|
public:
|
||||||
std::vector<float> spectrum_points;
|
std::vector<float> spectrum_points;
|
||||||
double fft_ceiling, fft_floor;
|
double fft_ceiling, fft_floor;
|
||||||
|
long long centerFreq;
|
||||||
|
int bandwidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ThreadQueue<SpectrumVisualData *> SpectrumVisualDataQueue;
|
typedef ThreadQueue<SpectrumVisualData *> SpectrumVisualDataQueue;
|
||||||
@ -20,6 +24,7 @@ public:
|
|||||||
|
|
||||||
bool isView();
|
bool isView();
|
||||||
void setView(bool bView);
|
void setView(bool bView);
|
||||||
|
void setView(bool bView, long long centerFreq_in, long bandwidth_in);
|
||||||
|
|
||||||
void setFFTAverageRate(float fftAverageRate);
|
void setFFTAverageRate(float fftAverageRate);
|
||||||
float getFFTAverageRate();
|
float getFFTAverageRate();
|
||||||
@ -44,12 +49,14 @@ protected:
|
|||||||
ReBuffer<SpectrumVisualData> outputBuffers;
|
ReBuffer<SpectrumVisualData> outputBuffers;
|
||||||
std::atomic_bool is_view;
|
std::atomic_bool is_view;
|
||||||
std::atomic_int fftSize;
|
std::atomic_int fftSize;
|
||||||
|
std::atomic_int fftSizeInternal;
|
||||||
std::atomic_llong centerFreq;
|
std::atomic_llong centerFreq;
|
||||||
std::atomic_long bandwidth;
|
std::atomic_long bandwidth;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
long lastInputBandwidth;
|
long lastInputBandwidth;
|
||||||
long lastBandwidth;
|
long lastBandwidth;
|
||||||
|
bool lastView;
|
||||||
|
|
||||||
fftwf_complex *fftwInput, *fftwOutput, *fftInData, *fftLastData;
|
fftwf_complex *fftwInput, *fftwOutput, *fftInData, *fftLastData;
|
||||||
unsigned int lastDataSize;
|
unsigned int lastDataSize;
|
||||||
@ -62,6 +69,7 @@ private:
|
|||||||
std::vector<double> fft_result;
|
std::vector<double> fft_result;
|
||||||
std::vector<double> fft_result_ma;
|
std::vector<double> fft_result_ma;
|
||||||
std::vector<double> fft_result_maa;
|
std::vector<double> fft_result_maa;
|
||||||
|
std::vector<double> fft_result_temp;
|
||||||
|
|
||||||
msresamp_crcf resampler;
|
msresamp_crcf resampler;
|
||||||
double resamplerRatio;
|
double resamplerRatio;
|
||||||
|
@ -53,6 +53,12 @@ long long InteractiveCanvas::getFrequencyAt(float x) {
|
|||||||
return freq;
|
return freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long long InteractiveCanvas::getFrequencyAt(float x, long long iqCenterFreq, long long iqBandwidth) {
|
||||||
|
long long freq = iqCenterFreq - (long long)(0.5 * (long double) iqBandwidth) + ((long double) x * (long double) iqBandwidth);
|
||||||
|
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
void InteractiveCanvas::setCenterFrequency(long long center_freq_in) {
|
void InteractiveCanvas::setCenterFrequency(long long center_freq_in) {
|
||||||
centerFreq = center_freq_in;
|
centerFreq = center_freq_in;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ public:
|
|||||||
~InteractiveCanvas();
|
~InteractiveCanvas();
|
||||||
|
|
||||||
long long getFrequencyAt(float x);
|
long long getFrequencyAt(float x);
|
||||||
|
long long getFrequencyAt(float x, long long iqCenterFreq, long long iqBandwidth);
|
||||||
|
|
||||||
virtual void setView(long long center_freq_in, int bandwidth_in);
|
virtual void setView(long long center_freq_in, int bandwidth_in);
|
||||||
virtual void disableView();
|
virtual void disableView();
|
||||||
|
@ -162,7 +162,7 @@ void TuningCanvas::StepTuner(ActiveState state, int exponent, bool up) {
|
|||||||
double exp = pow(10, exponent);
|
double exp = pow(10, exponent);
|
||||||
long long amount = up?exp:-exp;
|
long long amount = up?exp:-exp;
|
||||||
|
|
||||||
if (halfBand && exp == 1) {
|
if (halfBand) {
|
||||||
amount *= 2;
|
amount *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,9 +182,8 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
|||||||
bw = minBandwidth;
|
bw = minBandwidth;
|
||||||
}
|
}
|
||||||
if (mouseInView) {
|
if (mouseInView) {
|
||||||
long long mfreqA = getFrequencyAt(mpos);
|
long long mfreqA = getFrequencyAt(mpos, centerFreq, getBandwidth());
|
||||||
setBandwidth(bw);
|
long long mfreqB = getFrequencyAt(mpos, centerFreq, bw);
|
||||||
long long mfreqB = getFrequencyAt(mpos);
|
|
||||||
centerFreq += mfreqA - mfreqB;
|
centerFreq += mfreqA - mfreqB;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,12 +197,14 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
|||||||
if (spectrumCanvas) {
|
if (spectrumCanvas) {
|
||||||
spectrumCanvas->disableView();
|
spectrumCanvas->disableView();
|
||||||
}
|
}
|
||||||
|
bw = wxGetApp().getSampleRate();
|
||||||
|
centerFreq = wxGetApp().getFrequency();
|
||||||
} else {
|
} else {
|
||||||
if (mouseInView) {
|
if (mouseInView) {
|
||||||
long long mfreqA = getFrequencyAt(mpos);
|
long long mfreqA = getFrequencyAt(mpos, centerFreq, getBandwidth());
|
||||||
setBandwidth(bw);
|
long long mfreqB = getFrequencyAt(mpos, centerFreq, bw);
|
||||||
long long mfreqB = getFrequencyAt(mpos);
|
|
||||||
centerFreq += mfreqA - mfreqB;
|
centerFreq += mfreqA - mfreqB;
|
||||||
|
setBandwidth(bw);
|
||||||
} else {
|
} else {
|
||||||
setBandwidth(bw);
|
setBandwidth(bw);
|
||||||
}
|
}
|
||||||
@ -822,11 +823,11 @@ void WaterfallCanvas::updateCenterFrequency(long long freq) {
|
|||||||
long long minFreq = wxGetApp().getFrequency()-(wxGetApp().getSampleRate()/2);
|
long long minFreq = wxGetApp().getFrequency()-(wxGetApp().getSampleRate()/2);
|
||||||
long long maxFreq = wxGetApp().getFrequency()+(wxGetApp().getSampleRate()/2);
|
long long maxFreq = wxGetApp().getFrequency()+(wxGetApp().getSampleRate()/2);
|
||||||
|
|
||||||
if (freq < minFreq) {
|
if (freq - bandwidth / 2 < minFreq) {
|
||||||
wxGetApp().setFrequency(freq+(wxGetApp().getSampleRate()/2));
|
wxGetApp().setFrequency(wxGetApp().getFrequency() - (minFreq - (freq - bandwidth/2)));
|
||||||
}
|
}
|
||||||
if (freq > maxFreq) {
|
if (freq + bandwidth / 2 > maxFreq) {
|
||||||
wxGetApp().setFrequency(freq-(wxGetApp().getSampleRate()/2));
|
wxGetApp().setFrequency(wxGetApp().getFrequency() + ((freq + bandwidth/2) - maxFreq));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (spectrumCanvas) {
|
if (spectrumCanvas) {
|
||||||
|
Loading…
Reference in New Issue
Block a user