2015-06-15 22:42:37 -04:00
|
|
|
/*
|
|
|
|
* ctcssdetector.cpp
|
|
|
|
*
|
|
|
|
* Created on: Jun 16, 2015
|
|
|
|
* Author: f4exb
|
|
|
|
*/
|
2017-09-15 22:50:25 -04:00
|
|
|
#include <math.h>
|
2015-06-15 22:42:37 -04:00
|
|
|
#include "dsp/ctcssdetector.h"
|
2020-10-31 17:56:12 -04:00
|
|
|
#include "ctcssfrequencies.h"
|
2015-06-15 22:42:37 -04:00
|
|
|
|
2017-09-15 22:50:25 -04:00
|
|
|
#undef M_PI
|
|
|
|
#define M_PI 3.14159265358979323846
|
|
|
|
|
2015-06-15 22:42:37 -04:00
|
|
|
CTCSSDetector::CTCSSDetector() :
|
|
|
|
N(0),
|
|
|
|
sampleRate(0),
|
|
|
|
samplesProcessed(0),
|
|
|
|
maxPowerIndex(0),
|
|
|
|
toneDetected(false),
|
|
|
|
maxPower(0.0)
|
|
|
|
{
|
2020-10-31 17:56:12 -04:00
|
|
|
nTones = CTCSSFrequencies::m_nbFreqs;
|
2015-06-15 22:42:37 -04:00
|
|
|
k = new Real[nTones];
|
|
|
|
coef = new Real[nTones];
|
|
|
|
toneSet = new Real[nTones];
|
|
|
|
u0 = new Real[nTones];
|
|
|
|
u1 = new Real[nTones];
|
|
|
|
power = new Real[nTones];
|
2020-10-31 17:56:12 -04:00
|
|
|
toneSet = CTCSSFrequencies::m_Freqs;
|
2015-06-15 22:42:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
CTCSSDetector::CTCSSDetector(int _nTones, Real *tones) :
|
|
|
|
N(0),
|
|
|
|
sampleRate(0),
|
|
|
|
samplesProcessed(0),
|
|
|
|
maxPowerIndex(0),
|
|
|
|
toneDetected(false),
|
|
|
|
maxPower(0.0)
|
|
|
|
{
|
2020-10-31 17:56:12 -04:00
|
|
|
nTones = CTCSSFrequencies::m_nbFreqs;
|
2015-06-15 22:42:37 -04:00
|
|
|
k = new Real[nTones];
|
|
|
|
coef = new Real[nTones];
|
|
|
|
toneSet = new Real[nTones];
|
|
|
|
u0 = new Real[nTones];
|
|
|
|
u1 = new Real[nTones];
|
|
|
|
power = new Real[nTones];
|
2020-10-31 17:56:12 -04:00
|
|
|
toneSet = CTCSSFrequencies::m_Freqs;
|
2015-06-15 22:42:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CTCSSDetector::~CTCSSDetector()
|
|
|
|
{
|
|
|
|
delete[] k;
|
|
|
|
delete[] coef;
|
|
|
|
delete[] toneSet;
|
|
|
|
delete[] u0;
|
|
|
|
delete[] u1;
|
|
|
|
delete[] power;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-28 04:53:37 -05:00
|
|
|
void CTCSSDetector::setCoefficients(int zN, int _samplerate )
|
2015-06-15 22:42:37 -04:00
|
|
|
{
|
2016-02-28 04:53:37 -05:00
|
|
|
N = zN; // save the basic parameters for use during analysis
|
2015-06-15 22:42:37 -04:00
|
|
|
sampleRate = _samplerate;
|
|
|
|
|
|
|
|
// for each of the frequencies (tones) of interest calculate
|
|
|
|
// k and the associated filter coefficient as per the Goertzel
|
|
|
|
// algorithm. Note: we are using a real value (as apposed to
|
|
|
|
// an integer as described in some references. k is retained
|
|
|
|
// for later display. The tone set is specified in the
|
|
|
|
// constructor. Notice that the resulting coefficients are
|
|
|
|
// independent of N.
|
|
|
|
for (int j = 0; j < nTones; ++j)
|
|
|
|
{
|
|
|
|
k[j] = ((double)N * toneSet[j]) / (double)sampleRate;
|
|
|
|
coef[j] = 2.0 * cos((2.0 * M_PI * toneSet[j])/(double)sampleRate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Analyze an input signal for the presence of CTCSS tones.
|
|
|
|
bool CTCSSDetector::analyze(Real *sample)
|
|
|
|
{
|
|
|
|
|
|
|
|
feedback(*sample); // Goertzel feedback
|
|
|
|
samplesProcessed += 1;
|
|
|
|
|
|
|
|
if (samplesProcessed == N) // completed a block of N
|
|
|
|
{
|
|
|
|
feedForward(); // calculate the power at each tone
|
|
|
|
samplesProcessed = 0;
|
|
|
|
return true; // have a result
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CTCSSDetector::feedback(Real in)
|
|
|
|
{
|
|
|
|
Real t;
|
|
|
|
|
|
|
|
// feedback for each tone
|
|
|
|
for (int j = 0; j < nTones; ++j)
|
|
|
|
{
|
|
|
|
t = u0[j];
|
|
|
|
u0[j] = in + (coef[j] * u0[j]) - u1[j];
|
|
|
|
u1[j] = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CTCSSDetector::feedForward()
|
|
|
|
{
|
|
|
|
initializePower();
|
|
|
|
|
|
|
|
for (int j = 0; j < nTones; ++j)
|
|
|
|
{
|
|
|
|
power[j] = (u0[j] * u0[j]) + (u1[j] * u1[j]) - (coef[j] * u0[j] * u1[j]);
|
|
|
|
u0[j] = u1[j] = 0.0; // reset for next block.
|
|
|
|
}
|
|
|
|
|
|
|
|
evaluatePower();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CTCSSDetector::reset()
|
|
|
|
{
|
|
|
|
for (int j = 0; j < nTones; ++j)
|
|
|
|
{
|
|
|
|
power[j] = u0[j] = u1[j] = 0.0; // reset
|
|
|
|
}
|
|
|
|
|
|
|
|
samplesProcessed = 0;
|
|
|
|
maxPower = 0.0;
|
|
|
|
maxPowerIndex = 0;
|
|
|
|
toneDetected = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CTCSSDetector::initializePower()
|
|
|
|
{
|
|
|
|
for (int j = 0; j < nTones; ++j)
|
|
|
|
{
|
|
|
|
power[j] = 0.0; // reset
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CTCSSDetector::evaluatePower()
|
|
|
|
{
|
|
|
|
Real sumPower = 0.0;
|
2015-06-16 19:51:25 -04:00
|
|
|
Real aboveAvg = 2.0; // Arbitrary max power above average threshold
|
2015-06-15 22:42:37 -04:00
|
|
|
maxPower = 0.0;
|
|
|
|
|
|
|
|
for (int j = 0; j < nTones; ++j)
|
|
|
|
{
|
|
|
|
sumPower += power[j];
|
|
|
|
|
|
|
|
if (power[j] > maxPower)
|
|
|
|
{
|
|
|
|
maxPower = power[j];
|
|
|
|
maxPowerIndex = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
toneDetected = (maxPower > (sumPower/nTones) + aboveAvg);
|
|
|
|
}
|