Demod Analyzer: implementation for the rest of planned plugins

This commit is contained in:
f4exb 2020-12-21 02:30:29 +01:00
parent e8ea0665fe
commit 793d8b9f49
41 changed files with 363 additions and 27 deletions

View File

@ -30,7 +30,7 @@
const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = {
DSDDemod::m_channelId,
QStringLiteral("DSD Demodulator"),
QStringLiteral("6.3.3"),
QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -12,7 +12,7 @@
const PluginDescriptor NFMPlugin::m_pluginDescriptor = {
NFMDemod::m_channelId,
QStringLiteral("NFM Demodulator"),
QStringLiteral("6.3.3"),
QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -58,6 +58,7 @@ SSBDemod::SSBDemod(DeviceAPI *deviceAPI) :
m_thread = new QThread(this);
m_basebandSink = new SSBDemodBaseband();
m_basebandSink->setSpectrumSink(&m_spectrumVis);
m_basebandSink->setChannel(this);
m_basebandSink->moveToThread(m_thread);
applySettings(m_settings, true);

View File

@ -63,6 +63,11 @@ void SSBDemodBaseband::reset()
m_sampleFifo.reset();
}
void SSBDemodBaseband::setChannel(ChannelAPI *channel)
{
m_sink.setChannel(channel);
}
void SSBDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
{
m_sampleFifo.write(begin, end);
@ -198,4 +203,4 @@ void SSBDemodBaseband::setBasebandSampleRate(int sampleRate)
{
m_channelizer->setBasebandSampleRate(sampleRate);
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
}
}

View File

@ -28,6 +28,7 @@
#include "ssbdemodsink.h"
class DownChannelizer;
class ChannelAPI;
class SSBDemodBaseband : public QObject
{
@ -69,6 +70,7 @@ public:
bool getAudioActive() const { return m_sink.getAudioActive(); }
void setBasebandSampleRate(int sampleRate);
void setMessageQueueToGUI(MessageQueue *messageQueue) { m_messageQueueToGUI = messageQueue; }
void setChannel(ChannelAPI *channel);
private:
SampleSinkFifo m_sampleFifo;
@ -90,4 +92,4 @@ private slots:
void handleData(); //!< Handle data when samples have to be processed
};
#endif // INCLUDE_SSBDEMODBASEBAND_H
#endif // INCLUDE_SSBDEMODBASEBAND_H

View File

@ -25,8 +25,11 @@
#include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h"
#include "dsp/basebandsamplesink.h"
#include "dsp/datafifo.h"
#include "device/deviceapi.h"
#include "util/db.h"
#include "util/messagequeue.h"
#include "maincore.h"
#include "ssbdemodsink.h"
@ -62,6 +65,9 @@ SSBDemodSink::SSBDemodSink() :
m_undersampleCount = 0;
m_sum = 0;
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
m_usb = true;
m_magsq = 0.0f;
m_magsqSum = 0.0f;
@ -194,6 +200,25 @@ void SSBDemodSink::processOneSample(Complex &ci)
m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample;
}
m_demodBuffer[m_demodBufferFill] = (z.real() + z.imag()) * 0.7;
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
}
++m_audioBufferFill;
@ -279,6 +304,19 @@ void SSBDemodSink::applyAudioSampleRate(int sampleRate)
m_audioFifo.setSize(sampleRate);
m_audioSampleRate = sampleRate;
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate);
(*it)->push(msg);
}
}
}
void SSBDemodSink::applySettings(const SSBDemodSettings& settings, bool force)

View File

@ -18,7 +18,7 @@
#ifndef INCLUDE_SSBDEMODSINK_H
#define INCLUDE_SSBDEMODSINK_H
#include <vector>
#include <QVector>
#include "dsp/channelsamplesink.h"
#include "dsp/ncof.h"
@ -31,6 +31,7 @@
#include "ssbdemodsettings.h"
class BasebandSampleSink;
class ChannelAPI;
class SSBDemodSink : public ChannelSampleSink {
public:
@ -47,6 +48,7 @@ public:
AudioFifo *getAudioFifo() { return &m_audioFifo; }
double getMagSq() const { return m_magsq; }
bool getAudioActive() const { return m_audioActive; }
void setChannel(ChannelAPI *channel) { m_channel = channel; }
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
{
@ -78,6 +80,7 @@ private:
};
SSBDemodSettings m_settings;
ChannelAPI *m_channel;
Real m_Bandwidth;
Real m_LowCutoff;
@ -121,10 +124,13 @@ private:
AudioFifo m_audioFifo;
quint32 m_audioSampleRate;
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
static const int m_ssbFftLen;
static const int m_agcTarget;
void processOneSample(Complex &ci);
};
#endif // INCLUDE_SSBDEMODSINK_H
#endif // INCLUDE_SSBDEMODSINK_H

View File

@ -12,7 +12,7 @@
const PluginDescriptor SSBPlugin::m_pluginDescriptor = {
SSBDemod::m_channelId,
QStringLiteral("SSB Demodulator"),
QStringLiteral("6.3.3"),
QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -59,6 +59,7 @@ WFMDemod::WFMDemod(DeviceAPI* deviceAPI) :
m_thread = new QThread(this);
m_basebandSink = new WFMDemodBaseband();
m_basebandSink->setChannel(this);
m_basebandSink->moveToThread(m_thread);
applySettings(m_settings, true);

View File

@ -58,6 +58,11 @@ void WFMDemodBaseband::reset()
m_sampleFifo.reset();
}
void WFMDemodBaseband::setChannel(ChannelAPI *channel)
{
m_sink.setChannel(channel);
}
void WFMDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
{
m_sampleFifo.write(begin, end);

View File

@ -28,6 +28,7 @@
#include "wfmdemodsink.h"
class DownChannelizer;
class ChannelAPI;
class WFMDemodBaseband : public QObject
{
@ -69,6 +70,7 @@ public:
bool getSquelchOpen() const { return m_sink.getSquelchOpen(); }
int getSquelchState() const { return m_sink.getSquelchState(); }
void getMagSqLevels(double& avg, double& peak, int& nbSamples) { m_sink.getMagSqLevels(avg, peak, nbSamples); }
void setChannel(ChannelAPI *channel);
private:
SampleSinkFifo m_sampleFifo;

View File

@ -25,7 +25,10 @@
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h"
#include "dsp/datafifo.h"
#include "util/db.h"
#include "util/messagequeue.h"
#include "maincore.h"
#include "wfmdemodsink.h"
@ -35,6 +38,7 @@ WFMDemodSink::WFMDemodSink() :
m_channelSampleRate(384000),
m_channelFrequencyOffset(0),
m_audioSampleRate(48000),
m_squelchState(0),
m_squelchOpen(false),
m_magsq(0.0f),
m_magsqSum(0.0f),
@ -48,6 +52,9 @@ WFMDemodSink::WFMDemodSink() :
m_audioBuffer.resize(16384);
m_audioBufferFill = 0;
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
applySettings(m_settings, true);
applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
}
@ -130,6 +137,24 @@ void WFMDemodSink::feed(const SampleVector::const_iterator& begin, const SampleV
}
m_interpolatorDistanceRemain += m_interpolatorDistance;
m_demodBuffer[m_demodBufferFill] = sample;
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
}
}
}
@ -162,6 +187,19 @@ void WFMDemodSink::applyAudioSampleRate(int sampleRate)
m_interpolatorDistanceRemain = (Real) m_channelSampleRate / sampleRate;
m_interpolatorDistance = (Real) m_channelSampleRate / (Real) sampleRate;
m_audioSampleRate = sampleRate;
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate);
(*it)->push(msg);
}
}
}
void WFMDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
@ -186,8 +224,8 @@ void WFMDemodSink::applyChannelSettings(int channelSampleRate, int channelFreque
Real lowCut = -(m_settings.m_rfBandwidth / 2.0) / channelSampleRate;
Real hiCut = (m_settings.m_rfBandwidth / 2.0) / channelSampleRate;
m_rfFilter->create_filter(lowCut, hiCut);
m_fmExcursion = m_settings.m_rfBandwidth / (Real) channelSampleRate;
m_phaseDiscri.setFMScaling(1.0f/m_fmExcursion);
//m_fmExcursion = m_settings.m_rfBandwidth / (Real) channelSampleRate;
m_phaseDiscri.setFMScaling((float) channelSampleRate / ((float) 2*m_fmExcursion));
qDebug("WFMDemod::applySettings: m_fmExcursion: %f", m_fmExcursion);
}
@ -224,8 +262,10 @@ void WFMDemodSink::applySettings(const WFMDemodSettings& settings, bool force)
Real lowCut = -(settings.m_rfBandwidth / 2.0) / m_channelSampleRate;
Real hiCut = (settings.m_rfBandwidth / 2.0) / m_channelSampleRate;
m_rfFilter->create_filter(lowCut, hiCut);
m_fmExcursion = settings.m_rfBandwidth / (Real) m_channelSampleRate;
m_phaseDiscri.setFMScaling(1.0f/m_fmExcursion);
m_fmExcursion = (settings.m_rfBandwidth / 2) - m_settings.m_afBandwidth;
m_fmExcursion = m_fmExcursion < 2500 ? 2500 : m_fmExcursion;
//m_fmExcursion = settings.m_rfBandwidth / (Real) m_channelSampleRate;
m_phaseDiscri.setFMScaling((float) m_channelSampleRate / ((float) 2*m_fmExcursion));
qDebug("WFMDemodSink::applySettings: m_fmExcursion: %f", m_fmExcursion);
}

View File

@ -18,7 +18,7 @@
#ifndef INCLUDE_WFMDEMODSINK_H
#define INCLUDE_WFMDEMODSINK_H
#include <vector>
#include <QVector>
#include "dsp/channelsamplesink.h"
#include "dsp/nco.h"
@ -32,6 +32,8 @@
#include "wfmdemodsettings.h"
class ChannelAPI;
class WFMDemodSink : public ChannelSampleSink {
public:
WFMDemodSink();
@ -67,6 +69,7 @@ public:
AudioFifo *getAudioFifo() { return &m_audioFifo; }
void applyAudioSampleRate(int sampleRate);
int getAudioSampleRate() const { return m_audioSampleRate; }
void setChannel(ChannelAPI *channel) { m_channel = channel; }
private:
struct MagSqLevelsStore
@ -87,6 +90,7 @@ private:
int m_channelSampleRate;
int m_channelFrequencyOffset;
WFMDemodSettings m_settings;
ChannelAPI *m_channel;
int m_audioSampleRate;
@ -115,6 +119,9 @@ private:
SampleVector m_sampleBuffer;
PhaseDiscriminators m_phaseDiscri;
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
static const unsigned int m_rfFilterFftLength;
};

View File

@ -13,7 +13,7 @@
const PluginDescriptor WFMPlugin::m_pluginDescriptor = {
WFMDemod::m_channelId,
QStringLiteral("WFM Demodulator"),
QStringLiteral("6.3.3"),
QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -343,7 +343,6 @@ void AMModSource::applyFeedbackAudioSampleRate(int sampleRate)
qDebug("AMModSource::applyFeedbackAudioSampleRate: %u", sampleRate);
m_feedbackInterpolatorDistanceRemain = 0;
m_feedbackInterpolatorConsumed = false;
m_feedbackInterpolatorDistance = (Real) sampleRate / (Real) m_audioSampleRate;
Real cutoff = std::min(sampleRate, m_audioSampleRate) / 2.2f;
m_feedbackInterpolator.create(48, sampleRate, cutoff, 3.0);

View File

@ -85,7 +85,6 @@ private:
Interpolator m_feedbackInterpolator;
Real m_feedbackInterpolatorDistance;
Real m_feedbackInterpolatorDistanceRemain;
bool m_feedbackInterpolatorConsumed;
double m_magsq;
MovingAverageUtil<double, double, 16> m_movingAverage;

View File

@ -66,6 +66,7 @@ NFMMod::NFMMod(DeviceAPI *deviceAPI) :
m_thread = new QThread(this);
m_basebandSource = new NFMModBaseband();
m_basebandSource->setInputFileStream(&m_ifstream);
m_basebandSource->setChannel(this);
m_basebandSource->moveToThread(m_thread);
applySettings(m_settings, true);

View File

@ -62,6 +62,11 @@ void NFMModBaseband::reset()
m_sampleFifo.reset();
}
void NFMModBaseband::setChannel(ChannelAPI *channel)
{
m_source.setChannel(channel);
}
void NFMModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples)
{
unsigned int part1Begin, part1End, part2Begin, part2End;
@ -226,4 +231,4 @@ void NFMModBaseband::applySettings(const NFMModSettings& settings, bool force)
int NFMModBaseband::getChannelSampleRate() const
{
return m_channelizer->getChannelSampleRate();
}
}

View File

@ -28,6 +28,7 @@
#include "nfmmodsource.h"
class UpChannelizer;
class ChannelAPI;
class NFMModBaseband : public QObject
{
@ -69,6 +70,7 @@ public:
void setInputFileStream(std::ifstream *ifstream) { m_source.setInputFileStream(ifstream); }
AudioFifo *getAudioFifo() { return m_source.getAudioFifo(); }
AudioFifo *getFeedbackAudioFifo() { return m_source.getFeedbackAudioFifo(); }
void setChannel(ChannelAPI *channel);
signals:
/**

View File

@ -28,7 +28,7 @@
const PluginDescriptor NFMModPlugin::m_pluginDescriptor = {
NFMMod::m_channelId,
QStringLiteral("NFM Modulator"),
QStringLiteral("6.3.3"),
QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -17,6 +17,10 @@
#include <QDebug>
#include "dsp/datafifo.h"
#include "util/messagequeue.h"
#include "maincore.h"
#include "nfmmodsource.h"
const int NFMModSource::m_levelNbSamples = 480; // every 10ms
@ -44,6 +48,9 @@ NFMModSource::NFMModSource() :
m_feedbackAudioBuffer.resize(1<<14);
m_feedbackAudioBufferFill = 0;
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
m_magsq = 0.0;
applySettings(m_settings, true);
@ -132,7 +139,7 @@ void NFMModSource::pullAudio(unsigned int nbSamplesAudio)
void NFMModSource::modulateSample()
{
Real t0, t;
Real t0, t1, t;
pullAF(t0);
m_preemphasisFilter.process(t0, t);
@ -144,11 +151,13 @@ void NFMModSource::modulateSample()
calculateLevel(t);
if (m_settings.m_ctcssOn) {
m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * (0.85f * m_bandpass.filter(t) + 0.15f * 0.625f * m_ctcssNco.next()) * 1.33f;
t1 = (0.85f * m_bandpass.filter(t) + 0.15f * 0.625f * m_ctcssNco.next()) * 1.2f;
} else {
m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * m_bandpass.filter(t) * 1.33f;
t1 = m_bandpass.filter(t) * 1.2f;
}
m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * t1;
// limit phasor range to ]-pi,pi]
if (m_modPhasor > M_PI) {
m_modPhasor -= (2.0f * M_PI);
@ -156,6 +165,25 @@ void NFMModSource::modulateSample()
m_modSample.real(cos(m_modPhasor) * 0.891235351562f * SDR_TX_SCALEF); // -1 dB
m_modSample.imag(sin(m_modPhasor) * 0.891235351562f * SDR_TX_SCALEF);
m_demodBuffer[m_demodBufferFill] = t1 * std::numeric_limits<int16_t>::max();
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
}
void NFMModSource::pullAF(Real& sample)
@ -321,6 +349,19 @@ void NFMModSource::applyAudioSampleRate(int sampleRate)
m_preemphasisFilter.configure(m_preemphasis*sampleRate);
m_audioSampleRate = sampleRate;
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate);
(*it)->push(msg);
}
}
}
void NFMModSource::applyFeedbackAudioSampleRate(int sampleRate)

View File

@ -20,6 +20,7 @@
#include <QObject>
#include <QMutex>
#include <QVector>
#include <iostream>
#include <fstream>
@ -36,6 +37,8 @@
#include "nfmmodsettings.h"
class ChannelAPI;
class NFMModSource : public QObject, public ChannelSampleSource
{
Q_OBJECT
@ -54,6 +57,7 @@ public:
void applyFeedbackAudioSampleRate(int sampleRate);
int getAudioSampleRate() const { return m_audioSampleRate; }
int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; }
void setChannel(ChannelAPI *channel) { m_channel = channel; }
CWKeyer& getCWKeyer() { return m_cwKeyer; }
double getMagSq() const { return m_magsq; }
void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const
@ -69,6 +73,7 @@ private:
int m_channelSampleRate;
int m_channelFrequencyOffset;
NFMModSettings m_settings;
ChannelAPI *m_channel;
NCO m_carrierNco;
NCOF m_toneNco;
@ -86,6 +91,9 @@ private:
Real m_feedbackInterpolatorDistanceRemain;
bool m_feedbackInterpolatorConsumed;
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
Lowpass<Real> m_lowpass;
Bandpass<Real> m_bandpass;
HighPassFilterRC m_preemphasisFilter;

View File

@ -64,6 +64,7 @@ PacketMod::PacketMod(DeviceAPI *deviceAPI) :
m_thread = new QThread(this);
m_basebandSource = new PacketModBaseband();
m_basebandSource->setSpectrumSampleSink(&m_spectrumVis);
m_basebandSource->setChannel(this);
m_basebandSource->moveToThread(m_thread);
applySettings(m_settings, true);

View File

@ -56,6 +56,11 @@ void PacketModBaseband::reset()
m_sampleFifo.reset();
}
void PacketModBaseband::setChannel(ChannelAPI *channel)
{
m_source.setChannel(channel);
}
void PacketModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples)
{
unsigned int part1Begin, part1End, part2Begin, part2End;

View File

@ -29,6 +29,7 @@
#include "packetmodsource.h"
class UpChannelizer;
class ChannelAPI;
class PacketModBaseband : public QObject
{
@ -65,7 +66,7 @@ public:
double getMagSq() const { return m_source.getMagSq(); }
int getChannelSampleRate() const;
void setSpectrumSampleSink(BasebandSampleSink* sampleSink) { m_source.setSpectrumSink(sampleSink); }
void setChannel(ChannelAPI *channel);
signals:
/**

View File

@ -29,7 +29,7 @@
const PluginDescriptor PacketModPlugin::m_pluginDescriptor = {
PacketMod::m_channelId,
QStringLiteral("Packet Modulator"),
QStringLiteral("6.3.3"),
QStringLiteral("6.4.0"),
QStringLiteral("(c) Jon Beniston, M7RCE"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -20,8 +20,11 @@
#include <QDebug>
#include "dsp/basebandsamplesink.h"
#include "dsp/datafifo.h"
#include "packetmodsource.h"
#include "util/crc.h"
#include "util/messagequeue.h"
#include "maincore.h"
PacketModSource::PacketModSource() :
m_channelSampleRate(48000),
@ -46,6 +49,10 @@ PacketModSource::PacketModSource() :
qDebug() << "PacketModSource::PacketModSource creating BPF : " << m_channelSampleRate;
m_bandpass.create(301, m_channelSampleRate, 800.0, 2600.0);
m_pulseShape.create(0.5, 6, m_channelSampleRate/9600);
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
applySettings(m_settings, true);
applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
}
@ -266,6 +273,25 @@ void PacketModSource::modulateSample()
Real s = std::real(m_modSample);
calculateLevel(s);
}
m_demodBuffer[m_demodBufferFill] = audioMod * std::numeric_limits<int16_t>::max();
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
}
void PacketModSource::calculateLevel(Real& sample)
@ -383,6 +409,19 @@ void PacketModSource::applyChannelSettings(int channelSampleRate, int channelFre
qDebug() << "m_samplesPerSymbol: " << m_samplesPerSymbol << " (" << m_channelSampleRate << "/" << m_settings.m_baud << ")";
// Precalculate FM sensensity to save doing it in the loop
m_phaseSensitivity = 2.0f * M_PI * m_settings.m_fmDeviation / (double)m_channelSampleRate;
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, m_channelSampleRate);
(*it)->push(msg);
}
}
}
static uint8_t *ax25_address(uint8_t *p, QString address, uint8_t crrl)

View File

@ -21,6 +21,7 @@
#include <QMutex>
#include <QDebug>
#include <QVector>
#include <iostream>
#include <fstream>
@ -44,6 +45,7 @@
#define AX25_NO_L3 0xf0
class BasebandSampleSink;
class ChannelAPI;
class PacketModSource : public ChannelSampleSource
{
@ -66,12 +68,14 @@ public:
void applySettings(const PacketModSettings& settings, bool force = false);
void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false);
void addTXPacket(QString callsign, QString to, QString via, QString data);
void setChannel(ChannelAPI *channel) { m_channel = channel; }
private:
int m_channelSampleRate;
int m_channelFrequencyOffset;
int m_spectrumRate;
PacketModSettings m_settings;
ChannelAPI *m_channel;
NCO m_carrierNco;
Real m_audioPhase;
@ -126,6 +130,9 @@ private:
std::ofstream m_audioFile; // For debug output of baseband waveform
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
bool bitsValid(); // Are there and bits to transmit
int getBit(); // Get bit from m_bits
void addBit(int bit); // Add bit to m_bits, with zero stuffing

View File

@ -67,6 +67,7 @@ SSBMod::SSBMod(DeviceAPI *deviceAPI) :
m_basebandSource = new SSBModBaseband();
m_basebandSource->setSpectrumSink(&m_spectrumVis);
m_basebandSource->setInputFileStream(&m_ifstream);
m_basebandSource->setChannel(this);
m_basebandSource->moveToThread(m_thread);
applySettings(m_settings, true);

View File

@ -63,6 +63,11 @@ void SSBModBaseband::reset()
m_sampleFifo.reset();
}
void SSBModBaseband::setChannel(ChannelAPI *channel)
{
m_source.setChannel(channel);
}
void SSBModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples)
{
unsigned int part1Begin, part1End, part2Begin, part2End;

View File

@ -30,6 +30,7 @@
class UpChannelizer;
class BasebandSampleSink;
class SpectrumVis;
class ChannelAPI;
class SSBModBaseband : public QObject
{
@ -72,6 +73,7 @@ public:
AudioFifo *getAudioFifo() { return m_source.getAudioFifo(); }
AudioFifo *getFeedbackAudioFifo() { return m_source.getFeedbackAudioFifo(); }
void setSpectrumSink(SpectrumVis *sampleSink) { m_spectrumVis = sampleSink; m_source.setSpectrumSink((BasebandSampleSink *) sampleSink); }
void setChannel(ChannelAPI *channel);
signals:
/**

View File

@ -28,7 +28,7 @@
const PluginDescriptor SSBModPlugin::m_pluginDescriptor = {
SSBMod::m_channelId,
QStringLiteral("SSB Modulator"),
QStringLiteral("6.3.3"),
QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -19,6 +19,10 @@
#include "dsp/basebandsamplesink.h"
#include "dsp/misc.h"
#include "dsp/datafifo.h"
#include "util/messagequeue.h"
#include "maincore.h"
#include "ssbmodsource.h"
const int SSBModSource::m_ssbFftLen = 1024;
@ -51,6 +55,9 @@ SSBModSource::SSBModSource() :
m_feedbackAudioBuffer.resize(1<<14);
m_feedbackAudioBufferFill = 0;
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
m_sum.real(0.0f);
m_sum.imag(0.0f);
m_undersampleCount = 0;
@ -163,6 +170,26 @@ void SSBModSource::modulateSample()
}
calculateLevel(m_modSample);
// take projection on real axis
m_demodBuffer[m_demodBufferFill] = m_modSample.real() * std::numeric_limits<int16_t>::max();
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
}
void SSBModSource::pullAF(Complex& sample)
@ -574,6 +601,19 @@ void SSBModSource::applyAudioSampleRate(int sampleRate)
m_audioSampleRate = sampleRate;
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate);
(*it)->push(msg);
}
}
}
void SSBModSource::applyFeedbackAudioSampleRate(int sampleRate)

View File

@ -20,6 +20,7 @@
#include <QObject>
#include <QMutex>
#include <QVector>
#include <iostream>
#include <fstream>
@ -36,6 +37,7 @@
#include "ssbmodsettings.h"
class BasebandSampleSink;
class ChannelAPI;
class SSBModSource : public QObject, public ChannelSampleSource
{
@ -55,6 +57,7 @@ public:
void applyFeedbackAudioSampleRate(int sampleRate);
int getAudioSampleRate() const { return m_audioSampleRate; }
int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; }
void setChannel(ChannelAPI *channel) { m_channel = channel; }
CWKeyer& getCWKeyer() { return m_cwKeyer; }
double getMagSq() const { return m_magsq; }
void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const
@ -71,6 +74,7 @@ private:
int m_channelSampleRate;
int m_channelFrequencyOffset;
SSBModSettings m_settings;
ChannelAPI *m_channel;
NCOF m_carrierNco;
NCOF m_toneNco;
@ -86,6 +90,9 @@ private:
Real m_feedbackInterpolatorDistanceRemain;
bool m_feedbackInterpolatorConsumed;
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
fftfilt* m_SSBFilter;
fftfilt* m_DSBFilter;
Complex* m_SSBFilterBuffer;

View File

@ -64,6 +64,7 @@ WFMMod::WFMMod(DeviceAPI *deviceAPI) :
m_thread = new QThread(this);
m_basebandSource = new WFMModBaseband();
m_basebandSource->setInputFileStream(&m_ifstream);
m_basebandSource->setChannel(this);
m_basebandSource->moveToThread(m_thread);
applySettings(m_settings, true);

View File

@ -61,6 +61,11 @@ void WFMModBaseband::reset()
m_sampleFifo.reset();
}
void WFMModBaseband::setChannel(ChannelAPI *channel)
{
m_source.setChannel(channel);
}
void WFMModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples)
{
unsigned int part1Begin, part1End, part2Begin, part2End;
@ -209,4 +214,4 @@ void WFMModBaseband::applySettings(const WFMModSettings& settings, bool force)
int WFMModBaseband::getChannelSampleRate() const
{
return m_channelizer->getChannelSampleRate();
}
}

View File

@ -28,6 +28,7 @@
#include "wfmmodsource.h"
class UpChannelizer;
class ChannelAPI;
class WFMModBaseband : public QObject
{
@ -68,6 +69,7 @@ public:
int getChannelSampleRate() const;
void setInputFileStream(std::ifstream *ifstream) { m_source.setInputFileStream(ifstream); }
AudioFifo *getAudioFifo() { return m_source.getAudioFifo(); }
void setChannel(ChannelAPI *channel);
signals:
/**

View File

@ -28,7 +28,7 @@
const PluginDescriptor WFMModPlugin::m_pluginDescriptor = {
WFMMod::m_channelId,
QStringLiteral("WFM Modulator"),
QStringLiteral("6.3.3"),
QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -16,6 +16,10 @@
#include <QDebug>
#include "dsp/datafifo.h"
#include "util/messagequeue.h"
#include "maincore.h"
#include "wfmmodsource.h"
const int WFMModSource::m_rfFilterFFTLength = 1024;
@ -46,6 +50,8 @@ WFMModSource::WFMModSource() :
m_magsq = 0.0;
m_feedbackAudioBuffer.resize(1<<14);
m_feedbackAudioBufferFill = 0;
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
applySettings(m_settings, true);
applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
@ -140,6 +146,25 @@ void WFMModSource::pullOne(Sample& sample)
sample.m_real = (FixReal) ci.real();
sample.m_imag = (FixReal) ci.imag();
m_demodBuffer[m_demodBufferFill] = t * std::numeric_limits<int16_t>::max();
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
}
void WFMModSource::modulateAudio()
@ -237,13 +262,13 @@ void WFMModSource::pullAF(Real& sample)
if (m_cwKeyer.getSample())
{
m_cwKeyer.getCWSmoother().getFadeSample(true, fadeFactor);
sample = m_cwToneNco.next() * m_settings.m_volumeFactor * fadeFactor;
sample = m_cwToneNco.next() * m_settings.m_volumeFactor * fadeFactor * 0.99f;
}
else
{
if (m_cwKeyer.getCWSmoother().getFadeSample(false, fadeFactor))
{
sample = m_cwToneNco.next() * m_settings.m_volumeFactor * fadeFactor;
sample = m_cwToneNco.next() * m_settings.m_volumeFactor * fadeFactor * 0.99f;
}
else
{
@ -339,6 +364,19 @@ void WFMModSource::applyAudioSampleRate(int sampleRate)
m_cwKeyer.reset();
m_audioSampleRate = sampleRate;
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate);
(*it)->push(msg);
}
}
}
void WFMModSource::applyFeedbackAudioSampleRate(int sampleRate)

View File

@ -20,6 +20,7 @@
#include <QObject>
#include <QMutex>
#include <QVector>
#include <iostream>
#include <fstream>
@ -35,6 +36,8 @@
#include "wfmmodsettings.h"
class ChannelAPI;
class WFMModSource : public QObject, public ChannelSampleSource
{
Q_OBJECT
@ -53,6 +56,7 @@ public:
void applyFeedbackAudioSampleRate(int sampleRate);
int getAudioSampleRate() const { return m_audioSampleRate; }
int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; }
void setChannel(ChannelAPI *channel) { m_channel = channel; }
CWKeyer& getCWKeyer() { return m_cwKeyer; }
double getMagSq() const { return m_magsq; }
void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const
@ -68,6 +72,7 @@ private:
int m_channelSampleRate;
int m_channelFrequencyOffset;
WFMModSettings m_settings;
ChannelAPI *m_channel;
NCO m_carrierNco;
NCOF m_toneNco;
@ -85,6 +90,9 @@ private:
Real m_feedbackInterpolatorDistanceRemain;
bool m_feedbackInterpolatorConsumed;
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
fftfilt* m_rfFilter;
static const int m_rfFilterFFTLength;
fftfilt::cmplx *m_rfFilterBuffer;

View File

@ -27,6 +27,12 @@ const QStringList DemodAnalyzerSettings::m_channelTypes = {
QStringLiteral("AMMod"),
QStringLiteral("DSDDemod"),
QStringLiteral("NFMDemod"),
QStringLiteral("NFMMod"),
QStringLiteral("PacketMod"),
QStringLiteral("SSBDemod"),
QStringLiteral("SSBMod"),
QStringLiteral("WFMDemod"),
QStringLiteral("WFMMod"),
};
const QStringList DemodAnalyzerSettings::m_channelURIs = {
@ -34,6 +40,12 @@ const QStringList DemodAnalyzerSettings::m_channelURIs = {
QStringLiteral("sdrangel.channeltx.modam"),
QStringLiteral("sdrangel.channel.dsddemod"),
QStringLiteral("sdrangel.channel.nfmdemod"),
QStringLiteral("sdrangel.channeltx.modnfm"),
QStringLiteral("sdrangel.channeltx.modpacket"),
QStringLiteral("sdrangel.channel.ssbdemod"),
QStringLiteral("sdrangel.channeltx.modssb"),
QStringLiteral("sdrangel.channel.wfmdemod"),
QStringLiteral("sdrangel.channeltx.modwfm"),
};
DemodAnalyzerSettings::DemodAnalyzerSettings() :