kopia lustrzana https://github.com/f4exb/sdrangel
Move Morse demod to separate class to share with ILS.
rodzic
8201bfba20
commit
6e3795d3d0
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "dsp/dspengine.h"
|
||||
#include "dsp/dspcommands.h"
|
||||
#include "dsp/morsedemod.h"
|
||||
#include "device/deviceapi.h"
|
||||
#include "feature/feature.h"
|
||||
#include "settings/serializable.h"
|
||||
|
@ -215,14 +216,14 @@ bool VORDemod::handleMessage(const Message& cmd)
|
|||
|
||||
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();
|
||||
|
||||
if (m_guiMessageQueue)
|
||||
{
|
||||
VORDemodReport::MsgReportIdent *msg = new VORDemodReport::MsgReportIdent(report);
|
||||
MorseDemod::MsgReportIdent *msg = new MorseDemod::MsgReportIdent(report);
|
||||
m_guiMessageQueue->push(msg);
|
||||
}
|
||||
|
||||
|
|
|
@ -136,9 +136,9 @@ bool VORDemodGUI::handleMessage(const Message& message)
|
|||
|
||||
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 identString = Morse::toString(ident); // Convert Morse to a string
|
||||
|
|
|
@ -18,4 +18,4 @@
|
|||
#include "vordemodreport.h"
|
||||
|
||||
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:
|
||||
VORDemodReport() {}
|
||||
~VORDemodReport() {}
|
||||
|
|
|
@ -62,6 +62,7 @@ QByteArray VORDemodSettings::serialize() const
|
|||
s.writeS32(3, m_streamIndex);
|
||||
s.writeS32(4, m_volume*10);
|
||||
s.writeS32(5, m_squelch);
|
||||
s.writeBool(10, m_audioMute);
|
||||
|
||||
if (m_channelMarker) {
|
||||
s.writeBlob(6, m_channelMarker->serialize());
|
||||
|
@ -114,6 +115,7 @@ bool VORDemodSettings::deserialize(const QByteArray& data)
|
|||
m_volume = tmp * 0.1;
|
||||
d.readS32(5, &tmp, -40);
|
||||
m_squelch = tmp;
|
||||
d.readBool(10, &m_audioMute, false);
|
||||
|
||||
if (m_channelMarker)
|
||||
{
|
||||
|
|
|
@ -44,9 +44,6 @@ VORDemodSCSink::VORDemodSCSink() :
|
|||
m_volumeAGC(0.003),
|
||||
m_audioFifo(48000),
|
||||
m_refPrev(0.0f),
|
||||
m_movingAverageIdent(5000),
|
||||
m_prevBit(0),
|
||||
m_bitTime(0),
|
||||
m_varGoertzel(30, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE),
|
||||
m_refGoertzel(30, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE)
|
||||
{
|
||||
|
@ -249,104 +246,14 @@ void VORDemodSCSink::processOneSample(Complex &ci)
|
|||
else
|
||||
m_refGoertzel.filter(phi);
|
||||
|
||||
// Ident demod
|
||||
// Filter to remove voice
|
||||
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));
|
||||
// Decode Morse ident
|
||||
m_morseDemod.processOneSample(magc);
|
||||
}
|
||||
|
||||
// Filter noise with moving average (moving average preserves edges)
|
||||
m_movingAverageIdent(c2.real());
|
||||
Real mav = m_movingAverageIdent.asFloat();
|
||||
|
||||
// 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::setMessageQueueToChannel(MessageQueue *messageQueue)
|
||||
{
|
||||
m_messageQueueToChannel = messageQueue;
|
||||
m_morseDemod.setMessageQueueToChannel(messageQueue);
|
||||
}
|
||||
|
||||
void VORDemodSCSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
|
||||
|
@ -367,30 +274,10 @@ void VORDemodSCSink::applyChannelSettings(int channelSampleRate, int channelFreq
|
|||
m_interpolatorDistanceRemain = 0;
|
||||
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_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_movingAverageIdent.resize(m_samplesPerDot10wpm/5); // Needs to be short enough for noise floor calculation
|
||||
|
||||
m_binSampleCnt = 0;
|
||||
m_binCnt = 0;
|
||||
m_identNoise = 0.0001f;
|
||||
for (int i = 0; i < m_identBins; i++)
|
||||
{
|
||||
m_identMaxs[i] = 0.0f;
|
||||
}
|
||||
m_morseDemod.applyChannelSettings(VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE);
|
||||
}
|
||||
|
||||
m_channelSampleRate = channelSampleRate;
|
||||
|
@ -414,14 +301,7 @@ void VORDemodSCSink::applySettings(const VORDemodSettings& settings, bool force)
|
|||
if (m_settings.m_navId != settings.m_navId)
|
||||
{
|
||||
// Reset state when navId changes, so we don't report old ident for new navId
|
||||
m_binSampleCnt = 0;
|
||||
m_binCnt = 0;
|
||||
m_identNoise = 0.0001f;
|
||||
for (int i = 0; i < m_identBins; i++)
|
||||
{
|
||||
m_identMaxs[i] = 0.0f;
|
||||
}
|
||||
m_ident = "";
|
||||
m_morseDemod.reset();
|
||||
m_refGoertzel.reset();
|
||||
m_varGoertzel.reset();
|
||||
}
|
||||
|
@ -437,6 +317,7 @@ void VORDemodSCSink::applySettings(const VORDemodSettings& settings, bool force)
|
|||
}
|
||||
|
||||
m_settings = settings;
|
||||
m_morseDemod.applySettings(m_settings.m_identThreshold);
|
||||
}
|
||||
|
||||
void VORDemodSCSink::applyAudioSampleRate(int sampleRate)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "dsp/agc.h"
|
||||
#include "dsp/firfilter.h"
|
||||
#include "dsp/goertzel.h"
|
||||
#include "dsp/morsedemod.h"
|
||||
#include "audio/audiofifo.h"
|
||||
#include "util/movingaverage.h"
|
||||
#include "util/doublebufferfifo.h"
|
||||
|
@ -43,7 +44,7 @@ public:
|
|||
|
||||
void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, 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);
|
||||
|
||||
int getAudioSampleRate() const { return m_audioSampleRate; }
|
||||
|
@ -116,28 +117,12 @@ private:
|
|||
AudioFifo m_audioFifo;
|
||||
uint32_t m_audioBufferFill;
|
||||
|
||||
NCO m_ncoIdent;
|
||||
NCO m_ncoRef;
|
||||
Lowpass<Complex> m_lowpassRef;
|
||||
Bandpass<Complex> m_bandpassIdent;
|
||||
Lowpass<Complex> m_lowpassIdent;
|
||||
Highpass<Real> m_highpassIdent;
|
||||
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_refGoertzel;
|
||||
//QFile m_file;
|
||||
//QTextStream m_stream;
|
||||
MorseDemod m_morseDemod;
|
||||
|
||||
void processOneSample(Complex &ci);
|
||||
void processOneAudioSample(Complex &ci);
|
||||
|
|
Ładowanie…
Reference in New Issue