1
$\begingroup$

enter image description here

I have FFT data that has logarithmically scaled at x-axis as shown on the image. But the problem is I do have only array of float numbers that has 1024 element in it, but I know that is already not a linearly indexed, and I just want to find the corresponding frequencies from array indices.

$\endgroup$
14
  • 1
    $\begingroup$ There is no such thing as a "log-spaced FFT". You need to be more specific about what that data is and how exactly it was generated. $\endgroup$ – Hilmar Jun 11 at 14:15
  • $\begingroup$ There is no such thing as a log-space FFT. You may receive some interpolated result or something else entirely, and it's up to whoever is giving it to you to provide the corresponding frequency axis. $\endgroup$ – Jazzmaniac Jun 11 at 14:16
  • $\begingroup$ Let me fix it then. When one plot the FFT, either can plot on the linearly spaced x-axis or logarithmically spaced x-axis to neglect the high frequencies. I am getting the data from Blender - Animation Node add-on's - Sound Spectrum node as a float list. And I've realized that the node's output is already logspaced indicies, not linear. Probably for visualization reasons. My frequency outputs cumulated around 14k to 19k, but the spectrum shows that they should be in 5k to 15k span. So I am getting logspaced indices. $\endgroup$ – merkwur Jun 11 at 14:42
  • 2
    $\begingroup$ Hmm... could Logarithmic Fourier transformation be used for this? (LFT) homepages.dias.ie/~ajones/publications/28.pdf , (FFTLog) jila.colorado.edu/~ajsh/FFTLog $\endgroup$ – Juha P Jun 11 at 15:34
  • $\begingroup$ Sorry for the earlier inconvenient question. I fixed it as clearly as possible. $\endgroup$ – merkwur Jun 11 at 15:54
0
$\begingroup$

This is a question on fitting an exponential through two points, like

That depends on the parent function, which could take on form of:

$$ f(x) = ab^x \tag{1} $$

or

$$ f(x) = a b_0^x + c \tag{2} $$ where $a, b, c$ are parameters that depend on start and end points, $(x_0, y_0)$ and $(x_1, y_1)$, and $b_0$ is chosen. Answer for 1, for 2, and derivations. I don't know which form LFT takes (see @JuhaP's references), it could be either depending on need.


Example

Suppose frequencies are dyadically distributed (i.e. 1, 2, 4, 8,...). Pick $(2)$ with $b_0=2$. Then, if min and max frequencies are $5\text{Hz}$ and $15k\text{Hz}$, and we have 1024 elements, set

$$ (x_0, y_0) = (0, 5); (x_1, y_1)=(1, 15000) $$

and round the output, which gives log-spaced frequencies. The $0$ and $1$ is somewhat arbitrary, see code.


Validating

If you have access to the transform, you can confirm the resulting frequencies are correct by taking the transform of exactly one period of a pure cosine at any given frequency, and seeing if the output is a single non-zero value. "Log FFT" is just FFT at log spaced frequencies (or at least that's what it could be, but doesn't change the rest of this answer).


Code

For 2 below, for 1 here.

import numpy as np
import matplotlib.pyplot as plt

def fit_exp(N, fmin, fmax, tmin=0, tmax=1, b0=2, endpoint=True):
    a = (fmax - fmin) / (b0**tmax - b0**tmin)
    c = (fmin * b0**tmax - fmax * b0**tmin) / (b0**tmax - b0**tmin)
    
    t = np.linspace(0, 1, N, endpoint=endpoint)
    return a*b0**t + c

fmin = 5
fmax = 15000
N = 1024

freqs = np.round(fit_exp(N, fmin, fmax, b0=2))
plt.plot(freqs)
plt.scatter([0, N - 1], [fmin, fmax], color='tab:red')
$\endgroup$
5
  • $\begingroup$ I feel this is the way I should go with it, but there is something confusing to me because I've consistently asked deficient version of the question. Sorry for that. I have a 44100 Sr and I have 0Hz - 22050Hz freq range fitted in 1024 nfft, let say at 314 point I have a spike and I want to find the corresponding freq, which is if linear spaced; 44100 / 1024 * 314 = 13522Hz approx. but appears to me either I will shifted the all indicies logarithmically then I will replace 314 with corresponding value which is seems to me to prone to mistakes, fitting in the exp is more reliable. $\endgroup$ – merkwur Jun 11 at 19:30
  • $\begingroup$ @merkwur As in general, rounding should delay as long as possible - so yes, exp fit first, then adjust to sampling rate, then round. So round(freqs[313] * 44100), where freqs wasn't rounded. From comments under your question it seems it's indeed FFT - just check how log scaling is done and apply one of $(1)$ or $(2)$, it'll be exact. $\endgroup$ – OverLordGoldDragon Jun 11 at 19:36
  • $\begingroup$ Here is the sound spectrum node doc, here is the source code, default rate is 5. $\endgroup$ – merkwur Jun 11 at 19:55
  • $\begingroup$ @merkwur If you have the source code you can perfectly undo the steps. Copy relevant code or breakpoint into it, use toy data, see if undo(bins) matches spectrum. $\endgroup$ – OverLordGoldDragon Jun 11 at 20:17
  • $\begingroup$ the issue is I am getting the data from the node. I do not have a direct permission to manipulate the source code of the node. Therefore I need to do undo step onto output of the node. $\endgroup$ – merkwur Jun 11 at 20:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.