1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-10-01 09:16:39 -04:00

SSB demod: implemented DSB option

This commit is contained in:
f4exb 2015-12-06 02:34:47 +01:00
parent f512503dc1
commit 5e0e3a01e1
4 changed files with 148 additions and 94 deletions

View File

@ -50,20 +50,20 @@ SSBDemod::SSBDemod(SampleSink* sampleSink) :
m_audioBuffer.resize(1<<9); m_audioBuffer.resize(1<<9);
m_audioBufferFill = 0; m_audioBufferFill = 0;
m_undersampleCount = 0; m_undersampleCount = 0;
m_sum = 0;
m_usb = true; m_usb = true;
m_magsq = 0.0f; m_magsq = 0.0f;
SSBFilter = new fftfilt(m_LowCutoff / m_audioSampleRate, m_Bandwidth / m_audioSampleRate, ssbFftLen); SSBFilter = new fftfilt(m_LowCutoff / m_audioSampleRate, m_Bandwidth / m_audioSampleRate, ssbFftLen);
DSBFilter = new fftfilt((2*m_Bandwidth) / m_sampleRate, 2*ssbFftLen);
DSPEngine::instance()->addAudioSink(&m_audioFifo); DSPEngine::instance()->addAudioSink(&m_audioFifo);
} }
SSBDemod::~SSBDemod() SSBDemod::~SSBDemod()
{ {
if (SSBFilter) if (SSBFilter) delete SSBFilter;
{ if (DSBFilter) delete DSBFilter;
delete SSBFilter;
}
DSPEngine::instance()->removeAudioSink(&m_audioFifo); DSPEngine::instance()->removeAudioSink(&m_audioFifo);
} }
@ -84,7 +84,7 @@ void SSBDemod::configure(MessageQueue* messageQueue,
void SSBDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly) void SSBDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly)
{ {
Complex ci; Complex ci;
fftfilt::cmplx *sideband, sum; fftfilt::cmplx *sideband;
Real avg; Real avg;
int n_out; int n_out;
@ -101,68 +101,81 @@ void SSBDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
if(m_interpolator.interpolate(&m_sampleDistanceRemain, c, &ci)) if(m_interpolator.interpolate(&m_sampleDistanceRemain, c, &ci))
{ {
n_out = SSBFilter->runSSB(ci, &sideband, m_usb); if (m_dsb)
{
n_out = DSBFilter->runDSB(ci, &sideband);
}
else
{
n_out = SSBFilter->runSSB(ci, &sideband, m_usb);
}
for (int i = 0; i < n_out; i++)
{
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
// smart decimation with bit gain using float arithmetic (23 bits significand)
m_sum += sideband[i];
if (!(m_undersampleCount++ & decim_mask))
{
m_sum /= decim;
m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30);
if (!m_dsb & !m_usb)
{ // invert spectrum for LSB
m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real()));
}
else
{
m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag()));
}
m_sum = 0;
}
if (m_audioBinaual)
{
if (m_audioFlipChannels)
{
m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].imag() * m_volume * 100);
m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].real() * m_volume * 100);
}
else
{
m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].real() * m_volume * 100);
m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].imag() * m_volume * 100);
}
}
else
{
Real demod = (sideband[i].real() + sideband[i].imag()) * 0.7;
qint16 sample = (qint16)(demod * m_volume * 100);
m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample;
}
++m_audioBufferFill;
if (m_audioBufferFill >= m_audioBuffer.size())
{
uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
if (res != m_audioBufferFill)
{
qDebug("lost %u samples", m_audioBufferFill - res);
}
m_audioBufferFill = 0;
}
}
m_sampleDistanceRemain += (Real)m_sampleRate / m_audioSampleRate; m_sampleDistanceRemain += (Real)m_sampleRate / m_audioSampleRate;
} }
else else
{ {
n_out = 0; n_out = 0;
} }
for (int i = 0; i < n_out; i++)
{
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
// smart decimation with bit gain using float arithmetic (23 bits significand)
sum += sideband[i];
if (!(m_undersampleCount++ & decim_mask))
{
Real avgr = sum.real() / decim;
Real avgi = sum.imag() / decim;
m_magsq = (avgr * avgr + avgi * avgi) / (1<<30);
//avg = (sum.real() + sum.imag()) * 0.7 * 32768.0 / decim;
avg = (avgr + avgi) * 0.7;
m_sampleBuffer.push_back(Sample(avg, 0.0));
sum.real() = 0.0;
sum.imag() = 0.0;
}
if (m_audioBinaual)
{
if (m_audioFlipChannels)
{
m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].imag() * m_volume * 100);
m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].real() * m_volume * 100);
}
else
{
m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].real() * m_volume * 100);
m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].imag() * m_volume * 100);
}
}
else
{
Real demod = (sideband[i].real() + sideband[i].imag()) * 0.7;
qint16 sample = (qint16)(demod * m_volume * 100);
m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample;
}
++m_audioBufferFill;
if (m_audioBufferFill >= m_audioBuffer.size())
{
uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
if (res != m_audioBufferFill)
{
qDebug("lost %u samples", m_audioBufferFill - res);
}
m_audioBufferFill = 0;
}
}
} }
if (m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 0) != m_audioBufferFill) if (m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 0) != m_audioBufferFill)
@ -173,7 +186,7 @@ void SSBDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
if(m_sampleSink != 0) if(m_sampleSink != 0)
{ {
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), true); m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), !m_dsb);
} }
m_sampleBuffer.clear(); m_sampleBuffer.clear();
@ -239,6 +252,7 @@ bool SSBDemod::handleMessage(const Message& cmd)
m_interpolator.create(16, m_sampleRate, band * 2.0f); m_interpolator.create(16, m_sampleRate, band * 2.0f);
SSBFilter->create_filter(m_LowCutoff / (float) m_audioSampleRate, m_Bandwidth / (float) m_audioSampleRate); SSBFilter->create_filter(m_LowCutoff / (float) m_audioSampleRate, m_Bandwidth / (float) m_audioSampleRate);
DSBFilter->create_dsb_filter((2*m_Bandwidth) / m_sampleRate);
m_volume = cfg.getVolume(); m_volume = cfg.getVolume();
m_volume *= m_volume * 0.1; m_volume *= m_volume * 0.1;

View File

@ -43,6 +43,7 @@ public:
bool audioFlipChannels, bool audioFlipChannels,
bool dsb); bool dsb);
int getSampleRate() const { return m_sampleRate; }
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
@ -112,6 +113,7 @@ private:
Real m_LowCutoff; Real m_LowCutoff;
Real m_volume; Real m_volume;
int m_spanLog2; int m_spanLog2;
fftfilt::cmplx m_sum;
int m_undersampleCount; int m_undersampleCount;
int m_sampleRate; int m_sampleRate;
int m_frequency; int m_frequency;
@ -125,6 +127,7 @@ private:
Interpolator m_interpolator; Interpolator m_interpolator;
Real m_sampleDistanceRemain; Real m_sampleDistanceRemain;
fftfilt* SSBFilter; fftfilt* SSBFilter;
fftfilt* DSBFilter;
SampleSink* m_sampleSink; SampleSink* m_sampleSink;
SampleVector m_sampleBuffer; SampleVector m_sampleBuffer;

View File

@ -167,7 +167,31 @@ void SSBDemodGUI::on_audioFlipChannels_toggled(bool flip)
void SSBDemodGUI::on_dsb_toggled(bool dsb) void SSBDemodGUI::on_dsb_toggled(bool dsb)
{ {
m_dsb = dsb; m_dsb = dsb;
applySettings();
if (!m_dsb)
{
if (ui->BW->value() < 0) {
m_channelMarker.setSidebands(ChannelMarker::lsb);
} else {
m_channelMarker.setSidebands(ChannelMarker::usb);
}
ui->glSpectrum->setCenterFrequency(m_rate/4);
ui->glSpectrum->setSampleRate(m_rate/2);
ui->glSpectrum->setSsbSpectrum(true);
on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100);
}
else
{
m_channelMarker.setSidebands(ChannelMarker::dsb);
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(m_rate);
ui->glSpectrum->setSsbSpectrum(false);
applySettings();
}
} }
void SSBDemodGUI::on_deltaFrequency_changed(quint64 value) void SSBDemodGUI::on_deltaFrequency_changed(quint64 value)
@ -188,13 +212,17 @@ void SSBDemodGUI::on_BW_valueChanged(int value)
ui->BWText->setText(tr("%1k").arg(s)); ui->BWText->setText(tr("%1k").arg(s));
m_channelMarker.setBandwidth(value * 100 * 2); m_channelMarker.setBandwidth(value * 100 * 2);
if (value < 0) if (!m_dsb)
{ {
m_channelMarker.setSidebands(ChannelMarker::lsb); if (value < 0) {
m_channelMarker.setSidebands(ChannelMarker::lsb);
} else {
m_channelMarker.setSidebands(ChannelMarker::usb);
}
} }
else else
{ {
m_channelMarker.setSidebands(ChannelMarker::usb); m_channelMarker.setSidebands(ChannelMarker::dsb);
} }
on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100);
@ -206,25 +234,18 @@ int SSBDemodGUI::getEffectiveLowCutoff(int lowCutoff)
int effectiveLowCutoff = lowCutoff; int effectiveLowCutoff = lowCutoff;
const int guard = 100; const int guard = 100;
if (ssbBW < 0) if (ssbBW < 0) {
{ if (effectiveLowCutoff < ssbBW + guard) {
if (effectiveLowCutoff < ssbBW + guard)
{
effectiveLowCutoff = ssbBW + guard; effectiveLowCutoff = ssbBW + guard;
} }
if (effectiveLowCutoff > 0) if (effectiveLowCutoff > 0) {
{
effectiveLowCutoff = 0; effectiveLowCutoff = 0;
} }
} } else {
else if (effectiveLowCutoff > ssbBW - guard) {
{
if (effectiveLowCutoff > ssbBW - guard)
{
effectiveLowCutoff = ssbBW - guard; effectiveLowCutoff = ssbBW - guard;
} }
if (effectiveLowCutoff < 0) if (effectiveLowCutoff < 0) {
{
effectiveLowCutoff = 0; effectiveLowCutoff = 0;
} }
} }
@ -323,6 +344,7 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
applySettings(); applySettings();
setNewRate(m_spanLog2);
} }
SSBDemodGUI::~SSBDemodGUI() SSBDemodGUI::~SSBDemodGUI()
@ -339,32 +361,26 @@ SSBDemodGUI::~SSBDemodGUI()
bool SSBDemodGUI::setNewRate(int spanLog2) bool SSBDemodGUI::setNewRate(int spanLog2)
{ {
if ((spanLog2 < 1) || (spanLog2 > 5)) if ((spanLog2 < 0) || (spanLog2 > 6)) {
{
return false; return false;
} }
m_spanLog2 = spanLog2; m_spanLog2 = spanLog2;
m_rate = 48000 / (1<<spanLog2); //m_rate = 48000 / (1<<spanLog2);
m_rate = m_ssbDemod->getSampleRate() / (1<<spanLog2);
if (ui->BW->value() < -m_rate/100) if (ui->BW->value() < -m_rate/100) {
{
ui->BW->setValue(-m_rate/100); ui->BW->setValue(-m_rate/100);
m_channelMarker.setBandwidth(-m_rate*2); m_channelMarker.setBandwidth(-m_rate*2);
} } else if (ui->BW->value() > m_rate/100) {
else if (ui->BW->value() > m_rate/100)
{
ui->BW->setValue(m_rate/100); ui->BW->setValue(m_rate/100);
m_channelMarker.setBandwidth(m_rate*2); m_channelMarker.setBandwidth(m_rate*2);
} }
if (ui->lowCut->value() < -m_rate/100) if (ui->lowCut->value() < -m_rate/100) {
{
ui->lowCut->setValue(-m_rate/100); ui->lowCut->setValue(-m_rate/100);
m_channelMarker.setLowCutoff(-m_rate); m_channelMarker.setLowCutoff(-m_rate);
} } else if (ui->lowCut->value() > m_rate/100) {
else if (ui->lowCut->value() > m_rate/100)
{
ui->lowCut->setValue(m_rate/100); ui->lowCut->setValue(m_rate/100);
m_channelMarker.setLowCutoff(m_rate); m_channelMarker.setLowCutoff(m_rate);
} }
@ -377,8 +393,26 @@ bool SSBDemodGUI::setNewRate(int spanLog2)
QString s = QString::number(m_rate/1000.0, 'f', 1); QString s = QString::number(m_rate/1000.0, 'f', 1);
ui->spanText->setText(tr("%1k").arg(s)); ui->spanText->setText(tr("%1k").arg(s));
ui->glSpectrum->setCenterFrequency(m_rate/2); if (!m_dsb)
ui->glSpectrum->setSampleRate(m_rate); {
if (ui->BW->value() < 0) {
m_channelMarker.setSidebands(ChannelMarker::lsb);
} else {
m_channelMarker.setSidebands(ChannelMarker::usb);
}
ui->glSpectrum->setCenterFrequency(m_rate/4);
ui->glSpectrum->setSampleRate(m_rate/2);
ui->glSpectrum->setSsbSpectrum(true);
}
else
{
m_channelMarker.setSidebands(ChannelMarker::dsb);
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(m_rate);
ui->glSpectrum->setSsbSpectrum(false);
}
return true; return true;
} }

View File

@ -201,6 +201,9 @@
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="autoRaise">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>