mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2024-11-26 13:48:38 -05:00
Experimental AM/LSB/USB demodulation
This commit is contained in:
parent
955ec54b44
commit
8b89b27b40
@ -150,7 +150,16 @@ AppFrame::AppFrame() :
|
||||
}
|
||||
|
||||
wxMenuBar *menuBar = new wxMenuBar;
|
||||
menuBar->Append(menu, wxT("&Device"));
|
||||
menuBar->Append(menu, wxT("Output &Device"));
|
||||
|
||||
wxMenu *demodMenu = new wxMenu;
|
||||
demod_menuitems[DemodulatorType::DEMOD_TYPE_FM] = demodMenu->AppendRadioItem(wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_FM,wxT("FM"),wxT("Description?"));
|
||||
demod_menuitems[DemodulatorType::DEMOD_TYPE_AM] = demodMenu->AppendRadioItem(wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_AM,wxT("AM"),wxT("Description?"));
|
||||
demod_menuitems[DemodulatorType::DEMOD_TYPE_LSB] = demodMenu->AppendRadioItem(wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_LSB,wxT("LSB"),wxT("Description?"));
|
||||
demod_menuitems[DemodulatorType::DEMOD_TYPE_USB] = demodMenu->AppendRadioItem(wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_USB,wxT("USB"),wxT("Description?"));
|
||||
|
||||
menuBar->Append(demodMenu, wxT("Demodulaton &Type"));
|
||||
|
||||
|
||||
SetMenuBar(menuBar);
|
||||
|
||||
@ -177,6 +186,22 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
|
||||
activeDemodulator = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (activeDemodulator) {
|
||||
if (event.GetId() == wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_FM) {
|
||||
activeDemodulator->setDemodulatorType(DemodulatorType::DEMOD_TYPE_FM);
|
||||
activeDemodulator = NULL;
|
||||
} else if (event.GetId() == wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_AM) {
|
||||
activeDemodulator->setDemodulatorType(DemodulatorType::DEMOD_TYPE_AM);
|
||||
activeDemodulator = NULL;
|
||||
} else if (event.GetId() == wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_LSB) {
|
||||
activeDemodulator->setDemodulatorType(DemodulatorType::DEMOD_TYPE_LSB);
|
||||
activeDemodulator = NULL;
|
||||
} else if (event.GetId() == wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_USB) {
|
||||
activeDemodulator->setDemodulatorType(DemodulatorType::DEMOD_TYPE_USB);
|
||||
activeDemodulator = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) {
|
||||
@ -207,6 +232,8 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
||||
int outputDevice = demod->getOutputDevice();
|
||||
scopeCanvas->setDeviceName(output_devices[outputDevice].name);
|
||||
output_device_menuitems[outputDevice]->Check(true);
|
||||
DemodulatorType dType = demod->getDemodulatorType();
|
||||
demod_menuitems[dType]->Check(true);
|
||||
}
|
||||
if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) {
|
||||
if (demod->getParams().frequency != demodWaterfallCanvas->GetCenterFrequency()) {
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <map>
|
||||
|
||||
#define wxID_RT_AUDIO_DEVICE 1000
|
||||
#define wxID_DEMOD_TYPE 1500
|
||||
|
||||
// Define a new frame type
|
||||
class AppFrame: public wxFrame {
|
||||
@ -41,5 +42,7 @@ private:
|
||||
std::map<int,RtAudio::DeviceInfo> output_devices;
|
||||
std::map<int,wxMenuItem *> output_device_menuitems;
|
||||
|
||||
std::map<DemodulatorType,wxMenuItem *> demod_menuitems;
|
||||
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
@ -207,3 +207,12 @@ void DemodulatorInstance::setOutputDevice(int device_id) {
|
||||
int DemodulatorInstance::getOutputDevice() {
|
||||
return audioThread->getOutputDevice();
|
||||
}
|
||||
|
||||
void DemodulatorInstance::setDemodulatorType(DemodulatorType demod_type_in) {
|
||||
demodulatorThread->setDemodulatorType(demod_type_in);
|
||||
}
|
||||
|
||||
DemodulatorType DemodulatorInstance::getDemodulatorType() {
|
||||
return demodulatorThread->getDemodulatorType();
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,9 @@ public:
|
||||
void setOutputDevice(int device_id);
|
||||
int getOutputDevice();
|
||||
|
||||
void setDemodulatorType(DemodulatorType demod_type_in);
|
||||
DemodulatorType getDemodulatorType();
|
||||
|
||||
private:
|
||||
std::atomic<std::string *> label; //
|
||||
bool terminated; //
|
||||
|
@ -8,10 +8,18 @@
|
||||
|
||||
DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* pQueue, DemodulatorThreadControlCommandQueue *threadQueueControl,
|
||||
DemodulatorThreadCommandQueue* threadQueueNotify) :
|
||||
postInputQueue(pQueue), visOutQueue(NULL), audioInputQueue(NULL), agc(NULL), stereo(false), terminated(false), threadQueueNotify(
|
||||
threadQueueNotify), threadQueueControl(threadQueueControl), squelch_level(0), squelch_tolerance(0), signal_level(0), squelch_enabled(false) {
|
||||
postInputQueue(pQueue), visOutQueue(NULL), audioInputQueue(NULL), agc(NULL), am_max(1), am_max_ma(1), am_max_maa(1), stereo(false), terminated(
|
||||
false), demodulatorType(DemodulatorType::DEMOD_TYPE_FM), threadQueueNotify(threadQueueNotify), threadQueueControl(threadQueueControl), squelch_level(
|
||||
0), squelch_tolerance(0), signal_level(0), squelch_enabled(false) {
|
||||
|
||||
fdem = freqdem_create(0.5);
|
||||
liquid_ampmodem_type type_lsb = LIQUID_AMPMODEM_LSB;
|
||||
ampdem_lsb = ampmodem_create(1.0, 0.5, type_lsb, 1);
|
||||
liquid_ampmodem_type type_usb = LIQUID_AMPMODEM_USB;
|
||||
ampdem_usb = ampmodem_create(1.0, -0.5, type_usb, 1);
|
||||
liquid_ampmodem_type type_dsb = LIQUID_AMPMODEM_DSB;
|
||||
ampdem = ampmodem_create(0.5, 0.0, type_dsb, 0);
|
||||
|
||||
}
|
||||
DemodulatorThread::~DemodulatorThread() {
|
||||
}
|
||||
@ -66,16 +74,6 @@ void DemodulatorThread::threadMain() {
|
||||
|
||||
std::cout << "Demodulator thread started.." << std::endl;
|
||||
|
||||
std::deque<AudioThreadInput *> buffers;
|
||||
std::deque<AudioThreadInput *>::iterator buffers_i;
|
||||
|
||||
std::vector<liquid_float_complex> resampled_data;
|
||||
std::vector<liquid_float_complex> agc_data;
|
||||
std::vector<float> demod_output;
|
||||
std::vector<float> demod_output_stereo;
|
||||
std::vector<float> resampled_audio_output;
|
||||
std::vector<float> resampled_audio_output_stereo;
|
||||
|
||||
double freq_index = 0;
|
||||
|
||||
while (!terminated) {
|
||||
@ -101,6 +99,11 @@ void DemodulatorThread::threadMain() {
|
||||
resampler = inp->resampler;
|
||||
audio_resampler = inp->audio_resampler;
|
||||
stereo_resampler = inp->stereo_resampler;
|
||||
|
||||
ampmodem_reset(ampdem_lsb);
|
||||
ampmodem_reset(ampdem_usb);
|
||||
ampmodem_reset(ampdem);
|
||||
freqdem_reset(fdem);
|
||||
}
|
||||
|
||||
int out_size = ceil((double) (bufSize) * inp->resample_ratio);
|
||||
@ -108,17 +111,17 @@ void DemodulatorThread::threadMain() {
|
||||
if (agc_data.size() != out_size) {
|
||||
if (agc_data.capacity() < out_size) {
|
||||
agc_data.reserve(out_size);
|
||||
agc_am_data.reserve(out_size);
|
||||
resampled_data.reserve(out_size);
|
||||
}
|
||||
agc_data.resize(out_size);
|
||||
resampled_data.resize(out_size);
|
||||
agc_am_data.resize(out_size);
|
||||
}
|
||||
|
||||
unsigned int num_written;
|
||||
msresamp_crcf_execute(resampler, &(inp->data[0]), bufSize, &resampled_data[0], &num_written);
|
||||
|
||||
agc_crcf_execute_block(agc, &resampled_data[0], num_written, &agc_data[0]);
|
||||
|
||||
double audio_resample_ratio = inp->audio_resample_ratio;
|
||||
|
||||
if (demod_output.size() != num_written) {
|
||||
@ -130,7 +133,51 @@ void DemodulatorThread::threadMain() {
|
||||
|
||||
int audio_out_size = ceil((double) (num_written) * audio_resample_ratio);
|
||||
|
||||
freqdem_demodulate_block(fdem, &agc_data[0], num_written, &demod_output[0]);
|
||||
agc_crcf_execute_block(agc, &resampled_data[0], num_written, &agc_data[0]);
|
||||
|
||||
float current_level = 0;
|
||||
|
||||
current_level = ((60.0 / fabs(agc_crcf_get_rssi(agc))) / 15.0 - signal_level);
|
||||
|
||||
if (agc_crcf_get_signal_level(agc) > current_level) {
|
||||
current_level = agc_crcf_get_signal_level(agc);
|
||||
}
|
||||
|
||||
switch (demodulatorType) {
|
||||
case DemodulatorType::DEMOD_TYPE_FM:
|
||||
freqdem_demodulate_block(fdem, &agc_data[0], num_written, &demod_output[0]);
|
||||
break;
|
||||
case DemodulatorType::DEMOD_TYPE_LSB:
|
||||
for (int i = 0; i < num_written; i++) {
|
||||
ampmodem_demodulate(ampdem_lsb, resampled_data[i], &demod_output[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
case DemodulatorType::DEMOD_TYPE_USB:
|
||||
for (int i = 0; i < num_written; i++) {
|
||||
ampmodem_demodulate(ampdem_usb, resampled_data[i], &demod_output[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
case DemodulatorType::DEMOD_TYPE_AM:
|
||||
am_max = 0;
|
||||
for (int i = 0; i < num_written; i++) {
|
||||
ampmodem_demodulate(ampdem, resampled_data[i], &demod_output[i]);
|
||||
if (demod_output[i] > am_max) {
|
||||
am_max = demod_output[i];
|
||||
}
|
||||
}
|
||||
am_max_ma = am_max_ma + (am_max - am_max_ma) * 0.03;
|
||||
am_max_maa = am_max_maa + (am_max_ma - am_max_maa) * 0.03;
|
||||
|
||||
float gain = 0.95/am_max_maa;
|
||||
|
||||
for (int i = 0; i < num_written; i++) {
|
||||
demod_output[i] *= gain;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (audio_out_size != resampled_audio_output.size()) {
|
||||
if (resampled_audio_output.capacity() < audio_out_size) {
|
||||
@ -174,15 +221,12 @@ void DemodulatorThread::threadMain() {
|
||||
msresamp_rrrf_execute(stereo_resampler, &demod_output_stereo[0], num_written, &resampled_audio_output_stereo[0], &num_audio_written);
|
||||
}
|
||||
|
||||
float current_level = ((60.0/fabs(agc_crcf_get_rssi(agc)))/15.0 - signal_level); //agc_crcf_get_signal_level(agc);
|
||||
|
||||
if (current_level > signal_level) {
|
||||
signal_level = signal_level + (current_level-signal_level) * 0.5;
|
||||
signal_level = signal_level + (current_level - signal_level) * 0.5;
|
||||
} else {
|
||||
signal_level = signal_level + (current_level-signal_level) * 0.05;
|
||||
signal_level = signal_level + (current_level - signal_level) * 0.05;
|
||||
}
|
||||
|
||||
|
||||
AudioThreadInput *ati = NULL;
|
||||
|
||||
if (audioInputQueue != NULL) {
|
||||
@ -242,8 +286,8 @@ void DemodulatorThread::threadMain() {
|
||||
ati_vis->data.resize(stereoSize);
|
||||
|
||||
for (int i = 0; i < stereoSize / 2; i++) {
|
||||
ati_vis->data[i] = ati->data[i*2];
|
||||
ati_vis->data[i + stereoSize / 2] = ati->data[i*2+1];
|
||||
ati_vis->data[i] = ati->data[i * 2];
|
||||
ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1];
|
||||
}
|
||||
} else {
|
||||
ati_vis->channels = 1;
|
||||
@ -352,3 +396,11 @@ void DemodulatorThread::setSquelchLevel(float signal_level_in) {
|
||||
float DemodulatorThread::getSquelchLevel() {
|
||||
return squelch_level;
|
||||
}
|
||||
|
||||
void DemodulatorThread::setDemodulatorType(DemodulatorType demod_type_in) {
|
||||
demodulatorType = demod_type_in;
|
||||
}
|
||||
|
||||
DemodulatorType DemodulatorThread::getDemodulatorType() {
|
||||
return demodulatorType;
|
||||
}
|
||||
|
@ -34,13 +34,14 @@ public:
|
||||
void initialize();
|
||||
void terminate();
|
||||
|
||||
void setStereo(bool state);
|
||||
bool isStereo();
|
||||
void setStereo(bool state);bool isStereo();
|
||||
|
||||
float getSignalLevel();
|
||||
void setSquelchLevel(float signal_level_in);
|
||||
float getSquelchLevel();
|
||||
|
||||
void setDemodulatorType(DemodulatorType demod_type_in);
|
||||
DemodulatorType getDemodulatorType();
|
||||
|
||||
#ifdef __APPLE__
|
||||
static void *pthread_helper(void *context) {
|
||||
@ -49,20 +50,39 @@ public:
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::deque<AudioThreadInput *> buffers;
|
||||
std::deque<AudioThreadInput *>::iterator buffers_i;
|
||||
|
||||
std::vector<liquid_float_complex> resampled_data;
|
||||
std::vector<liquid_float_complex> agc_data;
|
||||
std::vector<float> agc_am_data;
|
||||
std::vector<float> demod_output;
|
||||
std::vector<float> demod_output_stereo;
|
||||
std::vector<float> resampled_audio_output;
|
||||
std::vector<float> resampled_audio_output_stereo;
|
||||
|
||||
DemodulatorThreadPostInputQueue* postInputQueue;
|
||||
DemodulatorThreadOutputQueue* visOutQueue;
|
||||
AudioThreadInputQueue *audioInputQueue;
|
||||
|
||||
freqdem fdem;
|
||||
ampmodem ampdem;
|
||||
ampmodem ampdem_usb;
|
||||
ampmodem ampdem_lsb;
|
||||
|
||||
agc_crcf agc;
|
||||
|
||||
float am_max;
|
||||
float am_max_ma;
|
||||
float am_max_maa;
|
||||
|
||||
std::atomic<bool> stereo;
|
||||
std::atomic<bool> terminated;
|
||||
std::atomic<DemodulatorType> demodulatorType;
|
||||
|
||||
DemodulatorThreadCommandQueue* threadQueueNotify;
|
||||
DemodulatorThreadControlCommandQueue *threadQueueControl;
|
||||
std::atomic<float> squelch_level;
|
||||
float squelch_tolerance;
|
||||
std::atomic<float> signal_level;
|
||||
bool squelch_enabled;
|
||||
std::atomic<float> signal_level;bool squelch_enabled;
|
||||
};
|
||||
|
@ -17,7 +17,9 @@
|
||||
|
||||
#include <wx/numformatter.h>
|
||||
|
||||
#define MIN_FM_BANDWIDTH 10000
|
||||
#define MIN_FM_BANDWIDTH 2000
|
||||
#define MIN_AM_BANDWIDTH 2000
|
||||
|
||||
|
||||
wxBEGIN_EVENT_TABLE(WaterfallCanvas, wxGLCanvas) EVT_PAINT(WaterfallCanvas::OnPaint)
|
||||
EVT_KEY_DOWN(WaterfallCanvas::OnKeyDown)
|
||||
|
Loading…
Reference in New Issue
Block a user