sndfile-spectrogram produces poor spectrograms for some inputs.
Closed this issue · 13 comments
For instance this pair of commands produces a spectrogram with a bunch of rubbish in it.
$ sndfile-generate-chirp -amp 1.0 -linear -from 22000 -to 26000 96000 10 chirp96.wav
Start frequency : 22000.0 Hz (1.439897 rad/sec)
End frequency : 26000.0 Hz (1.701696 rad/sec)
$ sndfile-spectrogram chirp96.wav 800 600 chirp96.png
I've tried changing the window function in case it was related to that, both with success
Kaiser window:
Nuttall window (enabled from oxbow code in the source):
Hanning window from WikiPedia { data [k] = 0.5 * (1.0 - cos(2.0 * M_PI * k / (datalen - 1))); }
It looks from these that the Nuttall window gives better frequency-domain separation than Hanning, though Kaiser is even tighter that that.
Is this a property of the Kaiser window itself, to resonate at certain frequencies?
Zooming in on one of the frequency bands, it looks chaotic.
24025-24075:
24050-24056:
Thanks. Applied.
This issue is still with us unfortunately.
Analysing http://martinwguy.co.uk/test/50Hz.wav
sndfile-spectrogram --no-border --dyn-range=100 50Hz.wav 480 480 50Hz-kaiser-480-480.png
With --nuttall:
With --hanning:
Note: the above interpolate from spec_len==2880 to heignt==480. However, the results are just as bad at size 480x2880 so it doesn't look like the interpolator.
I'd like to get to the bottom of this. Erik, can you reopen this issue please?
The is an extremely artificial signal. I think what you are seeing is the effect of the transient at the onset of sine tone.
I don't think it's the onset (which is brusque, yes) because the erroneous vertical lines only appear when the FFT window only covers an area with pure 50Hz sine tone. It's only when a constant 50Hz tone is the only signal in town that the effect occurs, the same as with the "chirp" test piece. A gut felling says "integer overflow", but it can't be because we are in floating point world!
For the 50Hz signal, I wonder is the window length is too small to capture a full cycle of the sine wave.
A good experiment would be to do exactly this test for something around 200Hz> If there is no problem there, then reduce the frequency until it becomes a problem.
That might give us an idea what speclen
should actually be.
Thanks for the input.
Hypothesis: For the 50Hz signal, the window length is too small to capture a full cycle of the sine wave.
The test piece is at 44100 samples per second so a 50th of a second is 44100/50=882 samples. The above tests select spec_len==2880 so it has 3 cycles in its window.
Experiment: run the test on a 200Hz tone. It uses speclen=2880 again, so 1 cycle is 220 samples, 2880/220==13 cycles in-window
sndfile-spectrogram --no-border --dyn-range=100 200Hz.wav 480 480 200Hz-kaiser-480-480.png
Observation: The defect persists so it's not that it has only part of a cycle in-window.
Observation: It's very sensitive to tiny changes in --dyn-range. For the above tests, --dyn-range=100. Without --dyn-range the artifacts are replaced by a different kind of noise:
and changing dyn_range but a tiny amount radically changes the noise pattern:
--dyn-range=102:
Hypothesis: It's a defect in the colour mapping code, not in the FFT output.
Experiment: Try the test with --gray-scale
sndfile-spectrogram --no-border --dyn-range=100 --gray-scale 200Hz.wav 480 200 200Hz-kaiser-480-200-gray.png
Adding --gray-scale to the original "chirp96" testpiece also gives clean output.
Hypothesis confirmed! Something's going screwy in the colour-mapping code.
Ok, I'm going to break the get_colour_map_value
function into a separate file and write some tests for it.
Please test commit:
commit 9ca586748b2029b86a9b225178153953e0698f1e
Author: Erik de Castro Lopo <erikd@mega-nerd.com>
Date: Sat Dec 12 20:11:10 2015 +1100
src/spectrogram.c: Fix colour map calculation
I think that may have fixed it.
Yes, that fixes all the above testcases.
Wonderful!