mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-16 05:11:49 -05:00
169 lines
5.4 KiB
C++
169 lines
5.4 KiB
C++
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
// Copyright (C) 2023 Jon Beniston, M7RCE //
|
||
|
// //
|
||
|
// This program is free software; you can redistribute it and/or modify //
|
||
|
// it under the terms of the GNU General Public License as published by //
|
||
|
// the Free Software Foundation as version 3 of the License, or //
|
||
|
// (at your option) any later version. //
|
||
|
// //
|
||
|
// This program is distributed in the hope that it will be useful, //
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||
|
// GNU General Public License V3 for more details. //
|
||
|
// //
|
||
|
// You should have received a copy of the GNU General Public License //
|
||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include <QDebug>
|
||
|
|
||
|
#include "util/morse.h"
|
||
|
|
||
|
#include "morsedemod.h"
|
||
|
|
||
|
MESSAGE_CLASS_DEFINITION(MorseDemod::MsgReportIdent, Message)
|
||
|
|
||
|
MorseDemod::MorseDemod() :
|
||
|
m_movingAverageIdent(5000),
|
||
|
m_prevBit(0),
|
||
|
m_bitTime(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void MorseDemod::reset()
|
||
|
{
|
||
|
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 = "";
|
||
|
}
|
||
|
|
||
|
void MorseDemod::applyChannelSettings(int channelSampleRate)
|
||
|
{
|
||
|
if (channelSampleRate <= 0) {
|
||
|
return;
|
||
|
}
|
||
|
m_samplesPerDot7wpm = channelSampleRate*60/(50*7);
|
||
|
m_samplesPerDot10wpm = channelSampleRate*60/(50*10);
|
||
|
|
||
|
m_ncoIdent.setFreq(-1020, channelSampleRate); // +-50Hz source offset allowed
|
||
|
m_bandpassIdent.create(1001, channelSampleRate, 970.0f, 1070.0f); // Ident at 1020
|
||
|
|
||
|
m_lowpassIdent.create(301, channelSampleRate, 100.0f);
|
||
|
m_movingAverageIdent.resize(m_samplesPerDot10wpm/5); // Needs to be short enough for noise floor calculation
|
||
|
|
||
|
reset();
|
||
|
}
|
||
|
|
||
|
void MorseDemod::applySettings(int identThreshold)
|
||
|
{
|
||
|
m_identThreshold = identThreshold;
|
||
|
reset();
|
||
|
}
|
||
|
|
||
|
void MorseDemod::processOneSample(const Complex &magc)
|
||
|
{
|
||
|
// 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));
|
||
|
|
||
|
// 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_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() << "MorseDemod::processOneSample:" << m_ident << " " << Morse::toString(m_ident);
|
||
|
|
||
|
if (getMessageQueueToChannel())
|
||
|
{
|
||
|
MorseDemod::MsgReportIdent *msg = MorseDemod::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() << "MorseDemod::processOneSample:" << m_ident << " " << Morse::toString(m_ident);
|
||
|
|
||
|
if (getMessageQueueToChannel())
|
||
|
{
|
||
|
MorseDemod::MsgReportIdent *msg = MorseDemod::MsgReportIdent::create(m_ident);
|
||
|
getMessageQueueToChannel()->push(msg);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
m_ident = "";
|
||
|
m_bitTime = 0;
|
||
|
}
|
||
|
}
|
||
|
m_prevBit = bit;
|
||
|
}
|
||
|
|