mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-03 21:20:31 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			205 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * ctcssdetector.cpp
 | 
						|
 *
 | 
						|
 *  Created on: Jun 16, 2015
 | 
						|
 *      Author: f4exb
 | 
						|
 */
 | 
						|
#include <cmath>
 | 
						|
#include "dsp/ctcssdetector.h"
 | 
						|
 | 
						|
CTCSSDetector::CTCSSDetector() :
 | 
						|
			N(0),
 | 
						|
			sampleRate(0),
 | 
						|
			samplesProcessed(0),
 | 
						|
			maxPowerIndex(0),
 | 
						|
			toneDetected(false),
 | 
						|
			maxPower(0.0)
 | 
						|
{
 | 
						|
	nTones = 32;
 | 
						|
	k = new Real[nTones];
 | 
						|
	coef = new Real[nTones];
 | 
						|
	toneSet = new Real[nTones];
 | 
						|
	u0 = new Real[nTones];
 | 
						|
	u1 = new Real[nTones];
 | 
						|
	power = new Real[nTones];
 | 
						|
 | 
						|
	// The 32 EIA standard tones
 | 
						|
	toneSet[0]  = 67.0;
 | 
						|
	toneSet[1]  = 71.9;
 | 
						|
	toneSet[2]  = 74.4;
 | 
						|
	toneSet[3]  = 77.0;
 | 
						|
	toneSet[4]  = 79.7;
 | 
						|
	toneSet[5]  = 82.5;
 | 
						|
	toneSet[6]  = 85.4;
 | 
						|
	toneSet[7]  = 88.5;
 | 
						|
	toneSet[8]  = 91.5;
 | 
						|
	toneSet[9]  = 94.8;
 | 
						|
	toneSet[10]  = 97.4;
 | 
						|
	toneSet[11] = 100.0;
 | 
						|
	toneSet[12] = 103.5;
 | 
						|
	toneSet[13] = 107.2;
 | 
						|
	toneSet[14] = 110.9;
 | 
						|
	toneSet[15] = 114.8;
 | 
						|
	toneSet[16] = 118.8;
 | 
						|
	toneSet[17] = 123.0;
 | 
						|
	toneSet[18] = 127.3;
 | 
						|
	toneSet[19] = 131.8;
 | 
						|
	toneSet[20] = 136.5;
 | 
						|
	toneSet[21] = 141.3;
 | 
						|
	toneSet[22] = 146.2;
 | 
						|
	toneSet[23] = 151.4;
 | 
						|
	toneSet[24] = 156.7;
 | 
						|
	toneSet[25] = 162.2;
 | 
						|
	toneSet[26] = 167.9;
 | 
						|
	toneSet[27] = 173.8;
 | 
						|
	toneSet[28] = 179.9;
 | 
						|
	toneSet[29] = 186.2;
 | 
						|
	toneSet[30] = 192.8;
 | 
						|
	toneSet[31] = 203.5;
 | 
						|
}
 | 
						|
 | 
						|
CTCSSDetector::CTCSSDetector(int _nTones, Real *tones) :
 | 
						|
			N(0),
 | 
						|
			sampleRate(0),
 | 
						|
			samplesProcessed(0),
 | 
						|
			maxPowerIndex(0),
 | 
						|
			toneDetected(false),
 | 
						|
			maxPower(0.0)
 | 
						|
{
 | 
						|
	nTones = _nTones;
 | 
						|
	k = new Real[nTones];
 | 
						|
	coef = new Real[nTones];
 | 
						|
	toneSet = new Real[nTones];
 | 
						|
	u0 = new Real[nTones];
 | 
						|
	u1 = new Real[nTones];
 | 
						|
	power = new Real[nTones];
 | 
						|
 | 
						|
	for (int j = 0; j < nTones; ++j)
 | 
						|
	{
 | 
						|
		toneSet[j] = tones[j];
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
CTCSSDetector::~CTCSSDetector()
 | 
						|
{
 | 
						|
	delete[] k;
 | 
						|
	delete[] coef;
 | 
						|
	delete[] toneSet;
 | 
						|
	delete[] u0;
 | 
						|
	delete[] u1;
 | 
						|
	delete[] power;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void CTCSSDetector::setCoefficients(int _N, int _samplerate )
 | 
						|
{
 | 
						|
	N = _N;                   // save the basic parameters for use during analysis
 | 
						|
	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;
 | 
						|
	Real aboveAvg = 2.0; // Arbitrary max power above average threshold
 | 
						|
	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);
 | 
						|
}
 |