Added squelch to radio

This commit is contained in:
Ryzerth 2020-12-10 05:18:40 +01:00
parent 2c729bf646
commit 774663d70d
15 changed files with 322 additions and 50 deletions

View File

@ -70,10 +70,50 @@ int sdrpp_main() {
spdlog::info("SDR++ v" VERSION_STR);
// ======== DEFAULT CONFIG ========
json defConfig;
defConfig["bandColors"]["amateur"] = "#FF0000FF";
defConfig["bandColors"]["aviation"] = "#00FF00FF";
defConfig["bandColors"]["broadcast"] = "#0000FFFF";
defConfig["bandColors"]["marine"] = "#00FFFFFF";
defConfig["bandColors"]["military"] = "#FFFF00FF";
defConfig["bandPlan"] = "General";
defConfig["bandPlanEnabled"] = true;
defConfig["centerTuning"] = true;
defConfig["fftHeight"] = 300;
defConfig["frequency"] = 100000000.0;
defConfig["max"] = 0.0;
defConfig["maximized"] = false;
defConfig["menuOrder"] = {
"Source",
"Radio",
"Recorder",
"Sinks",
"Audio",
"Scripting",
"Band Plan",
"Display"
};
defConfig["menuWidth"] = 300;
defConfig["min"] = -70.0;
defConfig["moduleInstances"]["Audio Sink"] = "audio_sink";
defConfig["moduleInstances"]["PlutoSDR Source"] = "plutosdr_source";
defConfig["moduleInstances"]["RTL-TCP Source"] = "rtl_tcp_source";
defConfig["moduleInstances"]["Radio"] = "radio";
defConfig["moduleInstances"]["Recorder"] = "recorder";
defConfig["moduleInstances"]["SoapySDR Source"] = "soapy_source";
defConfig["modules"] = json::array();
defConfig["offset"] = 0.0;
defConfig["showWaterfall"] = true;
defConfig["source"] = "";
defConfig["streams"] = json::object();
defConfig["windowSize"]["h"] = 720;
defConfig["windowSize"]["w"] = 1280;
// Load config
spdlog::info("Loading config");
core::configManager.setPath(ROOT_DIR "/config.json");
core::configManager.load(json());
core::configManager.load(defConfig);
core::configManager.enableAutoSave();
// Setup window

View File

@ -219,4 +219,73 @@ namespace dsp {
stream<T>* _in;
};
class Squelch : public generic_block<Squelch> {
public:
Squelch() {}
Squelch(stream<complex_t>* in, float level) { init(in, level); }
~Squelch() {
generic_block<Squelch>::stop();
delete[] normBuffer;
}
void init(stream<complex_t>* in, float level) {
_in = in;
_level = level;
normBuffer = new float[STREAM_BUFFER_SIZE];
generic_block<Squelch>::registerInput(_in);
generic_block<Squelch>::registerOutput(&out);
}
void setInput(stream<complex_t>* in) {
std::lock_guard<std::mutex> lck(generic_block<Squelch>::ctrlMtx);
generic_block<Squelch>::tempStop();
generic_block<Squelch>::unregisterInput(_in);
_in = in;
generic_block<Squelch>::registerInput(_in);
generic_block<Squelch>::tempStart();
}
void setLevel(float level) {
_level = level;
}
float getLevel() {
return _level;
}
int run() {
count = _in->read();
if (count < 0) { return -1; }
if (out.aquire() < 0) { return -1; }
float sum = 0.0f;
volk_32fc_magnitude_32f(normBuffer, (lv_32fc_t*)_in->data, count);
volk_32f_accumulator_s32f(&sum, normBuffer, count);
sum /= (float)count;
if (10.0f * log10f(sum) >= _level) {
memcpy(out.data, _in->data, count * sizeof(complex_t));
}
else {
memset(out.data, 0, count * sizeof(complex_t));
}
_in->flush();
out.write(count);
return count;
}
stream<complex_t> out;
private:
int count;
float* normBuffer;
float _level = -50.0f;
stream<complex_t>* _in;
};
}

View File

@ -35,7 +35,6 @@ std::thread worker;
std::mutex fft_mtx;
fftwf_complex *fft_in, *fft_out;
fftwf_plan p;
float* tempData;
char buf[1024];
int fftSize = 8192 * 8;
@ -83,6 +82,7 @@ int fftHeight = 300;
bool showMenu = true;
bool centerTuning = false;
dsp::stream<dsp::complex_t> dummyStream;
bool demoWindow = false;
void windowInit() {
LoadingScreen::show("Initializing UI");
@ -234,7 +234,7 @@ void setVFO(double freq) {
gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0));
gui::waterfall.setCenterFrequency(freq);
gui::waterfall.setViewOffset(0);
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, 0);
sigpath::vfoManager.setOffset(gui::waterfall.selectedVFO, 0);
sigpath::sourceManager.tune(freq);
return;
}
@ -500,6 +500,7 @@ void drawWindow() {
if (ImGui::Checkbox("Test technique", &dcbias.val)) {
//sigpath::signalPath.setDCBiasCorrection(dcbias.val);
}
ImGui::Checkbox("Show demo window", &demoWindow);
ImGui::Spacing();
}
@ -575,6 +576,10 @@ void drawWindow() {
if (showCredits) {
credits::show();
}
if (demoWindow) {
ImGui::ShowDemoWindow();
}
}
void setViewBandwidthSlider(float bandwidth) {

View File

@ -25,8 +25,8 @@ public:
_config->aquire();
if(_config->conf.contains(prefix)) {
if(!_config->conf[prefix].contains("AM")) {
_config->conf[prefix]["AM"]["bandwidth"] = bw;
_config->conf[prefix]["AM"]["snapInterval"] = snapInterval;
if (!_config->conf[prefix]["AM"].contains("bandwidth")) { _config->conf[prefix]["AM"]["bandwidth"] = bw; }
if (!_config->conf[prefix]["AM"].contains("snapInterval")) { _config->conf[prefix]["AM"]["snapInterval"] = snapInterval; }
}
json conf = _config->conf[prefix]["AM"];
bw = conf["bandwidth"];
@ -37,8 +37,10 @@ public:
_config->conf[prefix]["AM"]["snapInterval"] = snapInterval;
}
_config->release(true);
squelch.init(_vfo->output, squelchLevel);
demod.init(_vfo->output);
demod.init(&squelch.out);
agc.init(&demod.out, 1.0f / 125.0f);
@ -52,6 +54,7 @@ public:
}
void start() {
squelch.start();
demod.start();
agc.start();
resamp.start();
@ -60,6 +63,7 @@ public:
}
void stop() {
squelch.stop();
demod.stop();
agc.stop();
resamp.stop();
@ -79,7 +83,7 @@ public:
void setVFO(VFOManager::VFO* vfo) {
_vfo = vfo;
demod.setInput(_vfo->output);
squelch.setInput(_vfo->output);
}
VFOManager::VFO* getVFO() {
@ -131,6 +135,16 @@ public:
_config->conf[uiPrefix]["AM"]["snapInterval"] = snapInterval;
_config->release(true);
}
ImGui::Text("Squelch");
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_am_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel);
_config->aquire();
_config->conf[uiPrefix]["AM"]["squelchLevel"] = squelchLevel;
_config->release(true);
}
}
private:
@ -153,8 +167,10 @@ private:
float audioSampRate = 48000;
float bw = 12500;
bool running = false;
float squelchLevel = -100.0f;
VFOManager::VFO* _vfo;
dsp::Squelch squelch;
dsp::AMDemod demod;
dsp::AGC agc;
dsp::filter_window::BlackmanWindow win;

View File

@ -28,8 +28,8 @@ public:
_config->aquire();
if(_config->conf.contains(prefix)) {
if(!_config->conf[prefix].contains("CW")) {
_config->conf[prefix]["CW"]["bandwidth"] = bw;
_config->conf[prefix]["CW"]["snapInterval"] = snapInterval;
if (!_config->conf[prefix]["CW"].contains("bandwidth")) { _config->conf[prefix]["CW"]["bandwidth"] = bw; }
if (!_config->conf[prefix]["CW"].contains("snapInterval")) { _config->conf[prefix]["CW"]["snapInterval"] = snapInterval; }
}
json conf = _config->conf[prefix]["CW"];
bw = conf["bandwidth"];
@ -40,10 +40,12 @@ public:
_config->conf[prefix]["CW"]["snapInterval"] = snapInterval;
}
_config->release(true);
squelch.init(_vfo->output, squelchLevel);
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
win.init(audioBW, audioBW, bbSampRate);
resamp.init(vfo->output, &win, bbSampRate, audioSampRate);
resamp.init(&squelch.out, &win, bbSampRate, audioSampRate);
win.setSampleRate(bbSampRate * resamp.getInterpolation());
resamp.updateWindow(&win);
@ -57,6 +59,7 @@ public:
}
void start() {
squelch.start();
resamp.start();
xlator.start();
c2r.start();
@ -66,6 +69,7 @@ public:
}
void stop() {
squelch.stop();
resamp.stop();
xlator.stop();
c2r.stop();
@ -86,7 +90,7 @@ public:
void setVFO(VFOManager::VFO* vfo) {
_vfo = vfo;
resamp.setInput(_vfo->output);
squelch.setInput(_vfo->output);
}
VFOManager::VFO* getVFO() {
@ -141,6 +145,16 @@ public:
_config->conf[uiPrefix]["CW"]["snapInterval"] = snapInterval;
_config->release(true);
}
ImGui::Text("Squelch");
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_cw_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel);
_config->aquire();
_config->conf[uiPrefix]["CW"]["squelchLevel"] = squelchLevel;
_config->release(true);
}
}
private:
@ -163,8 +177,10 @@ private:
float audioSampRate = 48000;
float bw = 200;
bool running = false;
float squelchLevel = -100.0f;
VFOManager::VFO* _vfo;
dsp::Squelch squelch;
dsp::filter_window::BlackmanWindow win;
dsp::PolyphaseResampler<dsp::complex_t> resamp;
dsp::FrequencyXlator<dsp::complex_t> xlator;

View File

@ -25,8 +25,8 @@ public:
_config->aquire();
if(_config->conf.contains(prefix)) {
if(!_config->conf[prefix].contains("DSB")) {
_config->conf[prefix]["DSB"]["bandwidth"] = bw;
_config->conf[prefix]["DSB"]["snapInterval"] = snapInterval;
if (!_config->conf[prefix]["DSB"].contains("bandwidth")) { _config->conf[prefix]["DSB"]["bandwidth"] = bw; }
if (!_config->conf[prefix]["DSB"].contains("snapInterval")) { _config->conf[prefix]["DSB"]["snapInterval"] = snapInterval; }
}
json conf = _config->conf[prefix]["DSB"];
bw = conf["bandwidth"];
@ -37,8 +37,10 @@ public:
_config->conf[prefix]["DSB"]["snapInterval"] = snapInterval;
}
_config->release(true);
squelch.init(_vfo->output, squelchLevel);
demod.init(_vfo->output, bbSampRate, bandWidth, dsp::SSBDemod::MODE_DSB);
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_DSB);
agc.init(&demod.out, 1.0f / 125.0f);
@ -52,6 +54,7 @@ public:
}
void start() {
squelch.start();
demod.start();
agc.start();
resamp.start();
@ -60,6 +63,7 @@ public:
}
void stop() {
squelch.stop();
demod.stop();
agc.stop();
resamp.stop();
@ -79,7 +83,7 @@ public:
void setVFO(VFOManager::VFO* vfo) {
_vfo = vfo;
demod.setInput(_vfo->output);
squelch.setInput(_vfo->output);
}
VFOManager::VFO* getVFO() {
@ -131,6 +135,16 @@ public:
_config->conf[uiPrefix]["DSB"]["snapInterval"] = snapInterval;
_config->release(true);
}
ImGui::Text("Squelch");
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_dsb_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel);
_config->aquire();
_config->conf[uiPrefix]["DSB"]["squelchLevel"] = squelchLevel;
_config->release(true);
}
}
private:
@ -153,8 +167,10 @@ private:
float audioSampRate = 48000;
float bw = 6000;
bool running = false;
float squelchLevel = -100.0f;
VFOManager::VFO* _vfo;
dsp::Squelch squelch;
dsp::SSBDemod demod;
dsp::AGC agc;
dsp::filter_window::BlackmanWindow win;

View File

@ -25,8 +25,8 @@ public:
_config->aquire();
if(_config->conf.contains(prefix)) {
if(!_config->conf[prefix].contains("FM")) {
_config->conf[prefix]["FM"]["bandwidth"] = bw;
_config->conf[prefix]["FM"]["snapInterval"] = snapInterval;
if (!_config->conf[prefix]["FM"].contains("bandwidth")) { _config->conf[prefix]["FM"]["bandwidth"] = bw; }
if (!_config->conf[prefix]["FM"].contains("snapInterval")) { _config->conf[prefix]["FM"]["snapInterval"] = snapInterval; }
}
json conf = _config->conf[prefix]["FM"];
bw = conf["bandwidth"];
@ -37,8 +37,10 @@ public:
_config->conf[prefix]["FM"]["snapInterval"] = snapInterval;
}
_config->release(true);
squelch.init(_vfo->output, squelchLevel);
demod.init(_vfo->output, bbSampRate, bandWidth / 2.0f);
demod.init(&squelch.out, bbSampRate, bandWidth / 2.0f);
float audioBW = std::min<float>(audioSampleRate / 2.0f, bw / 2.0f);
win.init(audioBW, audioBW, bbSampRate);
@ -50,6 +52,7 @@ public:
}
void start() {
squelch.start();
demod.start();
resamp.start();
m2s.start();
@ -57,6 +60,7 @@ public:
}
void stop() {
squelch.stop();
demod.stop();
resamp.stop();
m2s.stop();
@ -75,7 +79,7 @@ public:
void setVFO(VFOManager::VFO* vfo) {
_vfo = vfo;
demod.setInput(_vfo->output);
squelch.setInput(_vfo->output);
}
VFOManager::VFO* getVFO() {
@ -127,6 +131,16 @@ public:
_config->conf[uiPrefix]["FM"]["snapInterval"] = snapInterval;
_config->release(true);
}
ImGui::Text("Squelch");
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_fm_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel);
_config->aquire();
_config->conf[uiPrefix]["FM"]["squelchLevel"] = squelchLevel;
_config->release(true);
}
}
private:
@ -150,8 +164,10 @@ private:
float audioSampRate = 48000;
float bw = 12500;
bool running = false;
float squelchLevel = -100.0f;
VFOManager::VFO* _vfo;
dsp::Squelch squelch;
dsp::FMDemod demod;
dsp::filter_window::BlackmanWindow win;
dsp::PolyphaseResampler<float> resamp;

View File

@ -25,8 +25,8 @@ public:
_config->aquire();
if(_config->conf.contains(prefix)) {
if(!_config->conf[prefix].contains("LSB")) {
_config->conf[prefix]["LSB"]["bandwidth"] = bw;
_config->conf[prefix]["LSB"]["snapInterval"] = snapInterval;
if (!_config->conf[prefix]["LSB"].contains("bandwidth")) { _config->conf[prefix]["LSB"]["bandwidth"] = bw; }
if (!_config->conf[prefix]["LSB"].contains("snapInterval")) { _config->conf[prefix]["LSB"]["snapInterval"] = snapInterval; }
}
json conf = _config->conf[prefix]["LSB"];
bw = conf["bandwidth"];
@ -37,8 +37,10 @@ public:
_config->conf[prefix]["LSB"]["snapInterval"] = snapInterval;
}
_config->release(true);
squelch.init(_vfo->output, squelchLevel);
demod.init(_vfo->output, bbSampRate, bandWidth, dsp::SSBDemod::MODE_LSB);
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_LSB);
agc.init(&demod.out, 1.0f / 125.0f);
@ -52,6 +54,7 @@ public:
}
void start() {
squelch.start();
demod.start();
agc.start();
resamp.start();
@ -60,6 +63,7 @@ public:
}
void stop() {
squelch.stop();
demod.stop();
agc.stop();
resamp.stop();
@ -79,7 +83,7 @@ public:
void setVFO(VFOManager::VFO* vfo) {
_vfo = vfo;
demod.setInput(_vfo->output);
squelch.setInput(_vfo->output);
}
VFOManager::VFO* getVFO() {
@ -131,6 +135,16 @@ public:
_config->conf[uiPrefix]["LSB"]["snapInterval"] = snapInterval;
_config->release(true);
}
ImGui::Text("Squelch");
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_lsb_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel);
_config->aquire();
_config->conf[uiPrefix]["LSB"]["squelchLevel"] = squelchLevel;
_config->release(true);
}
}
private:
@ -153,8 +167,10 @@ private:
float audioSampRate = 48000;
float bw = 3000;
bool running = false;
float squelchLevel = -100.0f;
VFOManager::VFO* _vfo;
dsp::Squelch squelch;
dsp::SSBDemod demod;
dsp::AGC agc;
dsp::filter_window::BlackmanWindow win;

View File

@ -25,7 +25,7 @@ public:
_config->aquire();
if(_config->conf.contains(prefix)) {
if(!_config->conf[prefix].contains("RAW")) {
_config->conf[prefix]["RAW"]["snapInterval"] = snapInterval;
if (!_config->conf[prefix]["RAW"].contains("snapInterval")) { _config->conf[prefix]["RAW"]["snapInterval"] = snapInterval; }
}
json conf = _config->conf[prefix]["RAW"];
snapInterval = conf["snapInterval"];
@ -34,16 +34,20 @@ public:
_config->conf[prefix]["RAW"]["snapInterval"] = snapInterval;
}
_config->release(true);
squelch.init(_vfo->output, squelchLevel);
c2s.init(_vfo->output);
c2s.init(&squelch.out);
}
void start() {
squelch.start();
c2s.start();
running = true;
}
void stop() {
squelch.stop();
c2s.stop();
running = false;
}
@ -60,7 +64,7 @@ public:
void setVFO(VFOManager::VFO* vfo) {
_vfo = vfo;
c2s.setInput(_vfo->output);
squelch.setInput(_vfo->output);
}
VFOManager::VFO* getVFO() {
@ -95,6 +99,16 @@ public:
_config->release(true);
}
ImGui::Text("Squelch");
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_raw_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel);
_config->aquire();
_config->conf[uiPrefix]["RAW"]["squelchLevel"] = squelchLevel;
_config->release(true);
}
// TODO: Allow selection of the bandwidth
}
@ -109,8 +123,10 @@ private:
float audioSampRate = 48000;
float bw = 12500;
bool running = false;
float squelchLevel = -100.0f;
VFOManager::VFO* _vfo;
dsp::Squelch squelch;
dsp::ComplexToStereo c2s;
ConfigManager* _config;

View File

@ -25,8 +25,8 @@ public:
_config->aquire();
if(_config->conf.contains(prefix)) {
if(!_config->conf[prefix].contains("USB")) {
_config->conf[prefix]["USB"]["bandwidth"] = bw;
_config->conf[prefix]["USB"]["snapInterval"] = snapInterval;
if (!_config->conf[prefix]["USB"].contains("bandwidth")) { _config->conf[prefix]["USB"]["bandwidth"] = bw; }
if (!_config->conf[prefix]["USB"].contains("snapInterval")) { _config->conf[prefix]["USB"]["snapInterval"] = snapInterval; }
}
json conf = _config->conf[prefix]["USB"];
bw = conf["bandwidth"];
@ -37,8 +37,10 @@ public:
_config->conf[prefix]["USB"]["snapInterval"] = snapInterval;
}
_config->release(true);
squelch.init(_vfo->output, squelchLevel);
demod.init(_vfo->output, bbSampRate, bandWidth, dsp::SSBDemod::MODE_USB);
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_USB);
agc.init(&demod.out, 1.0f / 125.0f);
@ -52,6 +54,7 @@ public:
}
void start() {
squelch.start();
demod.start();
agc.start();
resamp.start();
@ -60,6 +63,7 @@ public:
}
void stop() {
squelch.stop();
demod.stop();
agc.stop();
resamp.stop();
@ -79,7 +83,7 @@ public:
void setVFO(VFOManager::VFO* vfo) {
_vfo = vfo;
demod.setInput(_vfo->output);
squelch.setInput(_vfo->output);
}
VFOManager::VFO* getVFO() {
@ -131,6 +135,16 @@ public:
_config->conf[uiPrefix]["USB"]["snapInterval"] = snapInterval;
_config->release(true);
}
ImGui::Text("Squelch");
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_usb_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel);
_config->aquire();
_config->conf[uiPrefix]["USB"]["squelchLevel"] = squelchLevel;
_config->release(true);
}
}
private:
@ -153,8 +167,10 @@ private:
float audioSampRate = 48000;
float bw = 3000;
bool running = false;
float squelchLevel = -100.0f;
VFOManager::VFO* _vfo;
dsp::Squelch squelch;
dsp::SSBDemod demod;
dsp::AGC agc;
dsp::filter_window::BlackmanWindow win;

View File

@ -25,24 +25,28 @@ public:
_config->aquire();
if(_config->conf.contains(prefix)) {
if(!_config->conf[prefix].contains("WFM")) {
_config->conf[prefix]["WFM"]["bandwidth"] = bw;
_config->conf[prefix]["WFM"]["snapInterval"] = snapInterval;
_config->conf[prefix]["WFM"]["deempMode"] = deempId;
if (!_config->conf[prefix]["WFM"].contains("bandwidth")) { _config->conf[prefix]["WFM"]["bandwidth"] = bw; }
if (!_config->conf[prefix]["WFM"].contains("snapInterval")) { _config->conf[prefix]["WFM"]["snapInterval"] = snapInterval; }
if (!_config->conf[prefix]["WFM"].contains("deempMode")) { _config->conf[prefix]["WFM"]["deempMode"] = deempId; }
if (!_config->conf[prefix]["WFM"].contains("squelchLevel")) { _config->conf[prefix]["WFM"]["squelchLevel"] = squelchLevel; }
}
json conf = _config->conf[prefix]["WFM"];
bw = conf["bandwidth"];
snapInterval = conf["snapInterval"];
deempId = conf["deempMode"];
squelchLevel = conf["squelchLevel"];
}
else {
_config->conf[prefix]["WFM"]["bandwidth"] = bw;
_config->conf[prefix]["WFM"]["snapInterval"] = snapInterval;
_config->conf[prefix]["WFM"]["deempMode"] = deempId;
_config->conf[prefix]["WFM"]["squelchLevel"] = squelchLevel;
}
_config->release(true);
squelch.init(_vfo->output, squelchLevel);
demod.init(_vfo->output, bbSampRate, bandWidth / 2.0f);
demod.init(&squelch.out, bbSampRate, bandWidth / 2.0f);
float audioBW = std::min<float>(audioSampleRate / 2.0f, 16000.0f);
win.init(audioBW, audioBW, bbSampRate);
@ -56,6 +60,7 @@ public:
}
void start() {
squelch.start();
demod.start();
resamp.start();
deemp.start();
@ -64,6 +69,7 @@ public:
}
void stop() {
squelch.stop();
demod.stop();
resamp.stop();
deemp.stop();
@ -83,7 +89,7 @@ public:
void setVFO(VFOManager::VFO* vfo) {
_vfo = vfo;
demod.setInput(_vfo->output);
squelch.setInput(_vfo->output);
}
VFOManager::VFO* getVFO() {
@ -149,6 +155,16 @@ public:
_config->conf[uiPrefix]["WFM"]["deempMode"] = deempId;
_config->release(true);
}
ImGui::Text("Squelch");
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_wfm_deemp_" + uiPrefix).c_str(), &squelchLevel, -100.0f, 0.0f, "%.3fdB")) {
squelch.setLevel(squelchLevel);
_config->aquire();
_config->conf[uiPrefix]["WFM"]["squelchLevel"] = squelchLevel;
_config->release(true);
}
}
private:
@ -181,12 +197,14 @@ private:
std::string uiPrefix;
float snapInterval = 100000;
float audioSampRate = 48000;
float squelchLevel = -100.0f;
float bw = 200000;
int deempId = 0;
float tau = 50e-6;
bool running = false;
VFOManager::VFO* _vfo;
dsp::Squelch squelch;
dsp::FMDemod demod;
dsp::filter_window::BlackmanWindow win;
dsp::PolyphaseResampler<float> resamp;

View File

@ -3,7 +3,7 @@
"bandPlanEnabled": true,
"centerTuning": false,
"fftHeight": 300,
"frequency": 99716000,
"frequency": 103600000,
"max": 0.0,
"maximized": false,
"menuOrder": [
@ -17,7 +17,7 @@
"Display"
],
"menuWidth": 300,
"min": -65.44117736816406,
"min": -66.17647552490234,
"moduleInstances": {
"Audio Sink": "audio_sink",
"PlutoSDR Source": "plutosdr_source",
@ -27,12 +27,12 @@
"SoapySDR Source": "soapy_source"
},
"modules": [
"./radio/Release/radio.dll",
"./recorder/Release/recorder.dll",
"./soapy_source/Release/soapy_source.dll",
"./rtl_tcp_source/Release/rtl_tcp_source.dll",
"./audio_sink/Release/audio_sink.dll",
"./plutosdr_source/Release/plutosdr_source.dll"
"./radio/RelWithDebInfo/radio.dll",
"./recorder/RelWithDebInfo/recorder.dll",
"./soapy_source/RelWithDebInfo/soapy_source.dll",
"./rtl_tcp_source/RelWithDebInfo/rtl_tcp_source.dll",
"./audio_sink/RelWithDebInfo/audio_sink.dll",
"./plutosdr_source/RelWithDebInfo/plutosdr_source.dll"
],
"offset": 0.0,
"showWaterfall": true,
@ -41,7 +41,7 @@
"Radio": {
"muted": false,
"sink": "Audio",
"volume": 0.4285714328289032
"volume": 0.6785714030265808
},
"Radio 1": {
"muted": false,

View File

@ -2,11 +2,13 @@
"Radio": {
"AM": {
"bandwidth": 12500.0,
"snapInterval": 1000.0
"snapInterval": 1000.0,
"squelchLevel": -100.0
},
"CW": {
"bandwidth": 200.0,
"snapInterval": 10.0
"snapInterval": 10.0,
"squelchLevel": -100.0
},
"DSB": {
"bandwidth": 6000.0,
@ -30,7 +32,8 @@
"WFM": {
"bandwidth": 200000.0,
"deempMode": 0,
"snapInterval": 100000.0
"snapInterval": 100000.0,
"squelchLevel": -100.0
},
"selectedDemodId": 1
}

View File

@ -1,17 +1,18 @@
{
"device": "HackRF One #0 901868dc282c8f8b",
"device": "AirSpy HF+ [c852435de0224af7]",
"devices": {
"": {
"agc": false,
"gains": {
"PGA": 0.0
},
"sampleRate": 8000000.0
"sampleRate": 4000000.0
},
"AirSpy HF+ [c852435de0224af7]": {
"agc": false,
"gains": {
"LNA": 6.0,
"RF": 0.0
"RF": -48.0
},
"sampleRate": 768000.0
},

View File

@ -143,6 +143,8 @@ private:
hasAgc = dev->hasGainMode(SOAPY_SDR_RX, channelId);
hasIQBalance = dev->hasIQBalanceMode(SOAPY_SDR_RX, channelId);
SoapySDR::Device::unmake(dev);
config.aquire();
@ -163,6 +165,12 @@ private:
else {
agc = false;
}
if (hasIQBalance && config.conf["devices"][name].contains("iqBalance")) {
iqBalance = config.conf["devices"][name]["iqBalance"];
}
else {
iqBalance = false;
}
if (config.conf["devices"][name].contains("sampleRate")) {
selectSampleRate(config.conf["devices"][name]["sampleRate"]);
}
@ -196,6 +204,9 @@ private:
if (hasAgc) {
conf["agc"] = agc;
}
if (hasIQBalance) {
conf["iqBalance"] = iqBalance;
}
config.aquire();
config.conf["devices"][devArgs["label"]] = conf;
config.release(true);
@ -231,6 +242,10 @@ private:
_this->dev->setGainMode(SOAPY_SDR_RX, _this->channelId, _this->agc);
}
if (_this->hasIQBalance) {
_this->dev->setIQBalanceMode(SOAPY_SDR_RX, _this->channelId, _this->iqBalance);
}
_this->dev->setFrequency(SOAPY_SDR_RX, _this->channelId, _this->freq);
_this->devStream = _this->dev->setupStream(SOAPY_SDR_RX, "CF32");
@ -322,6 +337,13 @@ private:
}
}
if (_this->hasIQBalance) {
if (ImGui::Checkbox((std::string("AGC##_iq_bal_sel_") + _this->name).c_str(), &_this->iqBalance)) {
if (_this->running) { _this->dev->setIQBalanceMode(SOAPY_SDR_RX, _this->channelId, _this->iqBalance); }
_this->saveCurrent();
}
}
int i = 0;
for (auto gain : _this->gainList) {
ImGui::Text("%s gain", gain.c_str());
@ -371,6 +393,8 @@ private:
bool running = false;
bool hasAgc = false;
bool agc = false;
bool hasIQBalance = false;
bool iqBalance = false;
std::vector<double> sampleRates;
int srId = -1;
float* uiGains;