1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-05-01 03:44:00 -04:00

Freq Scanner voice squelch: voice pitch validation (3)

This commit is contained in:
f4exb 2026-02-16 01:54:47 +01:00
parent e43f0e1e35
commit 642a6da8aa

View File

@ -505,6 +505,7 @@ Real FreqScannerSink::voiceActivityLevel(int bin, int channelBins, bool isLSB) c
// Try different f0 candidates in typical voice range (80-300 Hz)
int maxHarmonics = 0;
int bestF0Hz = 0;
for (int f0Hz = 80; f0Hz <= 300; f0Hz += 10)
{
@ -536,6 +537,7 @@ Real FreqScannerSink::voiceActivityLevel(int bin, int channelBins, bool isLSB) c
if (harmonicCount > maxHarmonics)
{
maxHarmonics = harmonicCount;
bestF0Hz = f0Hz;
}
}
@ -545,6 +547,44 @@ Real FreqScannerSink::voiceActivityLevel(int bin, int channelBins, bool isLSB) c
return 0.0;
}
// Check if first harmonic (f0) is actually present at low frequency
// When tuned correctly, f0 should be 80-300 Hz from carrier
int f0Bins = (int)(bestF0Hz / binBW);
int firstHarmonicBin = carrierBin + (isLSB ? -1 : 1) * f0Bins;
int tolerance = (int)(30.0 / binBW);
bool hasF0 = false;
for (int p = 0; p < peakBins.size(); p++)
{
if (std::abs(peakBins[p] - firstHarmonicBin) <= tolerance)
{
hasF0 = true;
break;
}
}
// If no peak near fundamental frequency, signal is mistuned
// (harmonics may still align but they're higher harmonics of wrong pitch)
if (!hasF0) {
return 0.0;
}
// Verify at least one broad formant in F1 range (300-1000 Hz from carrier)
// This catches low-tuning errors where harmonics might still align
bool hasF1 = false;
for (int p = 0; p < broadPeakBins.size(); p++)
{
float freqOffset = std::abs(broadPeakBins[p] - carrierBin) * binBW;
if (freqOffset >= 300.0 && freqOffset <= 1000.0) {
hasF1 = true;
break;
}
}
if (!hasF1) {
return 0.0; // No F1 formant - signal is mistuned
}
// Base score from number of broad peaks
score = std::min(broadPeakCount / 4.0f, 1.0f);