Modem, ModemKit and initial ModemAnalog refactor

This commit is contained in:
Charles J. Cliffe
2015-11-16 23:49:54 -05:00
parent f1f2cb91eb
commit a1a6a467e8
46 changed files with 932 additions and 186 deletions
+27
View File
@@ -0,0 +1,27 @@
#include "Modem.h"
ModemFactoryList Modem::modemFactories;
void Modem::addModemFactory(std::string modemName, ModemFactoryFunc *factoryFunc) {
modemFactories[modemName] = factoryFunc;
}
ModemFactoryList Modem::getFactories() {
return modemFactories;
}
Modem *Modem::factory() {
return nullptr;
}
ModemKit *Modem::buildKit(long long sampleRate, int audioSampleRate) {
return nullptr;
}
void Modem::disposeKit(ModemKit *kit) {
return;
}
void Modem::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
return;
}
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include "liquid/liquid.h"
#include "IOThread.h"
#include "AudioThread.h"
class ModemKit {
public:
ModemKit() : sampleRate(0), audioSampleRate(0) {
}
long long sampleRate;
int audioSampleRate;
};
class ModemIQData: public ReferenceCounter {
public:
std::vector<liquid_float_complex> data;
long long sampleRate;
ModemIQData() : sampleRate(0) {
}
~ModemIQData() {
std::lock_guard < std::mutex > lock(m_mutex);
}
};
class Modem;
typedef Modem *(Modem::*ModemFactoryFunc)();
typedef std::map<std::string,ModemFactoryFunc *> ModemFactoryList;
class Modem {
public:
static void addModemFactory(std::string modemName, ModemFactoryFunc *factoryFunc);
static ModemFactoryList getFactories();
virtual Modem *factory();
virtual ModemKit *buildKit(long long sampleRate, int audioSampleRate);
virtual void disposeKit(ModemKit *kit);
virtual void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
static ModemFactoryList modemFactories;
};
+78
View File
@@ -0,0 +1,78 @@
#include "ModemAnalog.h"
ModemAnalog::ModemAnalog() : aOutputCeil(1), aOutputCeilMA(1), aOutputCeilMAA(1) {
}
ModemKit *ModemAnalog::buildKit(long long sampleRate, int audioSampleRate) {
ModemKitAnalog *akit = new ModemKitAnalog;
// stop-band attenuation [dB]
float As = 60.0f;
akit->sampleRate = sampleRate;
akit->audioSampleRate = audioSampleRate;
akit->audioResampleRatio = double(audioSampleRate) / double(sampleRate);
akit->audioResampler = msresamp_rrrf_create(akit->audioResampleRatio, As);
return akit;
}
void ModemAnalog::disposeKit(ModemKit *kit) {
ModemKitAnalog *akit = (ModemKitAnalog *)kit;
msresamp_rrrf_destroy(akit->audioResampler);
delete kit;
}
void ModemAnalog::initOutputBuffers(ModemKitAnalog *akit, ModemIQData *input) {
bufSize = input->data.size();
if (!bufSize) {
return;
}
double audio_resample_ratio = akit->audioResampleRatio;
int audio_out_size = ceil((double) (bufSize) * audio_resample_ratio) + 512;
if (demodOutputData.size() != bufSize) {
if (demodOutputData.capacity() < bufSize) {
demodOutputData.reserve(bufSize);
}
demodOutputData.resize(bufSize);
}
if (resampledOutputData.size() != audio_out_size) {
if (resampledOutputData.capacity() < audio_out_size) {
resampledOutputData.reserve(audio_out_size);
}
resampledOutputData.resize(audio_out_size);
}
}
void ModemAnalog::buildAudioOutput(ModemKitAnalog *akit, AudioThreadInput *audioOut, bool autoGain) {
unsigned int numAudioWritten;
if (autoGain) {
aOutputCeilMA = aOutputCeilMA + (aOutputCeil - aOutputCeilMA) * 0.025;
aOutputCeilMAA = aOutputCeilMAA + (aOutputCeilMA - aOutputCeilMAA) * 0.025;
aOutputCeil = 0;
for (int i = 0; i < bufSize; i++) {
if (demodOutputData[i] > aOutputCeil) {
aOutputCeil = demodOutputData[i];
}
}
float gain = 0.5 / aOutputCeilMAA;
for (int i = 0; i < bufSize; i++) {
demodOutputData[i] *= gain;
}
}
msresamp_rrrf_execute(akit->audioResampler, &demodOutputData[0], demodOutputData.size(), &resampledOutputData[0], &numAudioWritten);
audioOut->channels = 1;
audioOut->data.assign(resampledOutputData.begin(), resampledOutputData.begin() + numAudioWritten);
}
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "Modem.h"
class ModemKitAnalog : public ModemKit {
public:
ModemKitAnalog() : ModemKit(), audioResampler(nullptr), audioResampleRatio(0) {
};
msresamp_rrrf audioResampler;
double audioResampleRatio;
};
class ModemAnalog : public Modem {
public:
ModemAnalog();
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
void disposeKit(ModemKit *kit);
void initOutputBuffers(ModemKitAnalog *akit, ModemIQData *input);
void buildAudioOutput(ModemKitAnalog *akit, AudioThreadInput *audioOut, bool autoGain);
protected:
int bufSize;
std::vector<float> demodOutputData;
std::vector<float> resampledOutputData;
float aOutputCeil;
float aOutputCeilMA;
float aOutputCeilMAA;
};
+24
View File
@@ -0,0 +1,24 @@
#include "ModemAM.h"
ModemAM::ModemAM() {
demodAM = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0);
}
Modem *ModemAM::factory() {
return new ModemAM;
}
void ModemAM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitAnalog *amkit = (ModemKitAnalog *)kit;
initOutputBuffers(amkit,input);
if (!bufSize) {
input->decRefCount();
return;
}
ampmodem_demodulate_block(demodAM, &input->data[0], bufSize, &demodOutputData[0]);
buildAudioOutput(amkit,audioOut,true);
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "Modem.h"
#include "ModemAnalog.h"
class ModemAM : public ModemAnalog {
public:
ModemAM();
Modem *factory();
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
ampmodem demodAM;
};
+24
View File
@@ -0,0 +1,24 @@
#include "ModemDSB.h"
ModemDSB::ModemDSB() {
demodAM_DSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1);
}
Modem *ModemDSB::factory() {
return new ModemDSB;
}
void ModemDSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitAnalog *amkit = (ModemKitAnalog *)kit;
initOutputBuffers(amkit, input);
if (!bufSize) {
input->decRefCount();
return;
}
ampmodem_demodulate_block(demodAM_DSB, &input->data[0], bufSize, &demodOutputData[0]);
buildAudioOutput(amkit, audioOut, true);
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "Modem.h"
#include "ModemAnalog.h"
class ModemDSB : public ModemAnalog {
public:
ModemDSB();
Modem *factory();
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
ampmodem demodAM_DSB;
};
+24
View File
@@ -0,0 +1,24 @@
#include "ModemFM.h"
ModemFM::ModemFM() {
demodFM = freqdem_create(0.5);
}
Modem *ModemFM::factory() {
return new ModemFM;
}
void ModemFM::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitAnalog *fmkit = (ModemKitAnalog *)kit;
initOutputBuffers(fmkit, input);
if (!bufSize) {
input->decRefCount();
return;
}
freqdem_demodulate_block(demodFM, &input->data[0], bufSize, &demodOutputData[0]);
buildAudioOutput(fmkit, audioOut, false);
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include "Modem.h"
#include "ModemAnalog.h"
class ModemFM : public ModemAnalog {
public:
ModemFM();
Modem *factory();
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
freqdem demodFM;
};
+176
View File
@@ -0,0 +1,176 @@
#include "ModemFMStereo.h"
ModemFMStereo::ModemFMStereo() {
firStereoR2C = firhilbf_create(5, 60.0f);
firStereoC2R = firhilbf_create(5, 60.0f);
stereoPilot = nco_crcf_create(LIQUID_VCO);
nco_crcf_reset(stereoPilot);
nco_crcf_pll_set_bandwidth(stereoPilot, 0.25f);
}
ModemFMStereo::~ModemFMStereo() {
firhilbf_destroy(firStereoR2C);
firhilbf_destroy(firStereoC2R);
nco_crcf_destroy(stereoPilot);
}
Modem *ModemFMStereo::factory() {
return new ModemFMStereo;
}
ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) {
ModemKitFMStereo *kit = new ModemKitFMStereo;
kit->audioResampleRatio = double(audioSampleRate) / double(sampleRate);
float As = 60.0f; // stop-band attenuation [dB]
kit->audioResampler = msresamp_rrrf_create(kit->audioResampleRatio, As);
kit->stereoResampler = msresamp_rrrf_create(kit->audioResampleRatio, As);
// Stereo filters / shifters
double firStereoCutoff = 16000.0 / double(audioSampleRate);
// filter transition
float ft = 1000.0 / double(audioSampleRate);
// fractional timing offset
float mu = 0.0f;
if (firStereoCutoff < 0) {
firStereoCutoff = 0;
}
if (firStereoCutoff > 0.5) {
firStereoCutoff = 0.5;
}
unsigned int h_len = estimate_req_filter_len(ft, As);
float *h = new float[h_len];
liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);
kit->firStereoLeft = firfilt_rrrf_create(h, h_len);
kit->firStereoRight = firfilt_rrrf_create(h, h_len);
// stereo pilot filter
float bw = sampleRate;
if (bw < 100000.0) {
bw = 100000.0;
}
unsigned int order = 5; // filter order
float f0 = ((double) 19000 / bw);
float fc = ((double) 19500 / bw);
float Ap = 1.0f;
kit->iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As);
return kit;
}
void ModemFMStereo::disposeKit(ModemKit *kit) {
ModemKitFMStereo *fmkit = (ModemKitFMStereo *)kit;
msresamp_rrrf_destroy(fmkit->audioResampler);
msresamp_rrrf_destroy(fmkit->stereoResampler);
firfilt_rrrf_destroy(fmkit->firStereoLeft);
firfilt_rrrf_destroy(fmkit->firStereoRight);
}
void ModemFMStereo::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitFMStereo *fmkit = (ModemKitFMStereo *)kit;
int bufSize = input->data.size();
liquid_float_complex u, v, w, x, y;
double audio_resample_ratio = fmkit->audioResampleRatio;
if (demodOutputData.size() != bufSize) {
if (demodOutputData.capacity() < bufSize) {
demodOutputData.reserve(bufSize);
}
demodOutputData.resize(bufSize);
}
int audio_out_size = ceil((double) (bufSize) * audio_resample_ratio) + 512;
freqdem_demodulate_block(demodFM, &input->data[0], bufSize, &demodOutputData[0]);
if (resampledOutputData.size() != audio_out_size) {
if (resampledOutputData.capacity() < audio_out_size) {
resampledOutputData.reserve(audio_out_size);
}
resampledOutputData.resize(audio_out_size);
}
unsigned int numAudioWritten;
msresamp_rrrf_execute(fmkit->audioResampler, &demodOutputData[0], bufSize, &resampledOutputData[0], &numAudioWritten);
if (demodStereoData.size() != bufSize) {
if (demodStereoData.capacity() < bufSize) {
demodStereoData.reserve(bufSize);
}
demodStereoData.resize(bufSize);
}
float phase_error = 0;
for (int i = 0; i < bufSize; i++) {
// real -> complex
firhilbf_r2c_execute(firStereoR2C, demodOutputData[i], &x);
// 19khz pilot band-pass
iirfilt_crcf_execute(fmkit->iirStereoPilot, x, &v);
nco_crcf_cexpf(stereoPilot, &w);
w.imag = -w.imag; // conjf(w)
// multiply u = v * conjf(w)
u.real = v.real * w.real - v.imag * w.imag;
u.imag = v.real * w.imag + v.imag * w.real;
// cargf(u)
phase_error = atan2f(u.imag,u.real);
// step pll
nco_crcf_pll_step(stereoPilot, phase_error);
nco_crcf_step(stereoPilot);
// 38khz down-mix
nco_crcf_mix_down(stereoPilot, x, &y);
nco_crcf_mix_down(stereoPilot, y, &x);
// complex -> real
firhilbf_c2r_execute(firStereoC2R, x, &demodStereoData[i]);
}
// std::cout << "[PLL] phase error: " << phase_error;
// std::cout << " freq:" << (((nco_crcf_get_frequency(stereoPilot) / (2.0 * M_PI)) * inp->sampleRate)) << std::endl;
if (audio_out_size != resampledStereoData.size()) {
if (resampledStereoData.capacity() < audio_out_size) {
resampledStereoData.reserve(audio_out_size);
}
resampledStereoData.resize(audio_out_size);
}
msresamp_rrrf_execute(fmkit->stereoResampler, &demodStereoData[0], bufSize, &resampledStereoData[0], &numAudioWritten);
audioOut->channels = 2;
if (audioOut->data.capacity() < (numAudioWritten * 2)) {
audioOut->data.reserve(numAudioWritten * 2);
}
audioOut->data.resize(numAudioWritten * 2);
for (int i = 0; i < numAudioWritten; i++) {
float l, r;
firfilt_rrrf_push(fmkit->firStereoLeft, 0.568 * (resampledOutputData[i] - (resampledStereoData[i])));
firfilt_rrrf_execute(fmkit->firStereoLeft, &l);
firfilt_rrrf_push(fmkit->firStereoRight, 0.568 * (resampledOutputData[i] + (resampledStereoData[i])));
firfilt_rrrf_execute(fmkit->firStereoRight, &r);
audioOut->data[i * 2] = l;
audioOut->data[i * 2 + 1] = r;
}
}
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include "Modem.h"
class ModemKitFMStereo: public ModemKit {
public:
ModemKitFMStereo() : audioResampler(nullptr), stereoResampler(nullptr), audioResampleRatio(0), firStereoLeft(nullptr), firStereoRight(nullptr), iirStereoPilot(nullptr) {
}
msresamp_rrrf audioResampler;
msresamp_rrrf stereoResampler;
double audioResampleRatio;
firfilt_rrrf firStereoLeft;
firfilt_rrrf firStereoRight;
iirfilt_crcf iirStereoPilot;
};
class ModemFMStereo : public Modem {
public:
ModemFMStereo();
~ModemFMStereo();
Modem *factory();
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
void disposeKit(ModemKit *kit);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
std::vector<float> demodOutputData;
std::vector<float> demodStereoData;
std::vector<float> resampledOutputData;
std::vector<float> resampledStereoData;
freqdem demodFM;
firhilbf firStereoR2C;
firhilbf firStereoC2R;
nco_crcf stereoPilot;
};
+38
View File
@@ -0,0 +1,38 @@
#include "ModemIQ.h"
ModemIQ::ModemIQ() {
}
Modem *ModemIQ::factory() {
return new ModemIQ;
}
ModemKit *ModemIQ::buildKit(long long sampleRate, int audioSampleRate) {
ModemKit *kit = new ModemKit;
return kit;
}
void ModemIQ::disposeKit(ModemKit *kit) {
delete kit;
}
void ModemIQ::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
int bufSize = input->data.size();
if (!bufSize) {
input->decRefCount();
return;
}
audioOut->channels = 2;
if (audioOut->data.capacity() < (bufSize * 2)) {
audioOut->data.reserve(bufSize * 2);
}
audioOut->data.resize(bufSize * 2);
for (int i = 0; i < bufSize; i++) {
audioOut->data[i * 2] = input->data[i].imag;
audioOut->data[i * 2 + 1] = input->data[i].real;
}
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include "Modem.h"
class ModemIQ : public Modem {
public:
ModemIQ();
Modem *factory();
ModemKit *buildKit(long long sampleRate, int audioSampleRate);
void disposeKit(ModemKit *kit);
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
};
+35
View File
@@ -0,0 +1,35 @@
#include "ModemLSB.h"
ModemLSB::ModemLSB() {
// half band filter used for side-band elimination
ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f);
demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1);
}
Modem *ModemLSB::factory() {
return new ModemLSB;
}
ModemLSB::~ModemLSB() {
resamp2_crcf_destroy(ssbFilt);
ampmodem_destroy(demodAM_LSB);
}
void ModemLSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitAnalog *akit = (ModemKitAnalog *)kit;
initOutputBuffers(akit,input);
if (!bufSize) {
input->decRefCount();
return;
}
liquid_float_complex x, y;
for (int i = 0; i < bufSize; i++) { // Reject upper band
resamp2_crcf_filter_execute(ssbFilt,input->data[i],&x,&y);
ampmodem_demodulate(demodAM_LSB, x, &demodOutputData[i]);
}
buildAudioOutput(akit, audioOut, true);
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include "Modem.h"
#include "ModemAnalog.h"
class ModemLSB : public ModemAnalog {
public:
ModemLSB();
~ModemLSB();
Modem *factory();
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
resamp2_crcf ssbFilt;
ampmodem demodAM_LSB;
};
+36
View File
@@ -0,0 +1,36 @@
#include "ModemUSB.h"
ModemUSB::ModemUSB() {
// half band filter used for side-band elimination
ssbFilt = resamp2_crcf_create(12,-0.25f,60.0f);
demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1);
}
Modem *ModemUSB::factory() {
return new ModemUSB;
}
ModemUSB::~ModemUSB() {
resamp2_crcf_destroy(ssbFilt);
ampmodem_destroy(demodAM_USB);
}
void ModemUSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) {
ModemKitAnalog *akit = (ModemKitAnalog *)kit;
initOutputBuffers(akit,input);
if (!bufSize) {
input->decRefCount();
return;
}
liquid_float_complex x, y;
for (int i = 0; i < bufSize; i++) { // Reject lower band
resamp2_crcf_filter_execute(ssbFilt,input->data[i],&x,&y);
ampmodem_demodulate(demodAM_USB, y, &demodOutputData[i]);
}
buildAudioOutput(akit, audioOut, true);
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include "ModemAnalog.h"
class ModemUSB : public ModemAnalog {
public:
ModemUSB();
~ModemUSB();
Modem *factory();
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
resamp2_crcf ssbFilt;
ampmodem demodAM_USB;
};
+1
View File
@@ -0,0 +1 @@
#include "ModemAPSK.h"
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"
+1
View File
@@ -0,0 +1 @@
#include "ModemASK.h"
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"
+1
View File
@@ -0,0 +1 @@
#include "ModemBPSK.h"
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"
+1
View File
@@ -0,0 +1 @@
#include "ModemDPSK.h"
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"
+1
View File
@@ -0,0 +1 @@
#include "ModemOOK.h"
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"
+1
View File
@@ -0,0 +1 @@
#include "ModemPSK.h"
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"
+1
View File
@@ -0,0 +1 @@
#include "ModemQAM.h"
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"
+1
View File
@@ -0,0 +1 @@
#include "ModemQPSK.h"
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"
+1
View File
@@ -0,0 +1 @@
#include "ModemSQAM.h"
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "Modem.h"
+2
View File
@@ -0,0 +1,2 @@
#include "ModemST.h"
+2
View File
@@ -0,0 +1,2 @@
#pragma once
#include "Modem.h"