mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2024-11-26 13:48:38 -05:00
Demodulator can now tune offset!
Demodulator will up-convert / down-convert by mixing VCO with incoming IQ to shift frequency -- No longer limited to center freq. can listen anywhere on the waterfall.
This commit is contained in:
parent
df853bfd65
commit
1554348f55
@ -88,7 +88,7 @@ PrimaryGLContext& CubicSDR::GetContext(wxGLCanvas *canvas) {
|
|||||||
|
|
||||||
void CubicSDR::setFrequency(unsigned int freq) {
|
void CubicSDR::setFrequency(unsigned int freq) {
|
||||||
frequency = freq;
|
frequency = freq;
|
||||||
demodulatorTest->getParams().frequency = freq;
|
// demodulatorTest->getParams().frequency = freq;
|
||||||
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_TUNE);
|
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_TUNE);
|
||||||
command.int_value = freq;
|
command.int_value = freq;
|
||||||
threadCmdQueueSDR->push(command);
|
threadCmdQueueSDR->push(command);
|
||||||
|
@ -3,12 +3,16 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
DemodulatorThread::DemodulatorThread(DemodulatorThreadInputQueue* pQueue) :
|
DemodulatorThread::DemodulatorThread(DemodulatorThreadInputQueue* pQueue) :
|
||||||
inputQueue(pQueue), visOutQueue(NULL), terminated(false), initialized(false), audio_resampler(NULL), resample_ratio(1), audio_resample_ratio(1), resampler(NULL), commandQueue(NULL), fir_filter(NULL) {
|
inputQueue(pQueue), visOutQueue(NULL), terminated(false), initialized(false), audio_resampler(NULL), resample_ratio(1), audio_resample_ratio(
|
||||||
|
1), resampler(NULL), commandQueue(NULL), fir_filter(NULL) {
|
||||||
|
|
||||||
float kf = 0.75; // modulation factor
|
float kf = 0.75; // modulation factor
|
||||||
fdem = freqdem_create(kf);
|
fdem = freqdem_create(kf);
|
||||||
// freqdem_print(fdem);
|
// freqdem_print(fdem);
|
||||||
|
|
||||||
|
nco_shift = nco_crcf_create(LIQUID_VCO);
|
||||||
|
shift_freq = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DemodulatorThread::initialize() {
|
void DemodulatorThread::initialize() {
|
||||||
@ -55,7 +59,6 @@ void DemodulatorThread::initialize() {
|
|||||||
audio_resampler = msresamp_crcf_create(audio_resample_ratio, As);
|
audio_resampler = msresamp_crcf_create(audio_resample_ratio, As);
|
||||||
// msresamp_crcf_print(audio_resampler);
|
// msresamp_crcf_print(audio_resampler);
|
||||||
|
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
// std::cout << "inputResampleRate " << params.bandwidth << std::endl;
|
// std::cout << "inputResampleRate " << params.bandwidth << std::endl;
|
||||||
|
|
||||||
@ -82,7 +85,7 @@ void DemodulatorThread::threadMain() {
|
|||||||
DemodulatorThreadCommand command;
|
DemodulatorThreadCommand command;
|
||||||
commandQueue->pop(command);
|
commandQueue->pop(command);
|
||||||
switch (command.cmd) {
|
switch (command.cmd) {
|
||||||
case DemodulatorThreadCommand::SDR_THREAD_CMD_SETBANDWIDTH:
|
case DemodulatorThreadCommand::SDR_THREAD_CMD_SET_BANDWIDTH:
|
||||||
if (command.int_value < 3000) {
|
if (command.int_value < 3000) {
|
||||||
command.int_value = 3000;
|
command.int_value = 3000;
|
||||||
}
|
}
|
||||||
@ -92,6 +95,9 @@ void DemodulatorThread::threadMain() {
|
|||||||
params.bandwidth = command.int_value;
|
params.bandwidth = command.int_value;
|
||||||
paramsChanged = true;
|
paramsChanged = true;
|
||||||
break;
|
break;
|
||||||
|
case DemodulatorThreadCommand::SDR_THREAD_CMD_SET_FREQUENCY:
|
||||||
|
params.frequency = command.int_value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,17 +113,42 @@ void DemodulatorThread::threadMain() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Requested frequency is not center, shift it into the center!
|
||||||
|
if (inp.frequency != params.frequency) {
|
||||||
|
if ((params.frequency - inp.frequency) != shift_freq) {
|
||||||
|
shift_freq = params.frequency - inp.frequency;
|
||||||
|
if (abs(shift_freq) <= (int)((float)(SRATE/2) * 1.5)) {
|
||||||
|
nco_crcf_set_frequency(nco_shift, (2.0 * M_PI) * (((float)abs(shift_freq)) / ((float) SRATE)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abs(shift_freq) > (int)((float)(SRATE/2) * 1.5)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<signed char> *data = &inp.data;
|
std::vector<signed char> *data = &inp.data;
|
||||||
if (data->size()) {
|
if (data->size()) {
|
||||||
liquid_float_complex filtered_input[BUF_SIZE / 2];
|
liquid_float_complex filtered_input[BUF_SIZE / 2];
|
||||||
|
|
||||||
|
liquid_float_complex x, y, z;
|
||||||
|
|
||||||
for (int i = 0; i < BUF_SIZE / 2; i++) {
|
for (int i = 0; i < BUF_SIZE / 2; i++) {
|
||||||
|
if (shift_freq != 0) {
|
||||||
|
nco_crcf_step(nco_shift);
|
||||||
|
|
||||||
liquid_float_complex x;
|
z.real = (float) (*data)[i * 2] / 127.0f;
|
||||||
liquid_float_complex y;
|
z.imag = (float) (*data)[i * 2 + 1] / 127.0f;
|
||||||
|
|
||||||
|
if (shift_freq < 0) {
|
||||||
|
nco_crcf_mix_up(nco_shift, z, &x);
|
||||||
|
} else {
|
||||||
|
nco_crcf_mix_down(nco_shift, z, &x);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
x.real = (float) (*data)[i * 2] / 127.0f;
|
x.real = (float) (*data)[i * 2] / 127.0f;
|
||||||
x.imag = (float) (*data)[i * 2 + 1] / 127.0f;
|
x.imag = (float) (*data)[i * 2 + 1] / 127.0f;
|
||||||
|
}
|
||||||
|
|
||||||
firfilt_crcf_push(fir_filter, x); // push input sample
|
firfilt_crcf_push(fir_filter, x); // push input sample
|
||||||
firfilt_crcf_execute(fir_filter, &y); // compute output
|
firfilt_crcf_execute(fir_filter, &y); // compute output
|
||||||
|
@ -23,7 +23,8 @@ class DemodulatorThreadCommand {
|
|||||||
public:
|
public:
|
||||||
enum DemodulatorThreadCommandEnum {
|
enum DemodulatorThreadCommandEnum {
|
||||||
SDR_THREAD_CMD_NULL,
|
SDR_THREAD_CMD_NULL,
|
||||||
SDR_THREAD_CMD_SETBANDWIDTH
|
SDR_THREAD_CMD_SET_BANDWIDTH,
|
||||||
|
SDR_THREAD_CMD_SET_FREQUENCY
|
||||||
};
|
};
|
||||||
|
|
||||||
DemodulatorThreadCommand() : cmd(cmd), int_value(SDR_THREAD_CMD_NULL) {
|
DemodulatorThreadCommand() : cmd(cmd), int_value(SDR_THREAD_CMD_NULL) {
|
||||||
@ -149,6 +150,9 @@ protected:
|
|||||||
DemodulatorThreadParameters last_params;
|
DemodulatorThreadParameters last_params;
|
||||||
|
|
||||||
freqdem fdem;
|
freqdem fdem;
|
||||||
|
nco_crcf nco_shift;
|
||||||
|
int shift_freq;
|
||||||
|
|
||||||
|
|
||||||
std::atomic<bool> terminated;
|
std::atomic<bool> terminated;
|
||||||
std::atomic<bool> initialized;
|
std::atomic<bool> initialized;
|
||||||
|
@ -199,7 +199,7 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DemodulatorThreadCommand command;
|
DemodulatorThreadCommand command;
|
||||||
command.cmd = DemodulatorThreadCommand::SDR_THREAD_CMD_SETBANDWIDTH;
|
command.cmd = DemodulatorThreadCommand::SDR_THREAD_CMD_SET_BANDWIDTH;
|
||||||
demodBW = demodBW - bwDiff;
|
demodBW = demodBW - bwDiff;
|
||||||
if (demodBW < 1000) {
|
if (demodBW < 1000) {
|
||||||
demodBW = 1000;
|
demodBW = 1000;
|
||||||
@ -245,11 +245,17 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) {
|
|||||||
|
|
||||||
float pos = mTracker.getMouseX();
|
float pos = mTracker.getMouseX();
|
||||||
|
|
||||||
int freq = wxGetApp().getFrequency();
|
int center_freq = wxGetApp().getFrequency();
|
||||||
|
|
||||||
freq += (pos - 0.5) * SRATE;
|
DemodulatorInstance *demod = wxGetApp().getDemodTest();
|
||||||
|
|
||||||
wxGetApp().setFrequency(freq);
|
int freq = center_freq - (int)(0.5 * (float)SRATE) + (int)((float)pos * (float)SRATE);
|
||||||
|
|
||||||
|
DemodulatorThreadCommand command;
|
||||||
|
command.cmd = DemodulatorThreadCommand::SDR_THREAD_CMD_SET_FREQUENCY;
|
||||||
|
command.int_value = freq;
|
||||||
|
|
||||||
|
demod->getCommandQueue()->push(command);
|
||||||
|
|
||||||
((wxFrame*) parent)->GetStatusBar()->SetStatusText(
|
((wxFrame*) parent)->GetStatusBar()->SetStatusText(
|
||||||
wxString::Format(wxT("Set center frequency: %s"),
|
wxString::Format(wxT("Set center frequency: %s"),
|
||||||
|
Loading…
Reference in New Issue
Block a user