Implement support for multitone CTCSS SNR offset

New CTCSS configuration variable CTCSS_SNR_OFFSETS (note the plural S) which
replace the old variable with a similar name. The new variable take a comma
separated list of frequency:offset pairs to support the use of multiple
CTCSS tone frequencies. The siglevdetcal utility has also been modified to
output the new variable format. If you are using just one CTCSS frequency
with a previously calibrated offet value you can keep using that. The older
configuration variable will not be removed and it still work in the same
way.
This commit is contained in:
Tobias Blomberg 2022-01-09 11:00:18 +01:00
parent 68a653ef9a
commit d5cd8ce81b
11 changed files with 255 additions and 73 deletions

View File

@ -1,4 +1,4 @@
1.6.1 -- ?? ??? 2021
1.6.1 -- ?? ??? 2022
----------------------
* ASYNC_AUDIO_ALSA_ZEROFILL is now enabled by default.
@ -44,6 +44,12 @@
will be written instead. Enable this behavior by setting the environment
variable ASYNC_AUDIO_UDP_ZEROFILL=1.
* The Config class now also accept associative containers for getValue. This
for example make it possible to use a std::map<float,float> to read a
configuration variable with a list of values on the form
VARNAME=88.5:-1,136.5:1. It is also possible to use other key/value
separators.
1.6.0 -- 01 Sep 2019

View File

@ -325,6 +325,7 @@ class Config
return true;
}
std::stringstream ssval(str_val);
ssval.imbue(std::locale(ssval.getloc(), new csv_whitespace));
while (!ssval.eof())
{
Key tmp;
@ -342,6 +343,77 @@ class Config
return true;
} /* Config::getValue */
/**
* @brief Get value of given config variable into associative container
* @param section The name of the section where the configuration
* variable is located
* @param tag The name of the configuration variable to get
* @param c The value is returned in this argument.
* Successful completion overwrites previous contents
* @param sep The character used to separate key and value
* @param missing_ok If set to \em true, return \em true if the
* configuration variable is missing
* @return Returns \em true on success or else \em false on failure.
*
* This function is used to get the value of a configuraiton variable. The
* config variable is read into an associative container (e.g. std::map or
* std::multimap). It's a template function meaning that it can take any
* key and value type that supports the operator>> function.
* Normally a missing configuration variable is seen as an error and the
* function returns \em false. If the missing_ok parameter is set to \em
* true, this function returns \em true for a missing variable but still
* returns \em false if an illegal value is specified.
*/
template <template <typename, typename, typename, typename> class Container,
class Key, class T, class Compare=std::less<Key>,
class Allocator=std::allocator<std::pair<const Key, T>>>
bool getValue(const std::string& section, const std::string& tag,
Container<Key, T, Compare, Allocator>& c,
char sep = ':', bool missing_ok = false) const
{
std::string str_val;
if (!getValue(section, tag, str_val))
{
return missing_ok;
}
if (str_val.empty())
{
c.clear();
return true;
}
std::stringstream ssval(str_val);
ssval.imbue(std::locale(ssval.getloc(), new csv_whitespace));
while (!ssval.eof())
{
std::string entry;
ssval >> entry;
std::string::size_type seppos = entry.find(sep);
if (seppos == std::string::npos)
{
return false;
}
std::string keystr(entry.substr(0, seppos));
std::string valuestr(entry.substr(seppos+1));
Key key;
T value;
if (!setValueFromString(key, keystr) ||
!setValueFromString(value, valuestr))
{
return false;
}
if(!ssval.eof())
{
ssval >> std::ws;
}
if (ssval.fail())
{
return false;
}
c.insert(std::pair<Key, T>(key, value));
}
return true;
} /* Config::getValue */
/**
* @brief Get a range checked variable value
* @param section The name of the section where the configuration
@ -487,7 +559,19 @@ class Config
char *parseValue(char *value);
char *translateEscapedChars(char *val);
}; /* class Config */
template <class T>
bool setValueFromString(T& val, const std::string &str) const
{
std::istringstream ss(str);
ss >> std::noskipws >> val;
if(!ss.eof())
{
ss >> std::ws;
}
return !ss.fail() && ss.eof();
}
}; /* class Config */
} /* namespace */

View File

@ -951,7 +951,7 @@ The CTCSS squelch detector checks for the presence of a tone with the specified
frequency. The tone frequency is specified using the CTCSS_FQ config variable.
The thresholds are specified using the CTCSS_OPEN_THRESH and CTCSS_CLOSE_THRESH
config variables. Other config variables that effect the CTCSS squelch is:
CTCSS_MODE, CTCSS_SNR_OFFSET, CTCSS_BPF_LOW, CTCSS_BPF_HIGH.
CTCSS_MODE, CTCSS_SNR_OFFSETS, CTCSS_BPF_LOW, CTCSS_BPF_HIGH.
The SERIAL squelch detector use a pin in a serial port to detect if the squelch
is open. This squelch detector can be used if the receiver have an external
@ -1125,36 +1125,45 @@ frequency range (67.0 to 254.1Hz) need to be reasonable flat. When choosing
tones, try to select tones that are close to each other. However, selecting
tones too close may cause both to trigger. Also do not select tones that are a
multiple of another tone since overtones may trigger the wrong one.
If multiple tones are configured when running siglevdetcal, the first one will
be used for the calibration.
.TP
.B CTCSS_OPEN_THRESH
If CTCSS (PL, subtone) squelch is used (SQL_DET is set to CTCSS), this config
variable sets the required tone level to indicate squelch open. The value is
some kind of estimated signal to noise dB value. If using CTCSS mode 2 or 3 it
is helpful to set up the CTCSS_SNR_OFFSET config variable. This will make the
SNR estimation pretty good. Default threshold is 15dB.
some kind of estimated signal to noise dB value. If using CTCSS mode 2, 3 or 4
it is helpful to set up the CTCSS_SNR_OFFSETS config variable. This will make
the SNR estimation pretty good. Default threshold is 15dB.
.TP
.B CTCSS_CLOSE_THRESH
If CTCSS (PL, subtone) squelch is used (SQL_DET is set to CTCSS), this config
variable sets the required tone level to indicate squelch close. The value is
some kind of estimated signal to noise dB value. If using CTCSS mode 2 or 3 it
is helpful to set up the CTCSS_SNR_OFFSET config variable. This will make the
SNR estimation pretty good. Default threshold is 9dB.
some kind of estimated signal to noise dB value. If using CTCSS mode 2, 3 or 4
it is helpful to set up the CTCSS_SNR_OFFSETS config variable. This will make
the SNR estimation pretty good. Default threshold is 9dB.
.TP
.B CTCSS_SNR_OFFSET
This config variable is used when CTCSS_MODE is set to 0, 2 or 3. It will
adjust the estimated SNR value so that it becomes very close to a real SNR
This configuration variable should not be used unless you know why you use it.
Using CTCSS_SNR_OFFSETS is often more appropriate.
.TP
.B CTCSS_SNR_OFFSETS
This config variable is used when CTCSS_MODE is set to 0, 2, 3 or 4. It will
adjust the estimated SNR values so that they become very close to a real SNR
value. This value will have to be adjusted if CTCSS_FQ, CTCSS_MODE,
CTCSS_BPF_LOW or CTCSS_BPF_HIGH changes.
Use the siglevdetcal utility to find out what to set this config variable to.
There is no requirement to set this config variable up. The downside is that
you will then need to experiment more with the CTCSS_OPEN_THRESH and
CTCSS_CLOSE_THRESH config variables to find the correct squelch level.
CTCSS_CLOSE_THRESH config variables to find the correct squelch level. If using
multiple CTCSS frequencies it may not be possible to find good threshold values
due to uneven frequency characteristics for the receiver.
The format for this config variable is a comma separated list of
frequency:offset pairs. The CTCSS_SNR_OFFSET variable may be used as a form of
fallback value that is used if a specific tone frequency in use is missing from
this list.
.TP
.B CTCSS_BPF_LOW
When CTCSS_MODE is set to 0, 2 or 3, this config variable will set the low
When CTCSS_MODE is set to 0, 2, 3 or 4, this config variable will set the low
cutoff frequency for the passband filter. It normally should not have to be
adjusted but could improve the detector if some interference falls within the
passband (e.g. mains hum). Note however that the more narrow you make the
@ -1163,13 +1172,13 @@ increasing the open/close thresholds or by setting up SQL_DELAY and
SQL_HANGTIME. Default is 60Hz.
.TP
.B CTCSS_BPF_HIGH
When CTCSS_MODE is set to 0, 2 or 3, this config variable will set the high
When CTCSS_MODE is set to 0, 2, 3 or 4, this config variable will set the high
cutoff frequency for the passband filter. It normally should not have to be
adjusted but could improve the detector if some interference falls within the
passband. Note however that the more narrow you make the
passband, the less stable the detector will be. You may need to compensate by
increasing the open/close thresholds or by setting up SQL_DELAY and
SQL_HANGTIME. Default is 270Hz.
passband. Note however that the more narrow you make the passband, the less
stable the detector will be. You may need to compensate by increasing the
open/close thresholds or by setting up SQL_DELAY and SQL_HANGTIME. Default is
270Hz.
.TP
.B CTCSS_DEBUG
Set this to 1 to enable continuously printing SNR values for the CTCSS tone
@ -1277,7 +1286,7 @@ Below is a simple example of how to set up a combined squelch.
[Rx1:CTCSS]
SQL_DET=CTCSS
CTCSS_FQ=77.0
CTCSS_SNR_OFFSET=-3.22
CTCSS_SNR_OFFSETS=77.0:-3.22
[Rx1:SIGLEV]
SQL_DET=SIGLEV
@ -2729,7 +2738,7 @@ Before starting the siglevdetcal application, pull the PTT cable since the PTT
might get triggered during the calibration procedure.
The siglevdetcal utility will also measure the CTCSS tone SNR offset so that
the CTCSS_SNR_OFFSET config variable can be set up to a proper value.
the CTCSS_SNR_OFFSETS config variable can be set up to a proper value.
If the siglevdetcal application cannot be used for some reason, the manual
procedure below might be used. This procedure will only work for a

View File

@ -182,6 +182,15 @@
* Improved squelch state logging with more details about the detection.
* New CTCSS configuration variable CTCSS_SNR_OFFSETS (note the plural S) which
replace the old variable with a similar name. The new variable take a comma
separated list of frequency:offset pairs to support the use of multiple
CTCSS tone frequencies. The siglevdetcal utility has also been modified to
output the new variable format. If you are using just one CTCSS frequency
with a previously calibrated offet value you can keep using that. The older
configuration variable will not be removed and it still work in the same
way.
1.7.0 -- 01 Sep 2019

View File

@ -68,6 +68,7 @@ VOX_THRESH=1000
#CTCSS_MODE=2
CTCSS_FQ=136.5
#CTCSS_SNR_OFFSET=0
#CTCSS_SNR_OFFSETS=88.5:-1.0,136.5:-0.5
#CTCSS_OPEN_THRESH=15
#CTCSS_CLOSE_THRESH=9
#CTCSS_BPF_LOW=60
@ -167,6 +168,7 @@ VOX_THRESH=1000
#CTCSS_MODE=2
CTCSS_FQ=136.5
#CTCSS_SNR_OFFSET=0
#CTCSS_SNR_OFFSETS=88.5:-1.0,136.5:-0.5
#CTCSS_OPEN_THRESH=15
#CTCSS_CLOSE_THRESH=9
#CTCSS_BPF_LOW=60

View File

@ -1,5 +1,6 @@
#include <iostream>
#include <cstdlib>
#include <map>
#include <AsyncCppApplication.h>
#include <AsyncConfig.h>
@ -17,6 +18,12 @@ using namespace Async;
#define PROGRAM_NAME "SigLevDetCal"
struct CtcssMeasurement
{
double sum = 0.0;
size_t count = 0;
};
static const int INTERVAL = 100;
static const int ITERATIONS = 150;
@ -26,10 +33,9 @@ static double open_sum = 0.0f;
static double close_sum = 0.0f;
static float siglev_slope = 10.0;
static float siglev_offset = 0.0;
static double ctcss_snr_sum = 0.0;
static unsigned ctcss_snr_cnt = 0;
static float ctcss_open_snr = 0.0f;
static float ctcss_close_snr = 0.0f;
static std::map<float, CtcssMeasurement> ctcss_snr_sum;
static std::map<float, float> ctcss_open_snr;
static std::map<float, float> ctcss_close_snr;
#if 0
@ -89,34 +95,48 @@ void sample_squelch_close(Timer *t)
float new_siglev_slope = 100.0 / open_close_mean;
float new_siglev_offset = -close_mean * new_siglev_slope;
if (ctcss_snr_cnt > 0)
for (const auto& entry : ctcss_snr_sum)
{
ctcss_close_snr = ctcss_snr_sum / ctcss_snr_cnt;
ctcss_close_snr[entry.first] = entry.second.sum / entry.second.count;
}
cout << endl;
cout << "--- Results\n";
printf("Mean SNR for the CTCSS tone : ");
if (ctcss_snr_cnt > 0)
printf("Mean SNR for the CTCSS tones : ");
if (!ctcss_close_snr.empty())
{
printf("%.1fdB\n",
ctcss_open_snr - ctcss_close_snr);
printf("\n");
for (const auto& entry : ctcss_close_snr)
{
float snr = ctcss_open_snr[entry.first] - entry.second;
printf(" %5.1f : %+5.1fdB\n", entry.first, snr);
}
}
else
{
printf("N/A (CTCSS not enabled)\n");
}
printf("Dynamic range for the siglev measurement : %.1fdB\n",
10.0 * open_close_mean);
//printf("Dynamic range for the siglev measurement : %.1fdB\n",
// 10.0 * open_close_mean);
cout << endl;
cout << "--- Put the config variables below in the configuration file\n";
cout << "--- section for " << rx->name() << ".\n";
printf("SIGLEV_SLOPE=%.2f\n", new_siglev_slope);
printf("SIGLEV_OFFSET=%.2f\n", new_siglev_offset);
if (ctcss_snr_cnt > 0)
if (!ctcss_close_snr.empty())
{
printf("CTCSS_SNR_OFFSET=%.2f\n", ctcss_close_snr);
printf("CTCSS_SNR_OFFSETS=");
for (auto it = ctcss_close_snr.begin();
it != ctcss_close_snr.end(); ++it)
{
if (it->first != ctcss_close_snr.begin()->first)
{
printf(",");
}
printf("%.1f:%+.2f", it->first, it->second);
}
printf("\n");
}
cout << endl;
@ -140,12 +160,9 @@ void start_squelch_close_measurement(FdWatch *w)
cout << "--- Starting squelch close measurement\n";
delete w;
ctcss_snr_sum = 0.0;
ctcss_snr_cnt = 0;
ctcss_snr_sum.clear();
Timer *timer = new Timer(INTERVAL);
// must explicitly specify name space for ptr_fun() to avoid conflict
// with ptr_fun() in /usr/include/c++/4.5/bits/stl_function.h
timer->expired.connect(sigc::ptr_fun(&sample_squelch_close));
}
} /* start_squelch_close_measurement */
@ -163,9 +180,9 @@ void sample_squelch_open(Timer *t)
{
delete t;
if (ctcss_snr_cnt > 0)
for (const auto& entry : ctcss_snr_sum)
{
ctcss_open_snr = ctcss_snr_sum / ctcss_snr_cnt;
ctcss_open_snr[entry.first] = entry.second.sum / entry.second.count;
}
FdWatch *w = new FdWatch(0, FdWatch::FD_WATCH_RD);
@ -195,8 +212,7 @@ void start_squelch_open_measurement(FdWatch *w)
{
cout << "--- Starting squelch open measurement\n";
delete w;
ctcss_snr_sum = 0.0;
ctcss_snr_cnt = 0;
ctcss_snr_sum.clear();
Timer *timer = new Timer(INTERVAL);
// must explicitly specify name space for ptr_fun() to avoid conflict
// with ptr_fun() in /usr/include/c++/4.5/bits/stl_function.h
@ -208,8 +224,9 @@ void start_squelch_open_measurement(FdWatch *w)
void ctcss_snr_updated(float snr, float fq)
{
ctcss_snr_sum += snr;
ctcss_snr_cnt += 1;
auto& measurement = ctcss_snr_sum[fq];
measurement.sum += snr;
measurement.count += 1;
}

View File

@ -201,6 +201,7 @@ VOX_THRESH=1000
#CTCSS_MODE=2
CTCSS_FQ=136.5
#CTCSS_SNR_OFFSET=0
#CTCSS_SNR_OFFSETS=88.5:-1.0,136.5:-0.5
#CTCSS_OPEN_THRESH=15
#CTCSS_CLOSE_THRESH=9
#CTCSS_BPF_LOW=60

View File

@ -395,7 +395,7 @@ bool LocalRxBase::initialize(void)
}
// Create a splitter to distribute full bandwidth audio to all consumers
AudioSplitter *fullband_splitter = new AudioSplitter;
fullband_splitter = new AudioSplitter;
prev_src->registerSink(fullband_splitter, true);
prev_src = fullband_splitter;
@ -774,6 +774,17 @@ void LocalRxBase::reset(void)
} /* LocalRxBase::reset */
void LocalRxBase::registerFullbandSink(Async::AudioSink* sink)
{
fullband_splitter->addSink(sink);
} /* LocalRxBase::registerFullbandSink */
void LocalRxBase::unregisterFullbandSink(Async::AudioSink* sink)
{
fullband_splitter->removeSink(sink);
} /* LocalRxBase::unregisterFullbandSink */
/****************************************************************************
*

View File

@ -186,6 +186,32 @@ class LocalRxBase : public Rx
*/
virtual void reset(void);
/**
* @brief Register a fullband (unfiltered) audio sink
* @param sink The sink to register
*
* Use this function to register a sink for handling fullband audio, that
* is receiver audio that is not filtered. This can be used to get access
* to audio outside of the voice band, in theory 0 to 8000 Hz.
*/
void registerFullbandSink(Async::AudioSink* sink);
/**
* @brief Unregister a fullband (unfiltered) audio sink
* @param sink The sink to unregister
*
* Use this function to unregister a sink for handling fullband audio.
* See the documentation for the registerFullbandSink() function for more
* information.
*/
void unregisterFullbandSink(Async::AudioSink* sink);
/**
* @bried Get the squelch detector associated with this receiver
* @returns Returns a pointer to the squelch detector or nullptr if none
*/
Squelch* squelchDetector(void) { return squelch_det; }
/**
* @brief A signal that is emitted when the CTCSS tone SNR has changed
* @param snr The current SNR
@ -255,6 +281,7 @@ class LocalRxBase : public Rx
HdlcDeframer * ob_afsk_deframer;
HdlcDeframer * ib_afsk_deframer;
bool audio_dev_keep_open;
Async::AudioSplitter * fullband_splitter;
int audioRead(float *samples, int count);
void dtmfDigitActivated(char digit);

View File

@ -39,6 +39,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <iomanip>
#include <vector>
#include <cmath>
#include <map>
/****************************************************************************
@ -158,9 +159,11 @@ class SquelchCtcss : public Squelch
int ctcss_mode = 0;
cfg.getValue(rx_name, "CTCSS_MODE", ctcss_mode);
cfg.getValue(rx_name, "CTCSS_SNR_OFFSET", m_ctcss_snr_offset);
float ctcss_snr_offset = 0.0f;
cfg.getValue(rx_name, "CTCSS_SNR_OFFSET", ctcss_snr_offset);
cfg.getValue(rx_name, "CTCSS_SNR_OFFSETS", m_ctcss_snr_offsets);
float open_thresh = 15.0f;
float close_thresh = 9.0f;
if (cfg.getValue(rx_name, "CTCSS_THRESH", open_thresh))
@ -179,9 +182,21 @@ class SquelchCtcss : public Squelch
close_thresh = open_thresh;
}
open_thresh += m_ctcss_snr_offset;
close_thresh += m_ctcss_snr_offset;
std::map<float, float> open_threshs;
std::map<float, float> close_threshs;
for (auto ctcss_fq : ctcss_fqs)
{
if (m_ctcss_snr_offsets.count(ctcss_fq) == 0)
{
m_ctcss_snr_offsets[ctcss_fq] = ctcss_snr_offset;
}
//std::cout << "### f=" << ctcss_fq
// << " offset=" << m_ctcss_snr_offsets[ctcss_fq]
// << std::endl;
open_threshs[ctcss_fq] = open_thresh + m_ctcss_snr_offsets[ctcss_fq];
close_threshs[ctcss_fq] = close_thresh + m_ctcss_snr_offsets[ctcss_fq];
}
unsigned bpf_low = 60;
cfg.getValue(rx_name, "CTCSS_BPF_LOW", bpf_low);
if ((bpf_low < 50) || (bpf_low > 300))
@ -233,8 +248,8 @@ class SquelchCtcss : public Squelch
case 1:
{
//std::cout << "### CTCSS mode: Neighbour bins\n";
det->setDetectPeakThresh(open_thresh);
det->setUndetectPeakThresh(close_thresh);
det->setDetectPeakThresh(open_threshs[ctcss_fq]);
det->setUndetectPeakThresh(close_threshs[ctcss_fq]);
break;
}
@ -245,7 +260,7 @@ class SquelchCtcss : public Squelch
det->setDetectBw(16.0f);
det->setDetectPeakThresh(0.0f);
//det->setDetectPeakToTotPwrThresh(0.6f);
det->setDetectSnrThresh(open_thresh, bpf_high - bpf_low);
det->setDetectSnrThresh(open_threshs[ctcss_fq], bpf_high - bpf_low);
det->setDetectStableCountThresh(1);
det->setDetectPhaseBwThresh(2.0f, 2.0f);
@ -253,7 +268,7 @@ class SquelchCtcss : public Squelch
det->setUndetectUseWindowing(false);
det->setUndetectPeakThresh(0.0f);
//det->setUndetectPeakToTotPwrThresh(0.3f);
det->setUndetectSnrThresh(close_thresh, bpf_high - bpf_low);
det->setUndetectSnrThresh(close_threshs[ctcss_fq], bpf_high - bpf_low);
det->setUndetectStableCountThresh(2);
//det->setUndetectPhaseBwThresh(4.0f, 16.0f);
@ -280,14 +295,14 @@ class SquelchCtcss : public Squelch
det->setDetectToneFrequencyTolerancePercent(TONE_FQ_TOLERANCE);
det->setDetectUseWindowing(USE_WINDOWING);
det->setDetectPeakThresh(0.0f);
det->setDetectSnrThresh(open_thresh, bpf_high - bpf_low);
det->setDetectSnrThresh(open_threshs[ctcss_fq], bpf_high - bpf_low);
det->setUndetectBw(8.0f);
det->setUndetectOverlapPercent(OVERLAP_PERCENT);
det->setUndetectDelay(100);
det->setUndetectUseWindowing(USE_WINDOWING);
det->setUndetectPeakThresh(0.0f);
det->setUndetectSnrThresh(close_thresh, bpf_high - bpf_low);
det->setUndetectSnrThresh(close_threshs[ctcss_fq], bpf_high - bpf_low);
// Set up CTCSS band pass filter
Async::AudioFilter *filter =
@ -305,14 +320,14 @@ class SquelchCtcss : public Squelch
det->setDetectUseWindowing(false);
det->setDetectPeakThresh(0.0f);
//det->setDetectPeakToTotPwrThresh(0.6f);
det->setDetectSnrThresh(open_thresh, bpf_high - bpf_low);
det->setDetectSnrThresh(open_threshs[ctcss_fq], bpf_high - bpf_low);
det->setDetectStableCountThresh(1);
//det->setUndetectBw(8.0f);
det->setUndetectUseWindowing(false);
det->setUndetectPeakThresh(0.0f);
//det->setUndetectPeakToTotPwrThresh(0.3f);
det->setUndetectSnrThresh(close_thresh, bpf_high - bpf_low);
det->setUndetectSnrThresh(close_threshs[ctcss_fq], bpf_high - bpf_low);
det->setUndetectStableCountThresh(2);
// Set up CTCSS band pass filter
@ -408,7 +423,7 @@ class SquelchCtcss : public Squelch
DetList m_dets;
Async::AudioSplitter* m_splitter = nullptr;
ToneDetector* m_active_det = nullptr;
float m_ctcss_snr_offset = 0.0f;
std::map<float, float> m_ctcss_snr_offsets;
bool m_debug = false;
std::unique_ptr<Async::Timer> m_dbg_timer = nullptr;
@ -430,7 +445,7 @@ class SquelchCtcss : public Squelch
ss << std::showpos << fq_err;
}
ss << ":" << static_cast<int>(
std::roundf(det->lastSnr() - m_ctcss_snr_offset));
std::roundf(det->lastSnr() - m_ctcss_snr_offsets[det->toneFq()]));
if (is_detected)
{
if (m_active_det == 0)
@ -466,16 +481,17 @@ class SquelchCtcss : public Squelch
void printDebug(void)
{
std::ostringstream os;
os << rxName() << ": ";
os << rxName() << ":";
for (auto det : m_dets)
{
float snr = det->lastSnr() - m_ctcss_snr_offset;
float snr = det->lastSnr() - m_ctcss_snr_offsets[det->toneFq()];
os << std::setw(4) << static_cast<int>(roundf(snr))
<< ":" << std::fixed << std::setprecision(1) << det->toneFq();
<< ":" << std::fixed << std::setprecision(1) << std::noshowpos
<< det->toneFq();
if (det->toneFqEstimate() > 0.0)
{
float fq_err = det->toneFqEstimate() - det->toneFq();
os << std::showpos << fq_err;
os << std::showpos << std::setw(5) << fq_err;
}
}
std::cout << os.str() << std::endl;

View File

@ -8,10 +8,10 @@ QTEL=1.2.4.99.5
LIBECHOLIB=1.3.3.99.0
# Version for the Async library
LIBASYNC=1.6.99.16
LIBASYNC=1.6.99.17
# SvxLink versions
SVXLINK=1.7.99.54
SVXLINK=1.7.99.55
MODULE_HELP=1.0.0
MODULE_PARROT=1.1.1
MODULE_ECHO_LINK=1.5.99.2
@ -25,13 +25,13 @@ MODULE_FRN=1.1.0
MODULE_TRX=1.0.0
# Version for the RemoteTrx application
REMOTE_TRX=1.3.99.6
REMOTE_TRX=1.3.99.7
# Version for the signal level calibration utility
SIGLEV_DET_CAL=1.0.7.99.3
SIGLEV_DET_CAL=1.0.7.99.4
# Version for the deviation calibration utility
DEVCAL=1.0.2.99.4
DEVCAL=1.0.2.99.5
# Version for svxserver
SVXSERVER=0.0.6