mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-16 13:21:50 -05:00
Move Morse demod to separate class to share with ILS.
This commit is contained in:
parent
8201bfba20
commit
6e3795d3d0
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include "dsp/dspengine.h"
|
#include "dsp/dspengine.h"
|
||||||
#include "dsp/dspcommands.h"
|
#include "dsp/dspcommands.h"
|
||||||
|
#include "dsp/morsedemod.h"
|
||||||
#include "device/deviceapi.h"
|
#include "device/deviceapi.h"
|
||||||
#include "feature/feature.h"
|
#include "feature/feature.h"
|
||||||
#include "settings/serializable.h"
|
#include "settings/serializable.h"
|
||||||
@ -215,14 +216,14 @@ bool VORDemod::handleMessage(const Message& cmd)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (VORDemodReport::MsgReportIdent::match(cmd))
|
else if (MorseDemod::MsgReportIdent::match(cmd))
|
||||||
{
|
{
|
||||||
VORDemodReport::MsgReportIdent& report = (VORDemodReport::MsgReportIdent&) cmd;
|
MorseDemod::MsgReportIdent& report = (MorseDemod::MsgReportIdent&) cmd;
|
||||||
m_morseIdent = report.getIdent();
|
m_morseIdent = report.getIdent();
|
||||||
|
|
||||||
if (m_guiMessageQueue)
|
if (m_guiMessageQueue)
|
||||||
{
|
{
|
||||||
VORDemodReport::MsgReportIdent *msg = new VORDemodReport::MsgReportIdent(report);
|
MorseDemod::MsgReportIdent *msg = new MorseDemod::MsgReportIdent(report);
|
||||||
m_guiMessageQueue->push(msg);
|
m_guiMessageQueue->push(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,9 +136,9 @@ bool VORDemodGUI::handleMessage(const Message& message)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (VORDemodReport::MsgReportIdent::match(message))
|
else if (MorseDemod::MsgReportIdent::match(message))
|
||||||
{
|
{
|
||||||
VORDemodReport::MsgReportIdent& report = (VORDemodReport::MsgReportIdent&) message;
|
MorseDemod::MsgReportIdent& report = (MorseDemod::MsgReportIdent&) message;
|
||||||
|
|
||||||
QString ident = report.getIdent();
|
QString ident = report.getIdent();
|
||||||
QString identString = Morse::toString(ident); // Convert Morse to a string
|
QString identString = Morse::toString(ident); // Convert Morse to a string
|
||||||
|
@ -18,4 +18,4 @@
|
|||||||
#include "vordemodreport.h"
|
#include "vordemodreport.h"
|
||||||
|
|
||||||
MESSAGE_CLASS_DEFINITION(VORDemodReport::MsgReportRadial, Message)
|
MESSAGE_CLASS_DEFINITION(VORDemodReport::MsgReportRadial, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(VORDemodReport::MsgReportIdent, Message)
|
|
||||||
|
@ -53,27 +53,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgReportIdent : public Message {
|
|
||||||
MESSAGE_CLASS_DECLARATION
|
|
||||||
|
|
||||||
public:
|
|
||||||
QString getIdent() const { return m_ident; }
|
|
||||||
|
|
||||||
static MsgReportIdent* create(QString ident)
|
|
||||||
{
|
|
||||||
return new MsgReportIdent(ident);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_ident;
|
|
||||||
|
|
||||||
MsgReportIdent(QString ident) :
|
|
||||||
Message(),
|
|
||||||
m_ident(ident)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VORDemodReport() {}
|
VORDemodReport() {}
|
||||||
~VORDemodReport() {}
|
~VORDemodReport() {}
|
||||||
|
@ -62,6 +62,7 @@ QByteArray VORDemodSettings::serialize() const
|
|||||||
s.writeS32(3, m_streamIndex);
|
s.writeS32(3, m_streamIndex);
|
||||||
s.writeS32(4, m_volume*10);
|
s.writeS32(4, m_volume*10);
|
||||||
s.writeS32(5, m_squelch);
|
s.writeS32(5, m_squelch);
|
||||||
|
s.writeBool(10, m_audioMute);
|
||||||
|
|
||||||
if (m_channelMarker) {
|
if (m_channelMarker) {
|
||||||
s.writeBlob(6, m_channelMarker->serialize());
|
s.writeBlob(6, m_channelMarker->serialize());
|
||||||
@ -114,6 +115,7 @@ bool VORDemodSettings::deserialize(const QByteArray& data)
|
|||||||
m_volume = tmp * 0.1;
|
m_volume = tmp * 0.1;
|
||||||
d.readS32(5, &tmp, -40);
|
d.readS32(5, &tmp, -40);
|
||||||
m_squelch = tmp;
|
m_squelch = tmp;
|
||||||
|
d.readBool(10, &m_audioMute, false);
|
||||||
|
|
||||||
if (m_channelMarker)
|
if (m_channelMarker)
|
||||||
{
|
{
|
||||||
|
@ -44,9 +44,6 @@ VORDemodSCSink::VORDemodSCSink() :
|
|||||||
m_volumeAGC(0.003),
|
m_volumeAGC(0.003),
|
||||||
m_audioFifo(48000),
|
m_audioFifo(48000),
|
||||||
m_refPrev(0.0f),
|
m_refPrev(0.0f),
|
||||||
m_movingAverageIdent(5000),
|
|
||||||
m_prevBit(0),
|
|
||||||
m_bitTime(0),
|
|
||||||
m_varGoertzel(30, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE),
|
m_varGoertzel(30, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE),
|
||||||
m_refGoertzel(30, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE)
|
m_refGoertzel(30, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE)
|
||||||
{
|
{
|
||||||
@ -249,104 +246,14 @@ void VORDemodSCSink::processOneSample(Complex &ci)
|
|||||||
else
|
else
|
||||||
m_refGoertzel.filter(phi);
|
m_refGoertzel.filter(phi);
|
||||||
|
|
||||||
// Ident demod
|
// Decode Morse ident
|
||||||
// Filter to remove voice
|
m_morseDemod.processOneSample(magc);
|
||||||
Complex c1 = m_bandpassIdent.filter(magc);
|
}
|
||||||
// Remove ident sub-carrier offset
|
|
||||||
c1 *= m_ncoIdent.nextIQ();
|
|
||||||
// Filter other signals
|
|
||||||
Complex c2 = std::abs(m_lowpassIdent.filter(c1));
|
|
||||||
|
|
||||||
// Filter noise with moving average (moving average preserves edges)
|
void VORDemodSCSink::setMessageQueueToChannel(MessageQueue *messageQueue)
|
||||||
m_movingAverageIdent(c2.real());
|
{
|
||||||
Real mav = m_movingAverageIdent.asFloat();
|
m_messageQueueToChannel = messageQueue;
|
||||||
|
m_morseDemod.setMessageQueueToChannel(messageQueue);
|
||||||
// Caclulate noise floor
|
|
||||||
if (mav > m_identMaxs[m_binCnt])
|
|
||||||
m_identMaxs[m_binCnt] = mav;
|
|
||||||
m_binSampleCnt++;
|
|
||||||
if (m_binSampleCnt >= m_samplesPerDot10wpm/4)
|
|
||||||
{
|
|
||||||
// Calc minimum of maximums
|
|
||||||
m_identNoise = 1.0f;
|
|
||||||
for (int i = 0; i < m_identBins; i++)
|
|
||||||
{
|
|
||||||
m_identNoise = std::min(m_identNoise, m_identMaxs[i]);
|
|
||||||
}
|
|
||||||
m_binSampleCnt = 0;
|
|
||||||
m_binCnt++;
|
|
||||||
if (m_binCnt == m_identBins)
|
|
||||||
m_binCnt = 0;
|
|
||||||
m_identMaxs[m_binCnt] = 0.0f;
|
|
||||||
|
|
||||||
// Prevent divide by zero
|
|
||||||
if (m_identNoise == 0.0f)
|
|
||||||
m_identNoise = 1e-20f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CW demod
|
|
||||||
int bit = (mav / m_identNoise) >= m_settings.m_identThreshold;
|
|
||||||
//m_stream << mav << "," << m_identNoise << "," << bit << "," << (mav / m_identNoise) << "\n";
|
|
||||||
if ((m_prevBit == 0) && (bit == 1))
|
|
||||||
{
|
|
||||||
if (m_bitTime > 7*m_samplesPerDot10wpm)
|
|
||||||
{
|
|
||||||
if (m_ident.trimmed().size() > 2) // Filter out noise that may appear as one or two characters
|
|
||||||
{
|
|
||||||
qDebug() << "VORDemodSCSink::processOneSample:" << m_ident << " " << Morse::toString(m_ident);
|
|
||||||
|
|
||||||
if (getMessageQueueToChannel())
|
|
||||||
{
|
|
||||||
VORDemodReport::MsgReportIdent *msg = VORDemodReport::MsgReportIdent::create(m_ident);
|
|
||||||
getMessageQueueToChannel()->push(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_ident = "";
|
|
||||||
}
|
|
||||||
else if (m_bitTime > 2.5*m_samplesPerDot10wpm)
|
|
||||||
{
|
|
||||||
m_ident.append(" ");
|
|
||||||
}
|
|
||||||
m_bitTime = 0;
|
|
||||||
}
|
|
||||||
else if (bit == 1)
|
|
||||||
{
|
|
||||||
m_bitTime++;
|
|
||||||
}
|
|
||||||
else if ((m_prevBit == 1) && (bit == 0))
|
|
||||||
{
|
|
||||||
if (m_bitTime > 2*m_samplesPerDot10wpm)
|
|
||||||
{
|
|
||||||
m_ident.append("-");
|
|
||||||
}
|
|
||||||
else if (m_bitTime > 0.2*m_samplesPerDot10wpm)
|
|
||||||
{
|
|
||||||
m_ident.append(".");
|
|
||||||
}
|
|
||||||
m_bitTime = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_bitTime++;
|
|
||||||
if (m_bitTime > 10*m_samplesPerDot7wpm)
|
|
||||||
{
|
|
||||||
m_ident = m_ident.simplified();
|
|
||||||
if (m_ident.trimmed().size() > 2) // Filter out noise that may appear as one or two characters
|
|
||||||
{
|
|
||||||
qDebug() << "VORDemodSCSink::processOneSample:" << m_ident << " " << Morse::toString(m_ident);
|
|
||||||
|
|
||||||
if (getMessageQueueToChannel())
|
|
||||||
{
|
|
||||||
VORDemodReport::MsgReportIdent *msg = VORDemodReport::MsgReportIdent::create(m_ident);
|
|
||||||
getMessageQueueToChannel()->push(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
m_ident = "";
|
|
||||||
m_bitTime = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_prevBit = bit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VORDemodSCSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
|
void VORDemodSCSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
|
||||||
@ -367,30 +274,10 @@ void VORDemodSCSink::applyChannelSettings(int channelSampleRate, int channelFreq
|
|||||||
m_interpolatorDistanceRemain = 0;
|
m_interpolatorDistanceRemain = 0;
|
||||||
m_interpolatorDistance = (Real) channelSampleRate / (Real) VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE;
|
m_interpolatorDistance = (Real) channelSampleRate / (Real) VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE;
|
||||||
|
|
||||||
m_samplesPerDot7wpm = VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE*60/(50*7);
|
|
||||||
m_samplesPerDot10wpm = VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE*60/(50*10);
|
|
||||||
|
|
||||||
m_ncoIdent.setFreq(-1020, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE); // +-50Hz source offset allowed
|
|
||||||
m_ncoRef.setFreq(-9960, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE);
|
m_ncoRef.setFreq(-9960, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE);
|
||||||
m_bandpassIdent.create(1001, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE, 970.0f, 1070.0f); // Ident at 1020
|
|
||||||
//m_bandpassIdent.printTaps("bpf");
|
|
||||||
m_highpassIdent.create(1001, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE, 900.0f);
|
|
||||||
//m_highpassIdent.printTaps("hpf");
|
|
||||||
//m_file.setFileName("morse.txt");
|
|
||||||
//m_file.open(QIODevice::WriteOnly);
|
|
||||||
//m_stream.setDevice(&m_file);
|
|
||||||
|
|
||||||
m_lowpassIdent.create(301, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE, 100.0f);
|
|
||||||
m_lowpassRef.create(301, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE, 600.0f); // Max deviation is 480Hz
|
m_lowpassRef.create(301, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE, 600.0f); // Max deviation is 480Hz
|
||||||
m_movingAverageIdent.resize(m_samplesPerDot10wpm/5); // Needs to be short enough for noise floor calculation
|
|
||||||
|
|
||||||
m_binSampleCnt = 0;
|
m_morseDemod.applyChannelSettings(VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE);
|
||||||
m_binCnt = 0;
|
|
||||||
m_identNoise = 0.0001f;
|
|
||||||
for (int i = 0; i < m_identBins; i++)
|
|
||||||
{
|
|
||||||
m_identMaxs[i] = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_channelSampleRate = channelSampleRate;
|
m_channelSampleRate = channelSampleRate;
|
||||||
@ -414,14 +301,7 @@ void VORDemodSCSink::applySettings(const VORDemodSettings& settings, bool force)
|
|||||||
if (m_settings.m_navId != settings.m_navId)
|
if (m_settings.m_navId != settings.m_navId)
|
||||||
{
|
{
|
||||||
// Reset state when navId changes, so we don't report old ident for new navId
|
// Reset state when navId changes, so we don't report old ident for new navId
|
||||||
m_binSampleCnt = 0;
|
m_morseDemod.reset();
|
||||||
m_binCnt = 0;
|
|
||||||
m_identNoise = 0.0001f;
|
|
||||||
for (int i = 0; i < m_identBins; i++)
|
|
||||||
{
|
|
||||||
m_identMaxs[i] = 0.0f;
|
|
||||||
}
|
|
||||||
m_ident = "";
|
|
||||||
m_refGoertzel.reset();
|
m_refGoertzel.reset();
|
||||||
m_varGoertzel.reset();
|
m_varGoertzel.reset();
|
||||||
}
|
}
|
||||||
@ -437,6 +317,7 @@ void VORDemodSCSink::applySettings(const VORDemodSettings& settings, bool force)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_settings = settings;
|
m_settings = settings;
|
||||||
|
m_morseDemod.applySettings(m_settings.m_identThreshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VORDemodSCSink::applyAudioSampleRate(int sampleRate)
|
void VORDemodSCSink::applyAudioSampleRate(int sampleRate)
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "dsp/agc.h"
|
#include "dsp/agc.h"
|
||||||
#include "dsp/firfilter.h"
|
#include "dsp/firfilter.h"
|
||||||
#include "dsp/goertzel.h"
|
#include "dsp/goertzel.h"
|
||||||
|
#include "dsp/morsedemod.h"
|
||||||
#include "audio/audiofifo.h"
|
#include "audio/audiofifo.h"
|
||||||
#include "util/movingaverage.h"
|
#include "util/movingaverage.h"
|
||||||
#include "util/doublebufferfifo.h"
|
#include "util/doublebufferfifo.h"
|
||||||
@ -43,7 +44,7 @@ public:
|
|||||||
|
|
||||||
void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false);
|
void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false);
|
||||||
void applySettings(const VORDemodSettings& settings, bool force = false);
|
void applySettings(const VORDemodSettings& settings, bool force = false);
|
||||||
void setMessageQueueToChannel(MessageQueue *messageQueue) { m_messageQueueToChannel = messageQueue; }
|
void setMessageQueueToChannel(MessageQueue *messageQueue);
|
||||||
void applyAudioSampleRate(int sampleRate);
|
void applyAudioSampleRate(int sampleRate);
|
||||||
|
|
||||||
int getAudioSampleRate() const { return m_audioSampleRate; }
|
int getAudioSampleRate() const { return m_audioSampleRate; }
|
||||||
@ -116,28 +117,12 @@ private:
|
|||||||
AudioFifo m_audioFifo;
|
AudioFifo m_audioFifo;
|
||||||
uint32_t m_audioBufferFill;
|
uint32_t m_audioBufferFill;
|
||||||
|
|
||||||
NCO m_ncoIdent;
|
|
||||||
NCO m_ncoRef;
|
NCO m_ncoRef;
|
||||||
Lowpass<Complex> m_lowpassRef;
|
Lowpass<Complex> m_lowpassRef;
|
||||||
Bandpass<Complex> m_bandpassIdent;
|
|
||||||
Lowpass<Complex> m_lowpassIdent;
|
|
||||||
Highpass<Real> m_highpassIdent;
|
|
||||||
Complex m_refPrev;
|
Complex m_refPrev;
|
||||||
MovingAverageUtilVar<Real, double> m_movingAverageIdent;
|
|
||||||
static const int m_identBins = 20;
|
|
||||||
Real m_identMaxs[m_identBins];
|
|
||||||
Real m_identNoise;
|
|
||||||
int m_binSampleCnt;
|
|
||||||
int m_binCnt;
|
|
||||||
int m_samplesPerDot7wpm;
|
|
||||||
int m_samplesPerDot10wpm;
|
|
||||||
int m_prevBit;
|
|
||||||
int m_bitTime;
|
|
||||||
QString m_ident;
|
|
||||||
Goertzel m_varGoertzel;
|
Goertzel m_varGoertzel;
|
||||||
Goertzel m_refGoertzel;
|
Goertzel m_refGoertzel;
|
||||||
//QFile m_file;
|
MorseDemod m_morseDemod;
|
||||||
//QTextStream m_stream;
|
|
||||||
|
|
||||||
void processOneSample(Complex &ci);
|
void processOneSample(Complex &ci);
|
||||||
void processOneAudioSample(Complex &ci);
|
void processOneAudioSample(Complex &ci);
|
||||||
|
Loading…
Reference in New Issue
Block a user