Fix synchrosqueezing: correct complex division sign and add noise threshold

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-04-10 23:44:37 -07:00
parent 0bc30832be
commit d11546d282
2 changed files with 10 additions and 3 deletions
+10 -3
View File
@@ -473,13 +473,19 @@ static void GenerateSpectrogramTexture(StftResult* stft, Image* image, Texture2D
// Accumulation buffer for reassigned energy
float* accumBuffer = (float*)calloc(width * height, sizeof(float));
// Noise threshold: only reassign bins with significant energy
// This prevents noise from being reassigned to random frequencies
float noiseThreshold = maxAmplitude * 0.01f; // 1% of max amplitude
for (int seg = 0; seg < width; seg++) {
for (int bin = 0; bin < height; bin++) {
FrequencyData* V_f = &stft->segments[seg].spectrum[bin];
FrequencyData* V_fd = &stft->segments[seg].derivativeSpectrum[bin];
float amplitude = V_f->amplitude;
if (amplitude < 0.0001f) continue;
// Skip noise bins
if (amplitude < noiseThreshold) continue;
// Compute instantaneous frequency using synchrosqueezing formula:
// ω̂ = bin_freq + Re[V_fd / (i * V_f)]
@@ -496,8 +502,9 @@ static void GenerateSpectrogramTexture(StftResult* stft, Image* image, Texture2D
float trueFreq = V_f->frequency; // Default to bin frequency
if (denom > 1e-10f) {
// Re[V_fd / (i * V_f)] = (V_fd_real * V_f_imag + V_fd_imag * V_f_real) / denom
float correction = (V_fd_real * V_f_imag + V_fd_imag * V_f_real) / denom;
// Re[V_fd / (i * V_f)] = (-V_fd_real * V_f_imag + V_fd_imag * V_f_real) / denom
// Note the MINUS sign on the first term
float correction = (-V_fd_real * V_f_imag + V_fd_imag * V_f_real) / denom;
trueFreq = V_f->frequency + correction;
}
Binary file not shown.