1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-07-31 13:02:27 -04:00

AM Demod: added optional bandpass boxcar filter

This commit is contained in:
f4exb 2017-05-12 19:21:52 +02:00
parent b24ac8fa38
commit 375f327004
7 changed files with 81 additions and 24 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -63,9 +63,9 @@ AMDemod::~AMDemod()
DSPEngine::instance()->removeAudioSink(&m_audioFifo); DSPEngine::instance()->removeAudioSink(&m_audioFifo);
} }
void AMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real volume, Real squelch, bool audioMute) void AMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real volume, Real squelch, bool audioMute, bool bandpassEnable)
{ {
Message* cmd = MsgConfigureAMDemod::create(rfBandwidth, volume, squelch, audioMute); Message* cmd = MsgConfigureAMDemod::create(rfBandwidth, volume, squelch, audioMute, bandpassEnable);
messageQueue->push(cmd); messageQueue->push(cmd);
} }
@ -157,6 +157,7 @@ bool AMDemod::handleMessage(const Message& cmd)
m_config.m_volume = cfg.getVolume(); m_config.m_volume = cfg.getVolume();
m_config.m_squelch = cfg.getSquelch(); m_config.m_squelch = cfg.getSquelch();
m_config.m_audioMute = cfg.getAudioMute(); m_config.m_audioMute = cfg.getAudioMute();
m_config.m_bandpassEnable = cfg.getBandpassEnable();
apply(); apply();
@ -164,7 +165,8 @@ bool AMDemod::handleMessage(const Message& cmd)
<< " m_rfBandwidth: " << m_config.m_rfBandwidth << " m_rfBandwidth: " << m_config.m_rfBandwidth
<< " m_volume: " << m_config.m_volume << " m_volume: " << m_config.m_volume
<< " m_squelch: " << m_config.m_squelch << " m_squelch: " << m_config.m_squelch
<< " m_audioMute: " << m_config.m_audioMute; << " m_audioMute: " << m_config.m_audioMute
<< " m_bandpassEnable: " << m_config.m_bandpassEnable;
return true; return true;
} }
@ -185,12 +187,14 @@ void AMDemod::apply()
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) || if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth) || (m_config.m_rfBandwidth != m_running.m_rfBandwidth) ||
(m_config.m_audioSampleRate != m_running.m_audioSampleRate)) (m_config.m_audioSampleRate != m_running.m_audioSampleRate) ||
(m_config.m_bandpassEnable != m_running.m_bandpassEnable))
{ {
m_settingsMutex.lock(); m_settingsMutex.lock();
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2); m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2f);
m_interpolatorDistanceRemain = 0; m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate; m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate;
m_bandpass.create(301, m_config.m_audioSampleRate, 300.0, m_config.m_rfBandwidth / 2.0f);
m_settingsMutex.unlock(); m_settingsMutex.unlock();
} }
@ -207,4 +211,5 @@ void AMDemod::apply()
m_running.m_volume = m_config.m_volume; m_running.m_volume = m_config.m_volume;
m_running.m_audioSampleRate = m_config.m_audioSampleRate; m_running.m_audioSampleRate = m_config.m_audioSampleRate;
m_running.m_audioMute = m_config.m_audioMute; m_running.m_audioMute = m_config.m_audioMute;
m_running.m_bandpassEnable = m_config.m_bandpassEnable;
} }

View File

@ -24,6 +24,7 @@
#include "dsp/interpolator.h" #include "dsp/interpolator.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "dsp/agc.h" #include "dsp/agc.h"
#include "dsp/bandpass.h"
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "util/message.h" #include "util/message.h"
@ -33,7 +34,7 @@ public:
AMDemod(); AMDemod();
~AMDemod(); ~AMDemod();
void configure(MessageQueue* messageQueue, Real rfBandwidth, Real volume, Real squelch, bool audioMute); void configure(MessageQueue* messageQueue, Real rfBandwidth, Real volume, Real squelch, bool audioMute, bool bandpassEnable);
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
virtual void start(); virtual void start();
@ -62,10 +63,11 @@ private:
Real getVolume() const { return m_volume; } Real getVolume() const { return m_volume; }
Real getSquelch() const { return m_squelch; } Real getSquelch() const { return m_squelch; }
bool getAudioMute() const { return m_audioMute; } bool getAudioMute() const { return m_audioMute; }
bool getBandpassEnable() const { return m_bandpassEnable; }
static MsgConfigureAMDemod* create(Real rfBandwidth, Real volume, Real squelch, bool audioMute) static MsgConfigureAMDemod* create(Real rfBandwidth, Real volume, Real squelch, bool audioMute, bool bandpassEnable)
{ {
return new MsgConfigureAMDemod(rfBandwidth, volume, squelch, audioMute); return new MsgConfigureAMDemod(rfBandwidth, volume, squelch, audioMute, bandpassEnable);
} }
private: private:
@ -73,13 +75,15 @@ private:
Real m_volume; Real m_volume;
Real m_squelch; Real m_squelch;
bool m_audioMute; bool m_audioMute;
bool m_bandpassEnable;
MsgConfigureAMDemod(Real rfBandwidth, Real volume, Real squelch, bool audioMute) : MsgConfigureAMDemod(Real rfBandwidth, Real volume, Real squelch, bool audioMute, bool bandpassEnable) :
Message(), Message(),
m_rfBandwidth(rfBandwidth), m_rfBandwidth(rfBandwidth),
m_volume(volume), m_volume(volume),
m_squelch(squelch), m_squelch(squelch),
m_audioMute(audioMute) m_audioMute(audioMute),
m_bandpassEnable(bandpassEnable)
{ } { }
}; };
@ -102,6 +106,7 @@ private:
Real m_volume; Real m_volume;
quint32 m_audioSampleRate; quint32 m_audioSampleRate;
bool m_audioMute; bool m_audioMute;
bool m_bandpassEnable;
Config() : Config() :
m_inputSampleRate(-1), m_inputSampleRate(-1),
@ -110,7 +115,8 @@ private:
m_squelch(0), m_squelch(0),
m_volume(0), m_volume(0),
m_audioSampleRate(0), m_audioSampleRate(0),
m_audioMute(false) m_audioMute(false),
m_bandpassEnable(false)
{ } { }
}; };
@ -132,6 +138,7 @@ private:
MovingAverage<double> m_movingAverage; MovingAverage<double> m_movingAverage;
SimpleAGC m_volumeAGC; SimpleAGC m_volumeAGC;
Bandpass<Real> m_bandpass;
AudioVector m_audioBuffer; AudioVector m_audioBuffer;
uint m_audioBufferFill; uint m_audioBufferFill;
@ -180,18 +187,18 @@ private:
if ((m_squelchCount >= m_running.m_audioSampleRate / 20) && !m_running.m_audioMute) if ((m_squelchCount >= m_running.m_audioSampleRate / 20) && !m_running.m_audioMute)
{ {
Real demod = sqrt(magsq); Real demod = sqrt(magsq);
if (demod > 1)
{
demod = 1;
}
m_volumeAGC.feed(demod); m_volumeAGC.feed(demod);
demod /= m_volumeAGC.getValue(); demod /= m_volumeAGC.getValue();
if (m_running.m_bandpassEnable)
{
demod = m_bandpass.filter(demod);
demod /= 301.0f;
}
Real attack = m_squelchCount / (0.1f * m_running.m_audioSampleRate); Real attack = m_squelchCount / (0.1f * m_running.m_audioSampleRate);
sample = (0.5 - demod) * attack * 2048 * m_running.m_volume; sample = (0.5 - demod) * attack * 2048 * m_running.m_volume;
// demod *= ((0.003 * attack) / m_volumeAGC.getValue());
// sample = demod * 32700 * 16;
m_squelchOpen = true; m_squelchOpen = true;
} }
else else

View File

@ -88,6 +88,7 @@ QByteArray AMDemodGUI::serialize() const
s.writeS32(4, ui->volume->value()); s.writeS32(4, ui->volume->value());
s.writeS32(5, ui->squelch->value()); s.writeS32(5, ui->squelch->value());
s.writeU32(7, m_channelMarker.getColor().rgb()); s.writeU32(7, m_channelMarker.getColor().rgb());
s.writeBool(8, ui->bandpassEnable->isChecked());
return s.final(); return s.final();
} }
@ -106,6 +107,7 @@ bool AMDemodGUI::deserialize(const QByteArray& data)
QByteArray bytetmp; QByteArray bytetmp;
quint32 u32tmp; quint32 u32tmp;
qint32 tmp; qint32 tmp;
bool boolTmp;
blockApplySettings(true); blockApplySettings(true);
m_channelMarker.blockSignals(true); m_channelMarker.blockSignals(true);
@ -126,6 +128,9 @@ bool AMDemodGUI::deserialize(const QByteArray& data)
m_channelMarker.setColor(u32tmp); m_channelMarker.setColor(u32tmp);
} }
d.readBool(8, &boolTmp, false);
ui->bandpassEnable->setChecked(boolTmp);
blockApplySettings(false); blockApplySettings(false);
m_channelMarker.blockSignals(false); m_channelMarker.blockSignals(false);
@ -169,6 +174,11 @@ void AMDemodGUI::on_deltaFrequency_changed(quint64 value)
} }
} }
void AMDemodGUI::on_bandpassEnable_toggled(bool checked)
{
applySettings();
}
void AMDemodGUI::on_rfBW_valueChanged(int value) void AMDemodGUI::on_rfBW_valueChanged(int value)
{ {
ui->rfBWText->setText(QString("%1 kHz").arg(value / 10.0, 0, 'f', 1)); ui->rfBWText->setText(QString("%1 kHz").arg(value / 10.0, 0, 'f', 1));
@ -284,7 +294,8 @@ void AMDemodGUI::applySettings()
ui->rfBW->value() * 100.0, ui->rfBW->value() * 100.0,
ui->volume->value() / 10.0, ui->volume->value() / 10.0,
ui->squelch->value(), ui->squelch->value(),
ui->audioMute->isChecked()); ui->audioMute->isChecked(),
ui->bandpassEnable->isChecked());
} }
} }

View File

@ -41,6 +41,7 @@ private slots:
void viewChanged(); void viewChanged();
void on_deltaFrequency_changed(quint64 value); void on_deltaFrequency_changed(quint64 value);
void on_deltaMinus_toggled(bool minus); void on_deltaMinus_toggled(bool minus);
void on_bandpassEnable_toggled(bool checked);
void on_rfBW_valueChanged(int value); void on_rfBW_valueChanged(int value);
void on_volume_valueChanged(int value); void on_volume_valueChanged(int value);
void on_squelch_valueChanged(int value); void on_squelch_valueChanged(int value);

View File

@ -56,7 +56,16 @@
<property name="spacing"> <property name="spacing">
<number>3</number> <number>3</number>
</property> </property>
<property name="margin"> <property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number> <number>2</number>
</property> </property>
<item> <item>
@ -224,6 +233,21 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="ButtonSwitch" name="bandpassEnable">
<property name="toolTip">
<string>Toggle boxcar bandpass filter with 300 Hz low cuttof</string>
</property>
<property name="icon">
<iconset resource="../../../sdrbase/resources/res.qrc">
<normaloff>:/filter_bandpass.png</normaloff>
<normalon>:/filter_bandpass.png</normalon>:/filter_bandpass.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item> <item>
<widget class="QSlider" name="rfBW"> <widget class="QSlider" name="rfBW">
<property name="toolTip"> <property name="toolTip">
@ -381,6 +405,11 @@
<header>gui/levelmeter.h</header> <header>gui/levelmeter.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="../../../sdrbase/resources/res.qrc"/> <include location="../../../sdrbase/resources/res.qrc"/>

View File

@ -30,14 +30,18 @@ Use this button to toggle audio mute for this channel. The button will light up
- bottom bar (blue green): instantaneous peak value - bottom bar (blue green): instantaneous peak value
- tip vertical bar (bright green): peak hold value - tip vertical bar (bright green): peak hold value
<h3>6: RF bandwidth</h3> <h3>6:Bandpass boxcar filter toggle</h3>
Use this button to enable or disable the bandpass boxcar (sharp) filter with low cutoff at 300 Hz and high cutoff at half the RF bandwidth. This may help readibility of low signals on air traffic communications but degrades audio on comfortable AM broadcast transmissions.
<h3>7: RF bandwidth</h3>
This is the bandwidth in kHz of the channel signal before demodulation. It can be set continuously in 1 kHz steps from 1 to 40 kHz. This is the bandwidth in kHz of the channel signal before demodulation. It can be set continuously in 1 kHz steps from 1 to 40 kHz.
<h3>7: Volume</h3> <h3>8: Volume</h3>
This is the volume of the audio signal from 0.0 (mute) to 10.0 (maximum). It can be varied continuously in 0.1 steps using the dial button. This is the volume of the audio signal from 0.0 (mute) to 10.0 (maximum). It can be varied continuously in 0.1 steps using the dial button.
<h3>8: Squelch threshold</h3> <h3>9: Squelch threshold</h3>
This is the squelch threshold in dB. The average total power received in the signal bandwidth before demodulation is compared to this value and the squelch input is open above this value. It can be varied continuously in 0.1 dB steps from 0.0 to -100.0 dB using the dial button. This is the squelch threshold in dB. The average total power received in the signal bandwidth before demodulation is compared to this value and the squelch input is open above this value. It can be varied continuously in 0.1 dB steps from 0.0 to -100.0 dB using the dial button.