diff --git a/src/spectrogram.c b/src/spectrogram.c index d9f7545..9567e0c 100644 --- a/src/spectrogram.c +++ b/src/spectrogram.c @@ -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; } diff --git a/synchrosqueezing_for_programmers.pdf b/synchrosqueezing_for_programmers.pdf index 79e7544..5f42ea9 100644 Binary files a/synchrosqueezing_for_programmers.pdf and b/synchrosqueezing_for_programmers.pdf differ