mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2024-11-26 21:58:37 -05:00
Merge pull request #240 from cjcliffe/low_bandwidth
Updates and improvements for low-bandwidth input usage
This commit is contained in:
commit
1e5acb415a
@ -1322,3 +1322,9 @@ void AppFrame::updateModemProperties(ModemArgInfoList args) {
|
|||||||
modemPropertiesUpdated.store(true);
|
modemPropertiesUpdated.store(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppFrame::setMainWaterfallFFTSize(int fftSize) {
|
||||||
|
wxGetApp().getSpectrumProcessor()->setFFTSize(fftSize);
|
||||||
|
spectrumCanvas->setFFTSize(fftSize);
|
||||||
|
waterfallDataThread->getProcessor()->setFFTSize(fftSize);
|
||||||
|
waterfallCanvas->setFFTSize(fftSize);
|
||||||
|
}
|
||||||
|
@ -69,6 +69,7 @@ public:
|
|||||||
FFTVisualDataThread *getWaterfallDataThread();
|
FFTVisualDataThread *getWaterfallDataThread();
|
||||||
|
|
||||||
void updateModemProperties(ModemArgInfoList args);
|
void updateModemProperties(ModemArgInfoList args);
|
||||||
|
void setMainWaterfallFFTSize(int fftSize);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnMenu(wxCommandEvent& event);
|
void OnMenu(wxCommandEvent& event);
|
||||||
|
@ -441,6 +441,20 @@ void CubicSDR::setSampleRate(long long rate_in) {
|
|||||||
sampleRate = rate_in;
|
sampleRate = rate_in;
|
||||||
sdrThread->setSampleRate(sampleRate);
|
sdrThread->setSampleRate(sampleRate);
|
||||||
setFrequency(frequency);
|
setFrequency(frequency);
|
||||||
|
|
||||||
|
if (rate_in <= CHANNELIZER_RATE_MAX / 8) {
|
||||||
|
appframe->setMainWaterfallFFTSize(512);
|
||||||
|
appframe->getWaterfallDataThread()->getProcessor()->setHideDC(false);
|
||||||
|
spectrumVisualThread->getProcessor()->setHideDC(false);
|
||||||
|
} else if (rate_in <= CHANNELIZER_RATE_MAX) {
|
||||||
|
appframe->setMainWaterfallFFTSize(1024);
|
||||||
|
appframe->getWaterfallDataThread()->getProcessor()->setHideDC(false);
|
||||||
|
spectrumVisualThread->getProcessor()->setHideDC(false);
|
||||||
|
} else if (rate_in > CHANNELIZER_RATE_MAX) {
|
||||||
|
appframe->setMainWaterfallFFTSize(2048);
|
||||||
|
appframe->getWaterfallDataThread()->getProcessor()->setHideDC(true);
|
||||||
|
spectrumVisualThread->getProcessor()->setHideDC(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CubicSDR::setDevice(SDRDeviceInfo *dev) {
|
void CubicSDR::setDevice(SDRDeviceInfo *dev) {
|
||||||
|
@ -208,7 +208,7 @@ void AudioThread::enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs) {
|
|||||||
|
|
||||||
std::cout << "Audio Device #" << i << " " << info.name << std::endl;
|
std::cout << "Audio Device #" << i << " " << info.name << std::endl;
|
||||||
std::cout << "\tDefault Output? " << (info.isDefaultOutput ? "Yes" : "No") << std::endl;
|
std::cout << "\tDefault Output? " << (info.isDefaultOutput ? "Yes" : "No") << std::endl;
|
||||||
std::cout << "\tDefault Input? " << (info.isDefaultOutput ? "Yes" : "No") << std::endl;
|
std::cout << "\tDefault Input? " << (info.isDefaultInput ? "Yes" : "No") << std::endl;
|
||||||
std::cout << "\tInput channels: " << info.inputChannels << std::endl;
|
std::cout << "\tInput channels: " << info.inputChannels << std::endl;
|
||||||
std::cout << "\tOutput channels: " << info.outputChannels << std::endl;
|
std::cout << "\tOutput channels: " << info.outputChannels << std::endl;
|
||||||
std::cout << "\tDuplex channels: " << info.duplexChannels << std::endl;
|
std::cout << "\tDuplex channels: " << info.duplexChannels << std::endl;
|
||||||
|
@ -16,14 +16,6 @@ void WaterfallPanel::setup(int fft_size_in, int num_waterfall_lines_in) {
|
|||||||
points.resize(fft_size);
|
points.resize(fft_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
if (waterfall[i]) {
|
|
||||||
glDeleteTextures(1, &waterfall[i]);
|
|
||||||
waterfall[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
waterfall_ofs[i] = waterfall_lines - 1;
|
|
||||||
}
|
|
||||||
texInitialized.store(false);
|
texInitialized.store(false);
|
||||||
bufferInitialized.store(false);
|
bufferInitialized.store(false);
|
||||||
}
|
}
|
||||||
@ -65,7 +57,7 @@ void WaterfallPanel::step() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (points.size()) {
|
if (points.size() && points.size() == fft_size) {
|
||||||
for (int j = 0; j < 2; j++) {
|
for (int j = 0; j < 2; j++) {
|
||||||
for (int i = 0, iMax = half_fft_size; i < iMax; i++) {
|
for (int i = 0, iMax = half_fft_size; i < iMax; i++) {
|
||||||
float v = points[j * half_fft_size + i];
|
float v = points[j * half_fft_size + i];
|
||||||
@ -94,6 +86,15 @@ void WaterfallPanel::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!texInitialized.load()) {
|
if (!texInitialized.load()) {
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
if (waterfall[i]) {
|
||||||
|
glDeleteTextures(1, &waterfall[i]);
|
||||||
|
waterfall[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
waterfall_ofs[i] = waterfall_lines - 1;
|
||||||
|
}
|
||||||
|
|
||||||
glGenTextures(2, waterfall);
|
glGenTextures(2, waterfall);
|
||||||
|
|
||||||
unsigned char *waterfall_tex;
|
unsigned char *waterfall_tex;
|
||||||
@ -110,12 +111,13 @@ void WaterfallPanel::update() {
|
|||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, waterfall[i]);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, half_fft_size, waterfall_lines, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, (GLvoid *) waterfall_tex);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, half_fft_size, waterfall_lines, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, (GLvoid *) waterfall_tex);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] waterfall_tex;
|
delete[] waterfall_tex;
|
||||||
|
|
||||||
|
refreshTheme();
|
||||||
|
|
||||||
texInitialized.store(true);
|
texInitialized.store(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ 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);
|
||||||
|
fftSizeChanged.store(false);
|
||||||
|
newFFTSize.store(0);
|
||||||
lastView = false;
|
lastView = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,24 +85,38 @@ void SpectrumVisualProcessor::setup(int fftSize_in) {
|
|||||||
|
|
||||||
fftSize = fftSize_in;
|
fftSize = fftSize_in;
|
||||||
fftSizeInternal = fftSize_in * SPECTRUM_VZM;
|
fftSizeInternal = fftSize_in * SPECTRUM_VZM;
|
||||||
desiredInputSize.store(fftSizeInternal);
|
lastDataSize = 0;
|
||||||
|
|
||||||
|
int memSize = sizeof(fftwf_complex) * fftSizeInternal;
|
||||||
|
|
||||||
if (fftwInput) {
|
if (fftwInput) {
|
||||||
free(fftwInput);
|
free(fftwInput);
|
||||||
}
|
}
|
||||||
fftwInput = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSizeInternal);
|
//fftwInput = (fftwf_complex*) fftwf_malloc(memSize);
|
||||||
|
fftwInput = (fftwf_complex*)malloc(memSize);
|
||||||
|
memset(fftwInput,0,memSize);
|
||||||
|
|
||||||
if (fftInData) {
|
if (fftInData) {
|
||||||
free(fftInData);
|
free(fftInData);
|
||||||
}
|
}
|
||||||
fftInData = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSizeInternal);
|
//fftInData = (fftwf_complex*) fftwf_malloc(memSize);
|
||||||
|
fftInData = (fftwf_complex*)malloc(memSize);
|
||||||
|
memset(fftwInput,0,memSize);
|
||||||
|
|
||||||
if (fftLastData) {
|
if (fftLastData) {
|
||||||
free(fftLastData);
|
free(fftLastData);
|
||||||
}
|
}
|
||||||
fftLastData = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSizeInternal);
|
//fftLastData = (fftwf_complex*) fftwf_malloc(memSize);
|
||||||
|
fftLastData = (fftwf_complex*)malloc(memSize);
|
||||||
|
memset(fftwInput,0,memSize);
|
||||||
|
|
||||||
if (fftwOutput) {
|
if (fftwOutput) {
|
||||||
free(fftwOutput);
|
free(fftwOutput);
|
||||||
}
|
}
|
||||||
fftwOutput = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSizeInternal);
|
//fftwOutput = (fftwf_complex*) fftwf_malloc(memSize);
|
||||||
|
fftwOutput = (fftwf_complex*)malloc(memSize);
|
||||||
|
memset(fftwInput,0,memSize);
|
||||||
|
|
||||||
if (fftw_plan) {
|
if (fftw_plan) {
|
||||||
fftwf_destroy_plan(fftw_plan);
|
fftwf_destroy_plan(fftw_plan);
|
||||||
}
|
}
|
||||||
@ -108,6 +124,14 @@ void SpectrumVisualProcessor::setup(int fftSize_in) {
|
|||||||
busy_run.unlock();
|
busy_run.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpectrumVisualProcessor::setFFTSize(int fftSize_in) {
|
||||||
|
if (fftSize_in == fftSize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
newFFTSize = fftSize_in;
|
||||||
|
fftSizeChanged.store(true);
|
||||||
|
}
|
||||||
|
|
||||||
void SpectrumVisualProcessor::setHideDC(bool hideDC) {
|
void SpectrumVisualProcessor::setHideDC(bool hideDC) {
|
||||||
this->hideDC.store(hideDC);
|
this->hideDC.store(hideDC);
|
||||||
}
|
}
|
||||||
@ -121,6 +145,11 @@ void SpectrumVisualProcessor::process() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fftSizeChanged.load()) {
|
||||||
|
setup(newFFTSize);
|
||||||
|
fftSizeChanged.store(false);
|
||||||
|
}
|
||||||
|
|
||||||
DemodulatorThreadIQData *iqData;
|
DemodulatorThreadIQData *iqData;
|
||||||
|
|
||||||
input->pop(iqData);
|
input->pop(iqData);
|
||||||
@ -135,24 +164,11 @@ void SpectrumVisualProcessor::process() {
|
|||||||
std::vector<liquid_float_complex> *data = &iqData->data;
|
std::vector<liquid_float_complex> *data = &iqData->data;
|
||||||
|
|
||||||
if (data && data->size()) {
|
if (data && data->size()) {
|
||||||
SpectrumVisualData *output = outputBuffers.getBuffer();
|
|
||||||
|
|
||||||
if (output->spectrum_points.size() < fftSize * 2) {
|
|
||||||
output->spectrum_points.resize(fftSize * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int num_written;
|
unsigned int num_written;
|
||||||
long resampleBw = iqData->sampleRate;
|
long resampleBw = iqData->sampleRate;
|
||||||
bool newResampler = false;
|
bool newResampler = false;
|
||||||
int bwDiff;
|
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) {
|
||||||
iqData->decRefCount();
|
iqData->decRefCount();
|
||||||
@ -161,7 +177,6 @@ void SpectrumVisualProcessor::process() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// resamplerRatio = (double) (bandwidth) / (double) iqData->sampleRate;
|
|
||||||
while (resampleBw / SPECTRUM_VZM >= bandwidth) {
|
while (resampleBw / SPECTRUM_VZM >= bandwidth) {
|
||||||
resampleBw /= SPECTRUM_VZM;
|
resampleBw /= SPECTRUM_VZM;
|
||||||
}
|
}
|
||||||
@ -219,7 +234,7 @@ void SpectrumVisualProcessor::process() {
|
|||||||
nco_crcf_mix_block_down(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size);
|
nco_crcf_mix_block_down(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
shiftBuffer.assign(iqData->data.begin(), iqData->data.end());
|
shiftBuffer.assign(iqData->data.begin(), iqData->data.begin()+desired_input_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resampler || resampleBw != lastBandwidth || lastInputBandwidth != iqData->sampleRate) {
|
if (!resampler || resampleBw != lastBandwidth || lastInputBandwidth != iqData->sampleRate) {
|
||||||
@ -247,11 +262,8 @@ void SpectrumVisualProcessor::process() {
|
|||||||
resampleBuffer.resize(out_size);
|
resampleBuffer.resize(out_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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(fftSizeInternal);
|
|
||||||
|
|
||||||
if (num_written < fftSizeInternal) {
|
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;
|
||||||
@ -268,6 +280,8 @@ void SpectrumVisualProcessor::process() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
this->desiredInputSize.store(fftSizeInternal);
|
||||||
|
|
||||||
num_written = data->size();
|
num_written = data->size();
|
||||||
if (data->size() < fftSizeInternal) {
|
if (data->size() < fftSizeInternal) {
|
||||||
for (int i = 0, iMax = data->size(); i < iMax; i++) {
|
for (int i = 0, iMax = data->size(); i < iMax; i++) {
|
||||||
@ -311,11 +325,22 @@ void SpectrumVisualProcessor::process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (execute) {
|
if (execute) {
|
||||||
|
SpectrumVisualData *output = outputBuffers.getBuffer();
|
||||||
|
|
||||||
|
if (output->spectrum_points.size() != fftSize * 2) {
|
||||||
|
output->spectrum_points.resize(fftSize * 2);
|
||||||
|
}
|
||||||
|
|
||||||
fftwf_execute(fftw_plan);
|
fftwf_execute(fftw_plan);
|
||||||
|
|
||||||
float fft_ceil = 0, fft_floor = 1;
|
float fft_ceil = 0, fft_floor = 1;
|
||||||
|
|
||||||
if (fft_result.size() < fftSizeInternal) {
|
if (fft_result.size() != fftSizeInternal) {
|
||||||
|
if (fft_result.capacity() < fftSizeInternal) {
|
||||||
|
fft_result.reserve(fftSizeInternal);
|
||||||
|
fft_result_ma.reserve(fftSizeInternal);
|
||||||
|
fft_result_maa.reserve(fftSizeInternal);
|
||||||
|
}
|
||||||
fft_result.resize(fftSizeInternal);
|
fft_result.resize(fftSizeInternal);
|
||||||
fft_result_ma.resize(fftSizeInternal);
|
fft_result_ma.resize(fftSizeInternal);
|
||||||
fft_result_maa.resize(fftSizeInternal);
|
fft_result_maa.resize(fftSizeInternal);
|
||||||
@ -376,30 +401,31 @@ void SpectrumVisualProcessor::process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
|
for (int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
|
||||||
|
if (fft_result_maa[i] != fft_result_maa[i]) fft_result_maa[i] = fft_result[i];
|
||||||
fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
|
fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
|
||||||
|
if (fft_result_ma[i] != fft_result_ma[i]) fft_result_ma[i] = fft_result[i];
|
||||||
fft_result_ma[i] += (fft_result[i] - fft_result_ma[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_ceil) {
|
||||||
fft_ceil = fft_result_maa[i];
|
fft_ceil = fft_result_maa[i];
|
||||||
}
|
}
|
||||||
if (fft_result_maa[i] < fft_floor) {
|
if (fft_result_maa[i] < fft_floor || fft_floor != fft_floor) {
|
||||||
fft_floor = fft_result_maa[i];
|
fft_floor = fft_result_maa[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fft_ceil_ma != fft_ceil_ma) fft_ceil_ma = fft_ceil;
|
||||||
fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.05;
|
fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.05;
|
||||||
|
if (fft_ceil_maa != fft_ceil_maa) fft_ceil_maa = fft_ceil;
|
||||||
fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.05;
|
fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.05;
|
||||||
|
|
||||||
|
if (fft_floor_ma != fft_floor_ma) fft_floor_ma = fft_floor;
|
||||||
fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.05;
|
fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.05;
|
||||||
|
if (fft_floor_maa != fft_floor_maa) fft_floor_maa = fft_floor;
|
||||||
fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.05;
|
fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.05;
|
||||||
|
|
||||||
float sf = scaleFactor.load();
|
float sf = scaleFactor.load();
|
||||||
|
|
||||||
// for (int i = 0, iMax = fftSize; i < iMax; i++) {
|
|
||||||
// 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 + 1] = v*sf;
|
|
||||||
// }
|
|
||||||
double visualRatio = (double(bandwidth) / double(resampleBw));
|
double visualRatio = (double(bandwidth) / double(resampleBw));
|
||||||
double visualStart = (double(fftSizeInternal) / 2.0) - (double(fftSizeInternal) * (visualRatio / 2.0));
|
double visualStart = (double(fftSizeInternal) / 2.0) - (double(fftSizeInternal) * (visualRatio / 2.0));
|
||||||
double visualAccum = 0;
|
double visualAccum = 0;
|
||||||
@ -408,13 +434,6 @@ void SpectrumVisualProcessor::process() {
|
|||||||
|
|
||||||
for (int x = 0, xMax = output->spectrum_points.size() / 2; x < xMax; x++) {
|
for (int x = 0, xMax = output->spectrum_points.size() / 2; x < xMax; x++) {
|
||||||
visualAccum += visualRatio * double(SPECTRUM_VZM);
|
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) {
|
while (visualAccum >= 1.0) {
|
||||||
int idx = round(visualStart+i);
|
int idx = round(visualStart+i);
|
||||||
@ -429,8 +448,9 @@ void SpectrumVisualProcessor::process() {
|
|||||||
visualAccum -= 1.0;
|
visualAccum -= 1.0;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (accCount) {
|
|
||||||
output->spectrum_points[x * 2] = ((float) x / (float) xMax);
|
output->spectrum_points[x * 2] = ((float) x / (float) xMax);
|
||||||
|
if (accCount) {
|
||||||
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;
|
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;
|
acc = 0.0;
|
||||||
accCount = 0.0;
|
accCount = 0.0;
|
||||||
@ -475,12 +495,13 @@ void SpectrumVisualProcessor::process() {
|
|||||||
|
|
||||||
output->fft_ceiling = fft_ceil_maa/sf;
|
output->fft_ceiling = fft_ceil_maa/sf;
|
||||||
output->fft_floor = fft_floor_maa;
|
output->fft_floor = fft_floor_maa;
|
||||||
}
|
|
||||||
|
|
||||||
output->centerFreq = centerFreq;
|
output->centerFreq = centerFreq;
|
||||||
output->bandwidth = bandwidth;
|
output->bandwidth = bandwidth;
|
||||||
|
|
||||||
distribute(output);
|
distribute(output);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
iqData->decRefCount();
|
iqData->decRefCount();
|
||||||
iqData->busy_rw.unlock();
|
iqData->busy_rw.unlock();
|
||||||
|
@ -38,6 +38,7 @@ public:
|
|||||||
int getDesiredInputSize();
|
int getDesiredInputSize();
|
||||||
|
|
||||||
void setup(int fftSize);
|
void setup(int fftSize);
|
||||||
|
void setFFTSize(int fftSize);
|
||||||
void setHideDC(bool hideDC);
|
void setHideDC(bool hideDC);
|
||||||
|
|
||||||
void setScaleFactor(float sf);
|
void setScaleFactor(float sf);
|
||||||
@ -48,7 +49,7 @@ 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, newFFTSize;
|
||||||
std::atomic_int fftSizeInternal;
|
std::atomic_int fftSizeInternal;
|
||||||
std::atomic_llong centerFreq;
|
std::atomic_llong centerFreq;
|
||||||
std::atomic_long bandwidth;
|
std::atomic_long bandwidth;
|
||||||
@ -82,4 +83,5 @@ private:
|
|||||||
std::mutex busy_run;
|
std::mutex busy_run;
|
||||||
std::atomic_bool hideDC;
|
std::atomic_bool hideDC;
|
||||||
std::atomic<float> scaleFactor;
|
std::atomic<float> scaleFactor;
|
||||||
|
std::atomic_bool fftSizeChanged;
|
||||||
};
|
};
|
||||||
|
@ -157,15 +157,132 @@ void SDRPostThread::run() {
|
|||||||
|
|
||||||
iqDataInQueue->set_max_num_items(0);
|
iqDataInQueue->set_max_num_items(0);
|
||||||
|
|
||||||
std::vector<liquid_float_complex> dcBuf;
|
|
||||||
|
|
||||||
while (!terminated) {
|
while (!terminated) {
|
||||||
SDRThreadIQData *data_in;
|
SDRThreadIQData *data_in;
|
||||||
|
|
||||||
iqDataInQueue->pop(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() && data_in->numChannels) {
|
busy_demod.lock();
|
||||||
|
|
||||||
|
if (data_in && data_in->data.size()) {
|
||||||
|
if(data_in->numChannels > 1) {
|
||||||
|
runPFBCH(data_in);
|
||||||
|
} else {
|
||||||
|
runSingleCH(data_in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data_in->decRefCount();
|
||||||
|
|
||||||
|
bool doUpdate = false;
|
||||||
|
for (int j = 0; j < nRunDemods; j++) {
|
||||||
|
DemodulatorInstance *demod = runDemods[j];
|
||||||
|
if (abs(frequency - demod->getFrequency()) > (sampleRate / 2)) {
|
||||||
|
doUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doUpdate) {
|
||||||
|
updateActiveDemodulators();
|
||||||
|
}
|
||||||
|
|
||||||
|
busy_demod.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iqVisualQueue && !iqVisualQueue->empty()) {
|
||||||
|
DemodulatorThreadIQData *visualDataDummy;
|
||||||
|
iqVisualQueue->pop(visualDataDummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// buffers.purge();
|
||||||
|
// visualDataBuffers.purge();
|
||||||
|
|
||||||
|
std::cout << "SDR post-processing thread done." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDRPostThread::terminate() {
|
||||||
|
terminated = true;
|
||||||
|
SDRThreadIQData *dummy = new SDRThreadIQData;
|
||||||
|
iqDataInQueue->push(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDRPostThread::runSingleCH(SDRThreadIQData *data_in) {
|
||||||
|
if (sampleRate != data_in->sampleRate) {
|
||||||
|
sampleRate = data_in->sampleRate;
|
||||||
|
numChannels = 1;
|
||||||
|
doRefresh.store(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataSize = data_in->data.size();
|
||||||
|
int outSize = data_in->data.size();
|
||||||
|
|
||||||
|
if (outSize > dataOut.capacity()) {
|
||||||
|
dataOut.reserve(outSize);
|
||||||
|
}
|
||||||
|
if (outSize != dataOut.size()) {
|
||||||
|
dataOut.resize(outSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frequency != data_in->frequency) {
|
||||||
|
frequency = data_in->frequency;
|
||||||
|
doRefresh.store(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doRefresh.load()) {
|
||||||
|
updateActiveDemodulators();
|
||||||
|
doRefresh.store(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int refCount = nRunDemods;
|
||||||
|
bool doIQDataOut = (iqDataOutQueue != NULL && !iqDataOutQueue->full());
|
||||||
|
bool doDemodVisOut = (nRunDemods && iqActiveDemodVisualQueue != NULL && !iqActiveDemodVisualQueue->full());
|
||||||
|
bool doVisOut = (iqVisualQueue != NULL && !iqVisualQueue->full());
|
||||||
|
|
||||||
|
if (doIQDataOut) {
|
||||||
|
refCount++;
|
||||||
|
}
|
||||||
|
if (doDemodVisOut) {
|
||||||
|
refCount++;
|
||||||
|
}
|
||||||
|
if (doVisOut) {
|
||||||
|
refCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refCount) {
|
||||||
|
DemodulatorThreadIQData *demodDataOut = buffers.getBuffer();
|
||||||
|
demodDataOut->setRefCount(refCount);
|
||||||
|
demodDataOut->frequency = frequency;
|
||||||
|
demodDataOut->sampleRate = sampleRate;
|
||||||
|
|
||||||
|
if (demodDataOut->data.size() != dataSize) {
|
||||||
|
if (demodDataOut->data.capacity() < dataSize) {
|
||||||
|
demodDataOut->data.reserve(dataSize);
|
||||||
|
}
|
||||||
|
demodDataOut->data.resize(dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
iirfilt_crcf_execute_block(dcFilter, &data_in->data[0], dataSize, &demodDataOut->data[0]);
|
||||||
|
|
||||||
|
if (doDemodVisOut) {
|
||||||
|
iqActiveDemodVisualQueue->push(demodDataOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doIQDataOut) {
|
||||||
|
iqDataOutQueue->push(demodDataOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doVisOut) {
|
||||||
|
iqVisualQueue->push(demodDataOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < nRunDemods; i++) {
|
||||||
|
runDemods[i]->getIQInputDataPipe()->push(demodDataOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDRPostThread::runPFBCH(SDRThreadIQData *data_in) {
|
||||||
if (numChannels != data_in->numChannels || sampleRate != data_in->sampleRate) {
|
if (numChannels != data_in->numChannels || sampleRate != data_in->sampleRate) {
|
||||||
numChannels = data_in->numChannels;
|
numChannels = data_in->numChannels;
|
||||||
sampleRate = data_in->sampleRate;
|
sampleRate = data_in->sampleRate;
|
||||||
@ -182,9 +299,8 @@ void SDRPostThread::run() {
|
|||||||
if (outSize != dataOut.size()) {
|
if (outSize != dataOut.size()) {
|
||||||
dataOut.resize(outSize);
|
dataOut.resize(outSize);
|
||||||
}
|
}
|
||||||
int activeVisChannel = -1;
|
|
||||||
|
|
||||||
if (iqDataOutQueue != NULL && !iqDataOutQueue->full() && activeVisChannel < 0) {
|
if (iqDataOutQueue != NULL && !iqDataOutQueue->full()) {
|
||||||
DemodulatorThreadIQData *iqDataOut = visualDataBuffers.getBuffer();
|
DemodulatorThreadIQData *iqDataOut = visualDataBuffers.getBuffer();
|
||||||
|
|
||||||
bool doVis = false;
|
bool doVis = false;
|
||||||
@ -205,8 +321,6 @@ void SDRPostThread::run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
busy_demod.lock();
|
|
||||||
|
|
||||||
if (frequency != data_in->frequency) {
|
if (frequency != data_in->frequency) {
|
||||||
frequency = data_in->frequency;
|
frequency = data_in->frequency;
|
||||||
doRefresh.store(true);
|
doRefresh.store(true);
|
||||||
@ -222,7 +336,7 @@ void SDRPostThread::run() {
|
|||||||
int activeDemodChannel = -1;
|
int activeDemodChannel = -1;
|
||||||
|
|
||||||
// Find active demodulators
|
// Find active demodulators
|
||||||
if (nRunDemods || (activeVisChannel >= 0)) {
|
if (nRunDemods) {
|
||||||
|
|
||||||
// channelize data
|
// channelize data
|
||||||
// firpfbch output rate is (input rate / channels)
|
// firpfbch output rate is (input rate / channels)
|
||||||
@ -310,38 +424,4 @@ void SDRPostThread::run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool doUpdate = false;
|
|
||||||
for (int j = 0; j < nRunDemods; j++) {
|
|
||||||
DemodulatorInstance *demod = runDemods[j];
|
|
||||||
if (abs(frequency - demod->getFrequency()) > (sampleRate / 2)) {
|
|
||||||
doUpdate = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doUpdate) {
|
|
||||||
updateActiveDemodulators();
|
|
||||||
}
|
|
||||||
|
|
||||||
busy_demod.unlock();
|
|
||||||
}
|
|
||||||
data_in->decRefCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
// buffers.purge();
|
|
||||||
|
|
||||||
if (iqVisualQueue && !iqVisualQueue->empty()) {
|
|
||||||
DemodulatorThreadIQData *visualDataDummy;
|
|
||||||
iqVisualQueue->pop(visualDataDummy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// visualDataBuffers.purge();
|
|
||||||
|
|
||||||
std::cout << "SDR post-processing thread done." << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDRPostThread::terminate() {
|
|
||||||
terminated = true;
|
|
||||||
SDRThreadIQData *dummy = new SDRThreadIQData;
|
|
||||||
iqDataInQueue->push(dummy);
|
|
||||||
}
|
}
|
@ -18,6 +18,8 @@ public:
|
|||||||
void run();
|
void run();
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
|
void runSingleCH(SDRThreadIQData *data_in);
|
||||||
|
void runPFBCH(SDRThreadIQData *data_in);
|
||||||
void setIQVisualRange(long long frequency, int bandwidth);
|
void setIQVisualRange(long long frequency, int bandwidth);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -54,4 +56,5 @@ private:
|
|||||||
long long frequency;
|
long long frequency;
|
||||||
firpfbch_crcf channelizer;
|
firpfbch_crcf channelizer;
|
||||||
iirfilt_crcf dcFilter;
|
iirfilt_crcf dcFilter;
|
||||||
|
std::vector<liquid_float_complex> dcBuf;
|
||||||
};
|
};
|
||||||
|
@ -333,6 +333,10 @@ int SDRThread::getOptimalElementCount(long long sampleRate, int fps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int SDRThread::getOptimalChannelCount(long long sampleRate) {
|
int SDRThread::getOptimalChannelCount(long long sampleRate) {
|
||||||
|
if (sampleRate <= CHANNELIZER_RATE_MAX) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int optimal_rate = CHANNELIZER_RATE_MAX;
|
int optimal_rate = CHANNELIZER_RATE_MAX;
|
||||||
int optimal_count = int(ceil(double(sampleRate)/double(optimal_rate)));
|
int optimal_count = int(ceil(double(sampleRate)/double(optimal_rate)));
|
||||||
|
|
||||||
|
@ -169,6 +169,9 @@ void SpectrumCanvas::setScaleFactorEnabled(bool en) {
|
|||||||
scaleFactorEnabled = en;
|
scaleFactorEnabled = en;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpectrumCanvas::setFFTSize(int fftSize) {
|
||||||
|
spectrumPanel.setFFTSize(fftSize);
|
||||||
|
}
|
||||||
|
|
||||||
void SpectrumCanvas::updateScaleFactor(float factor) {
|
void SpectrumCanvas::updateScaleFactor(float factor) {
|
||||||
SpectrumVisualProcessor *sp = wxGetApp().getSpectrumProcessor();
|
SpectrumVisualProcessor *sp = wxGetApp().getSpectrumProcessor();
|
||||||
|
@ -26,6 +26,7 @@ public:
|
|||||||
void disableView();
|
void disableView();
|
||||||
|
|
||||||
void setScaleFactorEnabled(bool en);
|
void setScaleFactorEnabled(bool en);
|
||||||
|
void setFFTSize(int fftSize);
|
||||||
|
|
||||||
SpectrumVisualDataQueue *getVisualDataQueue();
|
SpectrumVisualDataQueue *getVisualDataQueue();
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ EVT_MOUSEWHEEL(WaterfallCanvas::OnMouseWheelMoved)
|
|||||||
wxEND_EVENT_TABLE()
|
wxEND_EVENT_TABLE()
|
||||||
|
|
||||||
WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
|
WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
|
||||||
InteractiveCanvas(parent, attribList), dragState(WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), fft_size(0), waterfall_lines(0),
|
InteractiveCanvas(parent, attribList), dragState(WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), fft_size(0), new_fft_size(0), waterfall_lines(0),
|
||||||
dragOfs(0), mouseZoom(1), zoom(1), freqMoving(false), freqMove(0.0), hoverAlpha(1.0) {
|
dragOfs(0), mouseZoom(1), zoom(1), freqMoving(false), freqMove(0.0), hoverAlpha(1.0) {
|
||||||
|
|
||||||
glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this));
|
glContext = new PrimaryGLContext(this, &wxGetApp().GetContext(this));
|
||||||
@ -43,6 +43,7 @@ WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
|
|||||||
SetCursor(wxCURSOR_CROSS);
|
SetCursor(wxCURSOR_CROSS);
|
||||||
scaleMove = 0;
|
scaleMove = 0;
|
||||||
minBandwidth = 30000;
|
minBandwidth = 30000;
|
||||||
|
fft_size_changed.store(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
WaterfallCanvas::~WaterfallCanvas() {
|
WaterfallCanvas::~WaterfallCanvas() {
|
||||||
@ -59,6 +60,14 @@ void WaterfallCanvas::setup(int fft_size_in, int waterfall_lines_in) {
|
|||||||
gTimer.start();
|
gTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WaterfallCanvas::setFFTSize(int fft_size_in) {
|
||||||
|
if (fft_size_in == fft_size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new_fft_size = fft_size_in;
|
||||||
|
fft_size_changed.store(true);
|
||||||
|
}
|
||||||
|
|
||||||
WaterfallCanvas::DragState WaterfallCanvas::getDragState() {
|
WaterfallCanvas::DragState WaterfallCanvas::getDragState() {
|
||||||
return dragState;
|
return dragState;
|
||||||
}
|
}
|
||||||
@ -88,7 +97,9 @@ void WaterfallCanvas::processInputQueue() {
|
|||||||
visualDataQueue.pop(vData);
|
visualDataQueue.pop(vData);
|
||||||
|
|
||||||
if (vData) {
|
if (vData) {
|
||||||
|
if (vData->spectrum_points.size() == fft_size * 2) {
|
||||||
waterfallPanel.setPoints(vData->spectrum_points);
|
waterfallPanel.setPoints(vData->spectrum_points);
|
||||||
|
}
|
||||||
waterfallPanel.step();
|
waterfallPanel.step();
|
||||||
vData->decRefCount();
|
vData->decRefCount();
|
||||||
updated = true;
|
updated = true;
|
||||||
@ -236,6 +247,12 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
|||||||
initGLExtensions();
|
initGLExtensions();
|
||||||
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
||||||
|
|
||||||
|
if (fft_size_changed.load()) {
|
||||||
|
fft_size = new_fft_size;
|
||||||
|
waterfallPanel.setup(fft_size, waterfall_lines);
|
||||||
|
fft_size_changed.store(false);
|
||||||
|
}
|
||||||
|
|
||||||
glContext->BeginDraw(0,0,0);
|
glContext->BeginDraw(0,0,0);
|
||||||
|
|
||||||
waterfallPanel.calcTransform(CubicVR::mat4::identity());
|
waterfallPanel.calcTransform(CubicVR::mat4::identity());
|
||||||
|
@ -20,6 +20,7 @@ public:
|
|||||||
|
|
||||||
WaterfallCanvas(wxWindow *parent, int *attribList = NULL);
|
WaterfallCanvas(wxWindow *parent, int *attribList = NULL);
|
||||||
void setup(int fft_size_in, int waterfall_lines_in);
|
void setup(int fft_size_in, int waterfall_lines_in);
|
||||||
|
void setFFTSize(int fft_size_in);
|
||||||
~WaterfallCanvas();
|
~WaterfallCanvas();
|
||||||
|
|
||||||
DragState getDragState();
|
DragState getDragState();
|
||||||
@ -59,7 +60,7 @@ private:
|
|||||||
DragState dragState;
|
DragState dragState;
|
||||||
DragState nextDragState;
|
DragState nextDragState;
|
||||||
|
|
||||||
int fft_size;
|
int fft_size, new_fft_size;
|
||||||
int waterfall_lines;
|
int waterfall_lines;
|
||||||
int dragOfs;
|
int dragOfs;
|
||||||
|
|
||||||
@ -77,6 +78,7 @@ private:
|
|||||||
bool preBuf;
|
bool preBuf;
|
||||||
std::mutex tex_update;
|
std::mutex tex_update;
|
||||||
int minBandwidth;
|
int minBandwidth;
|
||||||
|
std::atomic_bool fft_size_changed;
|
||||||
// event table
|
// event table
|
||||||
wxDECLARE_EVENT_TABLE();
|
wxDECLARE_EVENT_TABLE();
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user