I recently learned how to manually compute a spectrogram of an audio signal, which is essentially a matrix. Each column corresponds to a time frame (e.g. 10 ms or something) but I'm asking which row corresponds to which frequency?

See my implementation below:

clc; clear all; close all;
Fs = 44100;
t_max = 3;
T = 1/Fs;

time = 0:T:(t_max-T);
input = chirp(time,1500,1,8000);

window_length_t = 0.01; %10ms window length
window_length_s = round(0.01 * Fs); %window length in samples
if mod(window_length_s,2) == 0
    window_length_s = window_length_s + 1; %make sure we have odd window size

signal_framewise = buffer(input , window_length_s , floor(window_length_s/2));
nfft =((window_length_s-1)/2)+1;

out_buffer = zeros(nfft,size(signal_framewise,2));
for jj = 1:size(signal_framewise,2)
    current_frame = signal_framewise(:,jj).*gausswin(window_length_s);
    dtf = fft(current_frame);
    out_buffer(:,jj) = dtf(1:nfft);

My theory: The topmost row must be 0.5*Fs (half of the sampling frequency) because of the sampling theorem. All other rows are linear increments to then match to 0.5*Fs. Example: 5 Rows, topmost is 5 Hz, then the first row is 1 Hz, the second is 2 Hz and so forth.

  • $\begingroup$ Can I please ask if this was resolved? $\endgroup$ – A_A Jun 11 '18 at 5:51

The physical frequency $f$ that a given Discrete Fourier Transform (DFT) frequency bin $k$ corresponds to is $f = \frac{k}{N_{DFT}} \cdot Fs$.

For an $Fs=44100$ Hz, the middle point of a given $N_{DFT}$ point DFT would correspond to $\frac{1}{2} \cdot Fs$, also known as the Nyquist Frequency.

EXCEPT MATLAB, which maps $1$ to $\frac{Fs}{2}$.

For more information, please see here.

Hope this helps.

  • $\begingroup$ When you say EXCEPT MATLAB, are you talking about the FFT implementation of matlab, the spectrogram implementation or my code? $\endgroup$ – Alon May 2 '18 at 14:01
  • $\begingroup$ @JoschKraus MATLAB, as a software package (as a whole), chooses to call $1$ the Nyquist Frequency (which is 0.5 in Normalised Frequency). This is in contrast to the standard form of the normalised frequency (the textbook definition if you like). Consequently, what you call 0.25 Normalised Frequency is not the same with what MATLAB calls 0.25. This would confuse you a lot if you were calculating digital filter cut off frequencies. So, keep that in mind when comparing against MATLAB. $\endgroup$ – A_A May 2 '18 at 14:31

I don't know what you're doing but MATLAB's spectrogram implementation allows you to get the power spectrum ps, and the exact frequencies f and time instants t at which the spectrogram is computed with the following syntax at the output: [~, f, t, ps], where ps is a $M\times N$ matrix with the following:

  • Each $k^\rm{th}$ column is the power spectrum over all frequencies at a fixed ($k^\rm{th}$) time instant. Or $$P_k(f_i), \quad\text{where}\quad i = 1, 2\cdots, M\quad\text{and}\quad k \in \left\{1, 2, \cdots, N\right\}.$$ $P_k(f)$ is a $M$-element vector.

  • Each $i^\rm{th}$ row is the power spectrum over time at a fixed ($i^\rm{th}$) frequency value. Or $$P_i(t_k), \quad\text{where}\quad k = 1, 2\cdots, N\quad\text{and}\quad i \in \left\{1, 2, \cdots, M\right\}.$$ $P_i(t)$ is a $N$-element vector.

You don't always have $0$ to $F_s/2$ by default. The frequency range is $0$ to $F_s/2$ for real signal, one side of the spectrum is sufficient because of the Hermitian symmetry of the DFT. And $0$ to $F_s$ for complex signals, where uppper-half end of the frequencies can be shifted to negative frequencies.

  • $\begingroup$ Thanks for the effort! Unfortunately I'm adding my work into earlier work and the computation of the spectrogram cannot be outsourced to matlabs function "spectrogram" so I need an answer that takes the manual computation into account $\endgroup$ – Alon May 7 '18 at 14:32

Your Answer

