Experimental AM/LSB/USB demodulation

This commit is contained in:
Charles J. Cliffe 2015-01-01 03:48:32 -05:00
parent 955ec54b44
commit 8b89b27b40
7 changed files with 144 additions and 28 deletions

View File

@ -150,7 +150,16 @@ AppFrame::AppFrame() :
} }
wxMenuBar *menuBar = new wxMenuBar; 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); SetMenuBar(menuBar);
@ -177,6 +186,22 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
activeDemodulator = NULL; 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)) { void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) {
@ -207,6 +232,8 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
int outputDevice = demod->getOutputDevice(); int outputDevice = demod->getOutputDevice();
scopeCanvas->setDeviceName(output_devices[outputDevice].name); scopeCanvas->setDeviceName(output_devices[outputDevice].name);
output_device_menuitems[outputDevice]->Check(true); output_device_menuitems[outputDevice]->Check(true);
DemodulatorType dType = demod->getDemodulatorType();
demod_menuitems[dType]->Check(true);
} }
if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) { if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) {
if (demod->getParams().frequency != demodWaterfallCanvas->GetCenterFrequency()) { if (demod->getParams().frequency != demodWaterfallCanvas->GetCenterFrequency()) {

View File

@ -11,6 +11,7 @@
#include <map> #include <map>
#define wxID_RT_AUDIO_DEVICE 1000 #define wxID_RT_AUDIO_DEVICE 1000
#define wxID_DEMOD_TYPE 1500
// Define a new frame type // Define a new frame type
class AppFrame: public wxFrame { class AppFrame: public wxFrame {
@ -41,5 +42,7 @@ private:
std::map<int,RtAudio::DeviceInfo> output_devices; std::map<int,RtAudio::DeviceInfo> output_devices;
std::map<int,wxMenuItem *> output_device_menuitems; std::map<int,wxMenuItem *> output_device_menuitems;
std::map<DemodulatorType,wxMenuItem *> demod_menuitems;
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
}; };

View File

@ -207,3 +207,12 @@ void DemodulatorInstance::setOutputDevice(int device_id) {
int DemodulatorInstance::getOutputDevice() { int DemodulatorInstance::getOutputDevice() {
return audioThread->getOutputDevice(); return audioThread->getOutputDevice();
} }
void DemodulatorInstance::setDemodulatorType(DemodulatorType demod_type_in) {
demodulatorThread->setDemodulatorType(demod_type_in);
}
DemodulatorType DemodulatorInstance::getDemodulatorType() {
return demodulatorThread->getDemodulatorType();
}

View File

@ -63,6 +63,9 @@ public:
void setOutputDevice(int device_id); void setOutputDevice(int device_id);
int getOutputDevice(); int getOutputDevice();
void setDemodulatorType(DemodulatorType demod_type_in);
DemodulatorType getDemodulatorType();
private: private:
std::atomic<std::string *> label; // std::atomic<std::string *> label; //
bool terminated; // bool terminated; //

View File

@ -8,10 +8,18 @@
DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* pQueue, DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* pQueue, DemodulatorThreadControlCommandQueue *threadQueueControl,
DemodulatorThreadCommandQueue* threadQueueNotify) : DemodulatorThreadCommandQueue* threadQueueNotify) :
postInputQueue(pQueue), visOutQueue(NULL), audioInputQueue(NULL), agc(NULL), stereo(false), terminated(false), threadQueueNotify( postInputQueue(pQueue), visOutQueue(NULL), audioInputQueue(NULL), agc(NULL), am_max(1), am_max_ma(1), am_max_maa(1), stereo(false), terminated(
threadQueueNotify), threadQueueControl(threadQueueControl), squelch_level(0), squelch_tolerance(0), signal_level(0), squelch_enabled(false) { 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); 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() { DemodulatorThread::~DemodulatorThread() {
} }
@ -66,16 +74,6 @@ void DemodulatorThread::threadMain() {
std::cout << "Demodulator thread started.." << std::endl; 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; double freq_index = 0;
while (!terminated) { while (!terminated) {
@ -101,6 +99,11 @@ void DemodulatorThread::threadMain() {
resampler = inp->resampler; resampler = inp->resampler;
audio_resampler = inp->audio_resampler; audio_resampler = inp->audio_resampler;
stereo_resampler = inp->stereo_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); 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.size() != out_size) {
if (agc_data.capacity() < out_size) { if (agc_data.capacity() < out_size) {
agc_data.reserve(out_size); agc_data.reserve(out_size);
agc_am_data.reserve(out_size);
resampled_data.reserve(out_size); resampled_data.reserve(out_size);
} }
agc_data.resize(out_size); agc_data.resize(out_size);
resampled_data.resize(out_size); resampled_data.resize(out_size);
agc_am_data.resize(out_size);
} }
unsigned int num_written; unsigned int num_written;
msresamp_crcf_execute(resampler, &(inp->data[0]), bufSize, &resampled_data[0], &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; double audio_resample_ratio = inp->audio_resample_ratio;
if (demod_output.size() != num_written) { if (demod_output.size() != num_written) {
@ -130,7 +133,51 @@ void DemodulatorThread::threadMain() {
int audio_out_size = ceil((double) (num_written) * audio_resample_ratio); 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 (audio_out_size != resampled_audio_output.size()) {
if (resampled_audio_output.capacity() < audio_out_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); 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) { 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 { } else {
signal_level = signal_level + (current_level-signal_level) * 0.05; signal_level = signal_level + (current_level - signal_level) * 0.05;
} }
AudioThreadInput *ati = NULL; AudioThreadInput *ati = NULL;
if (audioInputQueue != NULL) { if (audioInputQueue != NULL) {
@ -242,8 +286,8 @@ void DemodulatorThread::threadMain() {
ati_vis->data.resize(stereoSize); ati_vis->data.resize(stereoSize);
for (int i = 0; i < stereoSize / 2; i++) { for (int i = 0; i < stereoSize / 2; i++) {
ati_vis->data[i] = ati->data[i*2]; ati_vis->data[i] = ati->data[i * 2];
ati_vis->data[i + stereoSize / 2] = ati->data[i*2+1]; ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1];
} }
} else { } else {
ati_vis->channels = 1; ati_vis->channels = 1;
@ -352,3 +396,11 @@ void DemodulatorThread::setSquelchLevel(float signal_level_in) {
float DemodulatorThread::getSquelchLevel() { float DemodulatorThread::getSquelchLevel() {
return squelch_level; return squelch_level;
} }
void DemodulatorThread::setDemodulatorType(DemodulatorType demod_type_in) {
demodulatorType = demod_type_in;
}
DemodulatorType DemodulatorThread::getDemodulatorType() {
return demodulatorType;
}

View File

@ -34,13 +34,14 @@ public:
void initialize(); void initialize();
void terminate(); void terminate();
void setStereo(bool state); void setStereo(bool state);bool isStereo();
bool isStereo();
float getSignalLevel(); float getSignalLevel();
void setSquelchLevel(float signal_level_in); void setSquelchLevel(float signal_level_in);
float getSquelchLevel(); float getSquelchLevel();
void setDemodulatorType(DemodulatorType demod_type_in);
DemodulatorType getDemodulatorType();
#ifdef __APPLE__ #ifdef __APPLE__
static void *pthread_helper(void *context) { static void *pthread_helper(void *context) {
@ -49,20 +50,39 @@ public:
#endif #endif
protected: 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; DemodulatorThreadPostInputQueue* postInputQueue;
DemodulatorThreadOutputQueue* visOutQueue; DemodulatorThreadOutputQueue* visOutQueue;
AudioThreadInputQueue *audioInputQueue; AudioThreadInputQueue *audioInputQueue;
freqdem fdem; freqdem fdem;
ampmodem ampdem;
ampmodem ampdem_usb;
ampmodem ampdem_lsb;
agc_crcf agc; agc_crcf agc;
float am_max;
float am_max_ma;
float am_max_maa;
std::atomic<bool> stereo; std::atomic<bool> stereo;
std::atomic<bool> terminated; std::atomic<bool> terminated;
std::atomic<DemodulatorType> demodulatorType;
DemodulatorThreadCommandQueue* threadQueueNotify; DemodulatorThreadCommandQueue* threadQueueNotify;
DemodulatorThreadControlCommandQueue *threadQueueControl; DemodulatorThreadControlCommandQueue *threadQueueControl;
std::atomic<float> squelch_level; std::atomic<float> squelch_level;
float squelch_tolerance; float squelch_tolerance;
std::atomic<float> signal_level; std::atomic<float> signal_level;bool squelch_enabled;
bool squelch_enabled;
}; };

View File

@ -17,7 +17,9 @@
#include <wx/numformatter.h> #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) wxBEGIN_EVENT_TABLE(WaterfallCanvas, wxGLCanvas) EVT_PAINT(WaterfallCanvas::OnPaint)
EVT_KEY_DOWN(WaterfallCanvas::OnKeyDown) EVT_KEY_DOWN(WaterfallCanvas::OnKeyDown)