2

I have done an FFT on an audio signal and want to plot the results on a logarithmic scale like this

http://abletonuniverse.altervista.org/wp-content/uploads/2013/04/Spectrum.jpg

but for some reason I can't figure out how to scale the data to fit that logarithmic curve (starting from 0, ending at the nyquist frequency i.e. Samplingrate / block size).

Currently this is what I have

CGContextMoveToPoint(context, 0, rect.size.height);

// Skip the DC Offset (index 0)
for (int i = 1; i < _bins; i++) {
    // Get frequency from bin
    float binFreq = i * 44100.0 / (_bins * 2);

    // Map to rect coordinate space
    float x = log10f(binFreq) * rect.size.width / log10f(44100.0 / 2);
    float y = _freqArray[i] * rect.size.height / -130.0;

    // Draw line
    CGContextAddLineToPoint(context, x, y);
}

My data comes in as 512 points of dB between 0 and ~-130 in _freqArray. Ignore the y component of the plotted point.

My data is not scaled correctly as my first bin (~43 hz) is log10(43)= 1.633 and the end of the graph is log10(22050) = 4.3, so the space between my first bin is taking up over a third of the window. It is important that I don't just put my first bin at the far left of the window the far left must be 0.

Does anybody know a correct way to scale the data into neat logarithmic bins such as in the picture? They have three neat bins representing orders of magnitude of 10, and it conveniently ends right at 22050.

For reference, this is what I have now, you can see the long straight line at the left of the spectrum. The first kink in the line is 43 hz i.e. My first bin. I am yet to put a grid up, but that will come when I figure out the scaling.enter image description here

Peter O.
  • 32,158
  • 14
  • 82
  • 96
shane
  • 1,742
  • 2
  • 19
  • 36

1 Answers1

2

A 0Hz frequency cannot be shown on log-scale frequency axis. The left side shown on the graph you referenced corresponds to 10Hz. You can map the frequency coordinate such that this selected minimum frequency (e.g. minFrequencyToDisplay=10Hz) is drawn at a value of x=0, and the last bin drawn at a value of x=rect.size.width-1, like so:

// Map to rect coordinate space
float logMinFreq = log10f(minFrequencyToDisplay);
float x = (log10f(binFreq)-logMinFreq ) * (rect.size.width-1) /
          (log10f(44100.0 / 2)-logMinFreq );

Gridlines at 100Hz, 1kHz and 10kHz can be obtained with the same formula.

SleuthEye
  • 14,379
  • 2
  • 32
  • 61
  • works perfectly, thank you, I didn't understand that we couldn't show a 0Hz frequency on the logarithmically placed graph, thanks! – shane Jun 30 '15 at 17:49
  • OK, thanks, but here it isn't shown how to use zero freqBin. `log10( 0 )` is undefined. But what if my fft size is 1024 and sample rate 44100. Then my lowest 10h is described by freqBin zero. So how to draw it? – pajczur Oct 14 '21 at 09:27