AM demod: synchronous AM: implemented sidebands selection

This commit is contained in:
f4exb 2018-05-13 22:30:50 +02:00
parent e9f64a05f2
commit 21840c5dd3
19 changed files with 372 additions and 20 deletions

4
debian/changelog vendored
View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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(

View File

@ -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;
}

View File

@ -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());
}

View File

@ -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;

View File

@ -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();
};

View File

@ -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">

View File

@ -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;
}

View File

@ -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();

View 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>

View 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();
}

View 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_ */

View File

@ -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);

View File

@ -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];

View File

@ -39,6 +39,7 @@ private:
float m_r;
float m_frequencyRatio;
float m_f;
float m_v[3];
};