mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 01:55:48 -05:00
AM demod: synchronous AM: implemented sidebands selection
This commit is contained in:
parent
e9f64a05f2
commit
21840c5dd3
4
debian/changelog
vendored
4
debian/changelog
vendored
@ -1,8 +1,10 @@
|
||||
sdrangel (3.14.7-1) unstable; urgency=medium
|
||||
|
||||
* ChanelAnalyzerNG: added PLL option
|
||||
* RTL-SDR: fixed inf/sup decimators
|
||||
* AM demod: syncrhronous AM detection option
|
||||
|
||||
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Sun, 13 May 2018 20:14:18 +0200
|
||||
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Sun, 20 May 2018 20:14:18 +0200
|
||||
|
||||
sdrangel (3.14.6-1) unstable; urgency=medium
|
||||
|
||||
|
@ -35,7 +35,6 @@ const QString ChannelAnalyzerNG::m_channelId = "ChannelAnalyzerNG";
|
||||
ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) :
|
||||
ChannelSinkAPI(m_channelIdURI),
|
||||
m_deviceAPI(deviceAPI),
|
||||
m_pll(0,0.05,0.01),
|
||||
m_sampleSink(0),
|
||||
m_settingsMutex(QMutex::Recursive)
|
||||
{
|
||||
@ -50,6 +49,7 @@ ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) :
|
||||
m_interpolatorDistanceRemain = 0.0f;
|
||||
SSBFilter = new fftfilt(m_config.m_LowCutoff / m_config.m_inputSampleRate, m_config.m_Bandwidth / m_config.m_inputSampleRate, ssbFftLen);
|
||||
DSBFilter = new fftfilt(m_config.m_Bandwidth / m_config.m_inputSampleRate, 2*ssbFftLen);
|
||||
m_pll.computeCoefficients(0.05f, 0.707f, 1000.0f); // bandwidth, damping factor, loop gain
|
||||
|
||||
apply(true);
|
||||
|
||||
@ -249,6 +249,13 @@ void ChannelAnalyzerNG::apply(bool force)
|
||||
m_settingsMutex.unlock();
|
||||
}
|
||||
|
||||
if (m_running.m_pll != m_config.m_pll || force)
|
||||
{
|
||||
if (m_config.m_pll) {
|
||||
m_pll.reset();
|
||||
}
|
||||
}
|
||||
|
||||
m_running.m_frequency = m_config.m_frequency;
|
||||
m_running.m_channelSampleRate = m_config.m_channelSampleRate;
|
||||
m_running.m_inputSampleRate = m_config.m_inputSampleRate;
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "dsp/interpolator.h"
|
||||
#include "dsp/ncof.h"
|
||||
#include "dsp/fftfilt.h"
|
||||
#include "dsp/phaselock.h"
|
||||
#include "dsp/phaselockcomplex.h"
|
||||
#include "audio/audiofifo.h"
|
||||
#include "util/message.h"
|
||||
|
||||
@ -148,6 +148,9 @@ public:
|
||||
int getChannelSampleRate() const { return m_running.m_channelSampleRate; }
|
||||
double getMagSq() const { return m_magsq; }
|
||||
bool isPllLocked() const { return m_running.m_pll && m_pll.locked(); }
|
||||
Real getPllFrequency() const { return m_pll.getFrequency(); }
|
||||
Real getPllDeltaPhase() const { return m_pll.getDeltaPhi(); }
|
||||
Real getPllPhase() const { return m_pll.getPhiHat(); }
|
||||
|
||||
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
|
||||
virtual void start();
|
||||
@ -203,7 +206,7 @@ private:
|
||||
bool m_useInterpolator;
|
||||
|
||||
NCOF m_nco;
|
||||
SimplePhaseLock m_pll;
|
||||
PhaseLockComplex m_pll;
|
||||
Interpolator m_interpolator;
|
||||
Real m_interpolatorDistance;
|
||||
Real m_interpolatorDistanceRemain;
|
||||
@ -247,11 +250,13 @@ private:
|
||||
|
||||
if (m_running.m_pll)
|
||||
{
|
||||
Real ncopll[2];
|
||||
m_pll.process(re, im, ncopll);
|
||||
m_pll.feed(re, im);
|
||||
|
||||
Real mixI = m_sum.real() * ncopll[0] - m_sum.imag() * ncopll[1];
|
||||
Real mixQ = m_sum.real() * ncopll[1] + m_sum.imag() * ncopll[0];
|
||||
// Use -fPLL to mix (exchange PLL real and image in the complex multiplication)
|
||||
Real mixI = m_sum.real() * m_pll.getImag() - m_sum.imag() * m_pll.getReal();
|
||||
Real mixQ = m_sum.real() * m_pll.getReal() + m_sum.imag() * m_pll.getImag();
|
||||
// Real mixI = m_pll.getReal() * SDR_RX_SCALED;
|
||||
// Real mixQ = m_pll.getImag() * SDR_RX_SCALED;
|
||||
|
||||
if (m_running.m_ssb & !m_usb)
|
||||
{ // invert spectrum for LSB
|
||||
|
@ -243,6 +243,15 @@ void ChannelAnalyzerNGGUI::tick()
|
||||
} else {
|
||||
ui->pll->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
|
||||
}
|
||||
|
||||
if (ui->pll->isChecked())
|
||||
{
|
||||
int fHz = round(m_channelAnalyzer->getPllFrequency()*m_rate);
|
||||
ui->pll->setToolTip(tr("PLL lock (f:%1 Hz e:%2 rad p:%3 rad)")
|
||||
.arg(fHz)
|
||||
.arg(m_channelAnalyzer->getPllDeltaPhase())
|
||||
.arg(m_channelAnalyzer->getPllPhase()));
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value)
|
||||
@ -257,8 +266,13 @@ void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value)
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelAnalyzerNGGUI::on_pll_toggled(bool checked __attribute__((unused)))
|
||||
void ChannelAnalyzerNGGUI::on_pll_toggled(bool checked)
|
||||
{
|
||||
if (!checked && m_usePll) {
|
||||
ui->pll->setToolTip("PLL lock");
|
||||
}
|
||||
|
||||
m_usePll = checked;
|
||||
applySettings();
|
||||
}
|
||||
|
||||
@ -399,7 +413,8 @@ ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceUISet *de
|
||||
m_channelMarker(this),
|
||||
m_doApplySettings(true),
|
||||
m_rate(6000),
|
||||
m_spanLog2(0)
|
||||
m_spanLog2(0),
|
||||
m_usePll(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
@ -66,6 +66,7 @@ private:
|
||||
bool m_doApplySettings;
|
||||
int m_rate; //!< sample rate after final in-channel decimation (spanlog2)
|
||||
int m_spanLog2;
|
||||
bool m_usePll;
|
||||
MovingAverageUtil<Real, double, 40> m_channelPowerDbAvg;
|
||||
|
||||
ChannelAnalyzerNG* m_channelAnalyzer;
|
||||
|
@ -7,6 +7,7 @@ set(am_SOURCES
|
||||
amdemodgui.cpp
|
||||
amdemodsettings.cpp
|
||||
amdemodplugin.cpp
|
||||
amdemodssbdialog.cpp
|
||||
)
|
||||
|
||||
set(am_HEADERS
|
||||
@ -14,10 +15,12 @@ set(am_HEADERS
|
||||
amdemodgui.h
|
||||
amdemodsettings.h
|
||||
amdemodplugin.h
|
||||
amdemodssbdialog.h
|
||||
)
|
||||
|
||||
set(am_FORMS
|
||||
amdemodgui.ui
|
||||
amdemodssb.ui
|
||||
)
|
||||
|
||||
include_directories(
|
||||
|
@ -67,6 +67,7 @@ AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) :
|
||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo, getInputMessageQueue());
|
||||
m_audioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
|
||||
DSBFilter = new fftfilt((2.0f * m_settings.m_rfBandwidth) / m_audioSampleRate, 2 * 1024);
|
||||
SSBFilter = new fftfilt(0.0f, m_settings.m_rfBandwidth / m_audioSampleRate, 1024);
|
||||
|
||||
applyChannelSettings(m_inputSampleRate, m_inputFrequencyOffset, true);
|
||||
applySettings(m_settings, true);
|
||||
@ -89,6 +90,7 @@ AMDemod::~AMDemod()
|
||||
delete m_threadedChannelizer;
|
||||
delete m_channelizer;
|
||||
delete DSBFilter;
|
||||
delete SSBFilter;
|
||||
}
|
||||
|
||||
void AMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst __attribute__((unused)))
|
||||
@ -233,6 +235,7 @@ void AMDemod::applyAudioSampleRate(int sampleRate)
|
||||
m_inputMessageQueue.push(channelConfigMsg);
|
||||
|
||||
m_settingsMutex.lock();
|
||||
|
||||
m_interpolator.create(16, m_inputSampleRate, m_settings.m_rfBandwidth / 2.2f);
|
||||
m_interpolatorDistanceRemain = 0;
|
||||
m_interpolatorDistance = (Real) m_inputSampleRate / (Real) sampleRate;
|
||||
@ -241,8 +244,14 @@ void AMDemod::applyAudioSampleRate(int sampleRate)
|
||||
m_squelchDelayLine.resize(sampleRate/5);
|
||||
DSBFilter->create_dsb_filter((2.0f * m_settings.m_rfBandwidth) / (float) sampleRate);
|
||||
m_pllFilt.create(101, sampleRate, 500.0);
|
||||
m_settingsMutex.unlock();
|
||||
|
||||
if (m_settings.m_pll) {
|
||||
m_volumeAGC.resizeNew(sampleRate, 0.003);
|
||||
} else {
|
||||
m_volumeAGC.resizeNew(sampleRate/10, 0.003);
|
||||
}
|
||||
|
||||
m_settingsMutex.unlock();
|
||||
m_audioSampleRate = sampleRate;
|
||||
}
|
||||
|
||||
@ -282,6 +291,7 @@ void AMDemod::applySettings(const AMDemodSettings& settings, bool force)
|
||||
<< " m_bandpassEnable: " << settings.m_bandpassEnable
|
||||
<< " m_audioDeviceName: " << settings.m_audioDeviceName
|
||||
<< " m_pll: " << settings.m_pll
|
||||
<< " m_syncAMOperation: " << (int) settings.m_syncAMOperation
|
||||
<< " force: " << force;
|
||||
|
||||
if((m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
|
||||
@ -314,6 +324,23 @@ void AMDemod::applySettings(const AMDemodSettings& settings, bool force)
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_pll != settings.m_pll) || force)
|
||||
{
|
||||
if (settings.m_pll)
|
||||
{
|
||||
m_volumeAGC.resizeNew(m_audioSampleRate/4, 0.003);
|
||||
m_syncAMBuffIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_volumeAGC.resizeNew(m_audioSampleRate/10, 0.003);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_syncAMOperation != settings.m_syncAMOperation) || force) {
|
||||
m_syncAMBuffIndex = 0;
|
||||
}
|
||||
|
||||
m_settings = settings;
|
||||
}
|
||||
|
||||
|
@ -167,11 +167,12 @@ private:
|
||||
int m_magsqCount;
|
||||
|
||||
MovingAverageUtil<Real, double, 16> m_movingAverage;
|
||||
SimpleAGC<4096> m_volumeAGC;
|
||||
SimpleAGC<4800> m_volumeAGC;
|
||||
Bandpass<Real> m_bandpass;
|
||||
Lowpass<std::complex<float> > m_pllFilt;
|
||||
PhaseLockComplex m_pll;
|
||||
fftfilt* DSBFilter;
|
||||
fftfilt* SSBFilter;
|
||||
Real m_syncAMBuff[2*1024];
|
||||
uint32_t m_syncAMBuffIndex;
|
||||
|
||||
@ -238,16 +239,29 @@ private:
|
||||
|
||||
fftfilt::cmplx *sideband;
|
||||
std::complex<float> cs(yr, yi);
|
||||
int n_out = DSBFilter->runDSB(cs, &sideband, false);
|
||||
int n_out;
|
||||
|
||||
if (m_settings.m_syncAMOperation == AMDemodSettings::SyncAMDSB) {
|
||||
n_out = DSBFilter->runDSB(cs, &sideband, false);
|
||||
} else {
|
||||
n_out = SSBFilter->runSSB(cs, &sideband, m_settings.m_syncAMOperation == AMDemodSettings::SyncAMUSB, false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_out; i++)
|
||||
{
|
||||
m_syncAMBuff[i] = (sideband[i].real() + sideband[i].imag());
|
||||
if (m_settings.m_syncAMOperation == AMDemodSettings::SyncAMDSB) {
|
||||
m_syncAMBuff[i] = (sideband[i].real() + sideband[i].imag())/2.0f;
|
||||
} else if (m_settings.m_syncAMOperation == AMDemodSettings::SyncAMUSB) {
|
||||
m_syncAMBuff[i] = (sideband[i].real() + sideband[i].imag());
|
||||
} else {
|
||||
m_syncAMBuff[i] = (sideband[i].real() + sideband[i].imag());
|
||||
}
|
||||
|
||||
m_syncAMBuffIndex = 0;
|
||||
}
|
||||
|
||||
m_syncAMBuffIndex = m_syncAMBuffIndex < 2*1024 ? m_syncAMBuffIndex : 0;
|
||||
demod = m_syncAMBuff[m_syncAMBuffIndex++]*0.7*(SDR_RX_SCALEF/602.0f);
|
||||
demod = m_syncAMBuff[m_syncAMBuffIndex++]*(SDR_RX_SCALEF/602.0f);
|
||||
m_volumeAGC.feed(demod);
|
||||
demod /= (10.0*m_volumeAGC.getValue());
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "amdemodgui.h"
|
||||
#include "amdemodssbdialog.h"
|
||||
|
||||
#include "device/devicesourceapi.h"
|
||||
#include "device/deviceuiset.h"
|
||||
@ -149,6 +150,12 @@ void AMDemodGUI::on_pll_toggled(bool checked)
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void AMDemodGUI::on_ssb_toggled(bool checked)
|
||||
{
|
||||
m_settings.m_syncAMOperation = checked ? m_samUSB ? AMDemodSettings::SyncAMUSB : AMDemodSettings::SyncAMLSB : AMDemodSettings::SyncAMDSB;
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void AMDemodGUI::on_bandpassEnable_toggled(bool checked)
|
||||
{
|
||||
m_settings.m_bandpassEnable = checked;
|
||||
@ -215,6 +222,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS
|
||||
m_channelMarker(this),
|
||||
m_doApplySettings(true),
|
||||
m_squelchOpen(false),
|
||||
m_samUSB(true),
|
||||
m_tickCount(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
@ -230,6 +238,9 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS
|
||||
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
||||
connect(audioMuteRightClickEnabler, SIGNAL(rightClick()), this, SLOT(audioSelect()));
|
||||
|
||||
CRightClickEnabler *samSidebandRightClickEnabler = new CRightClickEnabler(ui->ssb);
|
||||
connect(samSidebandRightClickEnabler, SIGNAL(rightClick()), this, SLOT(samSSBSelect()));
|
||||
|
||||
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
|
||||
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
|
||||
@ -254,6 +265,11 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS
|
||||
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
|
||||
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||
|
||||
m_iconDSBUSB.addPixmap(QPixmap("://dsb.png"), QIcon::Normal, QIcon::Off);
|
||||
m_iconDSBUSB.addPixmap(QPixmap("://usb.png"), QIcon::Normal, QIcon::On);
|
||||
m_iconDSBLSB.addPixmap(QPixmap("://dsb.png"), QIcon::Normal, QIcon::Off);
|
||||
m_iconDSBLSB.addPixmap(QPixmap("://lsb.png"), QIcon::Normal, QIcon::On);
|
||||
|
||||
displaySettings();
|
||||
applySettings(true);
|
||||
}
|
||||
@ -314,6 +330,20 @@ void AMDemodGUI::displaySettings()
|
||||
ui->bandpassEnable->setChecked(m_settings.m_bandpassEnable);
|
||||
ui->pll->setChecked(m_settings.m_pll);
|
||||
|
||||
if (m_settings.m_pll) {
|
||||
if (m_settings.m_syncAMOperation == AMDemodSettings::SyncAMLSB) {
|
||||
m_samUSB = false;
|
||||
ui->ssb->setIcon(m_iconDSBLSB);
|
||||
} else {
|
||||
m_samUSB = true;
|
||||
ui->ssb->setIcon(m_iconDSBUSB);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->ssb->setIcon(m_iconDSBUSB);
|
||||
}
|
||||
|
||||
blockApplySettings(false);
|
||||
}
|
||||
|
||||
@ -340,6 +370,26 @@ void AMDemodGUI::audioSelect()
|
||||
}
|
||||
}
|
||||
|
||||
void AMDemodGUI::samSSBSelect()
|
||||
{
|
||||
AMDemodSSBDialog ssbSelect(m_samUSB);
|
||||
ssbSelect.exec();
|
||||
|
||||
ui->ssb->setIcon(ssbSelect.isUsb() ? m_iconDSBUSB : m_iconDSBLSB);
|
||||
|
||||
if (ssbSelect.isUsb() != m_samUSB)
|
||||
{
|
||||
qDebug("AMDemodGUI::samSSBSelect: %s", ssbSelect.isUsb() ? "usb" : "lsb");
|
||||
m_samUSB = ssbSelect.isUsb();
|
||||
|
||||
if (m_settings.m_syncAMOperation != AMDemodSettings::SyncAMDSB)
|
||||
{
|
||||
m_settings.m_syncAMOperation = m_samUSB ? AMDemodSettings::SyncAMUSB : AMDemodSettings::SyncAMLSB;
|
||||
applySettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AMDemodGUI::tick()
|
||||
{
|
||||
double magsqAvg, magsqPeak;
|
||||
|
@ -1,7 +1,9 @@
|
||||
#ifndef INCLUDE_AMDEMODGUI_H
|
||||
#define INCLUDE_AMDEMODGUI_H
|
||||
|
||||
#include <plugin/plugininstancegui.h>
|
||||
#include <QIcon>
|
||||
|
||||
#include "plugin/plugininstancegui.h"
|
||||
#include "gui/rollupwidget.h"
|
||||
#include "dsp/channelmarker.h"
|
||||
#include "dsp/movingaverage.h"
|
||||
@ -50,9 +52,13 @@ private:
|
||||
|
||||
AMDemod* m_amDemod;
|
||||
bool m_squelchOpen;
|
||||
bool m_samUSB;
|
||||
uint32_t m_tickCount;
|
||||
MessageQueue m_inputMessageQueue;
|
||||
|
||||
QIcon m_iconDSBUSB;
|
||||
QIcon m_iconDSBLSB;
|
||||
|
||||
explicit AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
|
||||
virtual ~AMDemodGUI();
|
||||
|
||||
@ -66,6 +72,7 @@ private:
|
||||
private slots:
|
||||
void on_deltaFrequency_changed(qint64 value);
|
||||
void on_pll_toggled(bool checked);
|
||||
void on_ssb_toggled(bool checked);
|
||||
void on_bandpassEnable_toggled(bool checked);
|
||||
void on_rfBW_valueChanged(int value);
|
||||
void on_volume_valueChanged(int value);
|
||||
@ -75,6 +82,7 @@ private slots:
|
||||
void onMenuDialogCalled(const QPoint& p);
|
||||
void handleInputMessages();
|
||||
void audioSelect();
|
||||
void samSSBSelect();
|
||||
void tick();
|
||||
};
|
||||
|
||||
|
@ -154,6 +154,24 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="ssb">
|
||||
<property name="toolTip">
|
||||
<string>Synchronous AM SSB/DSB toggle right click to select side band</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/dsb.png</normaloff>
|
||||
<normalon>:/usb.png</normalon>:/dsb.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
|
@ -39,6 +39,7 @@ void AMDemodSettings::resetToDefaults()
|
||||
m_title = "AM Demodulator";
|
||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_pll = false;
|
||||
m_syncAMOperation = SyncAMDSB;
|
||||
}
|
||||
|
||||
QByteArray AMDemodSettings::serialize() const
|
||||
@ -58,6 +59,7 @@ QByteArray AMDemodSettings::serialize() const
|
||||
s.writeString(9, m_title);
|
||||
s.writeString(11, m_audioDeviceName);
|
||||
s.writeBool(12, m_pll);
|
||||
s.writeS32(13, (int) m_syncAMOperation);
|
||||
|
||||
return s.final();
|
||||
}
|
||||
@ -96,6 +98,8 @@ bool AMDemodSettings::deserialize(const QByteArray& data)
|
||||
d.readString(9, &m_title, "AM Demodulator");
|
||||
d.readString(11, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
|
||||
d.readBool(12, &m_pll, false);
|
||||
d.readS32(13, &tmp, 0);
|
||||
m_syncAMOperation = tmp < 0 ? SyncAMDSB : tmp > 2 ? SyncAMDSB : (SyncAMOperation) tmp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -23,6 +23,13 @@ class Serializable;
|
||||
|
||||
struct AMDemodSettings
|
||||
{
|
||||
enum SyncAMOperation
|
||||
{
|
||||
SyncAMDSB,
|
||||
SyncAMUSB,
|
||||
SyncAMLSB
|
||||
};
|
||||
|
||||
qint32 m_inputFrequencyOffset;
|
||||
Real m_rfBandwidth;
|
||||
Real m_squelch;
|
||||
@ -34,6 +41,7 @@ struct AMDemodSettings
|
||||
Serializable *m_channelMarker;
|
||||
QString m_audioDeviceName;
|
||||
bool m_pll;
|
||||
SyncAMOperation m_syncAMOperation;
|
||||
|
||||
AMDemodSettings();
|
||||
void resetToDefaults();
|
||||
|
96
plugins/channelrx/demodam/amdemodssb.ui
Normal file
96
plugins/channelrx/demodam/amdemodssb.ui
Normal file
@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AMDemodSSBDialog</class>
|
||||
<widget class="QDialog" name="AMDemodSSBDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>199</width>
|
||||
<height>115</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Liberation Sans</family>
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>SAM sideband selection</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="lsb">
|
||||
<property name="text">
|
||||
<string>LSB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QRadioButton" name="usb">
|
||||
<property name="text">
|
||||
<string>USB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>AMDemodSSBDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>257</x>
|
||||
<y>194</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>203</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>AMDemodSSBDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>314</x>
|
||||
<y>194</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>203</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
41
plugins/channelrx/demodam/amdemodssbdialog.cpp
Normal file
41
plugins/channelrx/demodam/amdemodssbdialog.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "amdemodssbdialog.h"
|
||||
#include "ui_amdemodssb.h"
|
||||
|
||||
AMDemodSSBDialog::AMDemodSSBDialog(bool usb, QWidget* parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::AMDemodSSBDialog),
|
||||
m_usb(usb)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->usb->setChecked(usb);
|
||||
ui->lsb->setChecked(!usb);
|
||||
}
|
||||
|
||||
AMDemodSSBDialog::~AMDemodSSBDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void AMDemodSSBDialog::accept()
|
||||
{
|
||||
m_usb = ui->usb->isChecked();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
|
43
plugins/channelrx/demodam/amdemodssbdialog.h
Normal file
43
plugins/channelrx/demodam/amdemodssbdialog.h
Normal file
@ -0,0 +1,43 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PLUGINS_CHANNELRX_DEMODAM_AMDEMODSSBDIALOG_H_
|
||||
#define PLUGINS_CHANNELRX_DEMODAM_AMDEMODSSBDIALOG_H_
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class AMDemodSSBDialog;
|
||||
}
|
||||
|
||||
class AMDemodSSBDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AMDemodSSBDialog(bool usb, QWidget* parent = 0);
|
||||
~AMDemodSSBDialog();
|
||||
|
||||
bool isUsb() const { return m_usb; }
|
||||
|
||||
private:
|
||||
Ui::AMDemodSSBDialog* ui;
|
||||
bool m_usb;
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
};
|
||||
|
||||
#endif /* PLUGINS_CHANNELRX_DEMODAM_AMDEMODSSBDIALOG_H_ */
|
@ -89,6 +89,13 @@ public:
|
||||
m_moving_average.resize(AvgSize, initial);
|
||||
}
|
||||
|
||||
void resizeNew(uint32_t newSize, Real initial, Real cutoff=0, Real clip=0)
|
||||
{
|
||||
m_cutoff = cutoff;
|
||||
m_clip = clip;
|
||||
m_moving_average.resize(newSize, initial);
|
||||
}
|
||||
|
||||
void fill(double value)
|
||||
{
|
||||
m_moving_average.fill(value);
|
||||
|
@ -18,11 +18,12 @@
|
||||
#include "recursivefilters.h"
|
||||
|
||||
#undef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#define M_PI 3.14159265358979323846
|
||||
|
||||
SecondOrderRecursiveFilter::SecondOrderRecursiveFilter(float samplingFrequency, float centerFrequency, float r) :
|
||||
m_r(r),
|
||||
m_frequencyRatio(centerFrequency/samplingFrequency)
|
||||
m_frequencyRatio(centerFrequency/samplingFrequency),
|
||||
m_f(cos(2.0*M_PI*(m_frequencyRatio)))
|
||||
{
|
||||
init();
|
||||
}
|
||||
@ -33,6 +34,7 @@ SecondOrderRecursiveFilter::~SecondOrderRecursiveFilter()
|
||||
void SecondOrderRecursiveFilter::setFrequencies(float samplingFrequency, float centerFrequency)
|
||||
{
|
||||
m_frequencyRatio = centerFrequency / samplingFrequency;
|
||||
m_f = cos(2.0*M_PI*m_frequencyRatio);
|
||||
init();
|
||||
}
|
||||
|
||||
@ -44,7 +46,7 @@ void SecondOrderRecursiveFilter::setR(float r)
|
||||
|
||||
short SecondOrderRecursiveFilter::run(short sample)
|
||||
{
|
||||
m_v[0] = ((1.0f - m_r) * (float) sample) + (2.0f * m_r * cos(2.0*M_PI*m_frequencyRatio) * m_v[1]) - (m_r * m_r * m_v[2]);
|
||||
m_v[0] = ((1.0f - m_r) * (float) sample) + (2.0f * m_r * m_f * m_v[1]) - (m_r * m_r * m_v[2]);
|
||||
float y = m_v[0] - m_v[2];
|
||||
m_v[2] = m_v[1];
|
||||
m_v[1] = m_v[0];
|
||||
@ -54,7 +56,7 @@ short SecondOrderRecursiveFilter::run(short sample)
|
||||
|
||||
float SecondOrderRecursiveFilter::run(float sample)
|
||||
{
|
||||
m_v[0] = ((1.0f - m_r) * sample) + (2.0f * m_r * cos(2.0*M_PI*m_frequencyRatio) * m_v[1]) - (m_r * m_r * m_v[2]);
|
||||
m_v[0] = ((1.0f - m_r) * sample) + (2.0f * m_r * m_f * m_v[1]) - (m_r * m_r * m_v[2]);
|
||||
float y = m_v[0] - m_v[2];
|
||||
m_v[2] = m_v[1];
|
||||
m_v[1] = m_v[0];
|
||||
|
@ -39,6 +39,7 @@ private:
|
||||
|
||||
float m_r;
|
||||
float m_frequencyRatio;
|
||||
float m_f;
|
||||
float m_v[3];
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user