MIT 6.300 — Lecture 15

Short-Time Fourier Transform

§ Lecture: Updated DFT Conventions

This note is purely definitional, but it's an important use of jargon that will be assumed for this lecture.

Definition. Let x[n]x[n] be a DT signal with length ss. The “DFT of size N\underline{\text{``DFT of size }N\text{''}} of x[n]x[n] when NsN \geq s is the result of first zero-padding x[n]x[n] to have length NN, then taking the length-NN DFT of the result.

So far, we've only talked about the N=sN = s case. This lecture will use the N>sN > s case.

Remark. In contrast, the N<sN < s case is completely nonsensical.

§ Lecture: Spectrograms

If you were to shove a recording of a piano playing a single chord through the DFT, you'd be able to retrieve the frequencies of that chord. But if you were to shove a recording of a piano playing an entire song through the DFT, you'd only retrieve the set of all frequencies present in the entire song—not the timing of each frequency, or even what order they came in.

The DFT no longer works when frequencies change over time. If we want to analyze the frequencies in an entire song, we need data that shows the frequencies present at each moment in time.

Such data is called a spectrogram, pictured above. It is produced by performing several short-time DFTs.

Problem. You're given a DT signal with sampling rate fs=44100f_s = 44100 samples per second and want a spectrogram such that:

Determine the range of all possible window lengths NN you might use.

Solution: The first condition implies Nfs18\frac{N}{f_s} \leq \frac{1}{8}, and the second condition implies fsN10\frac{f_s}{N} \leq 10. Together, this implies N[4410,5512]N \in [4410, 5512].

This process of taking DFTs over sliding windows is known as the Short-Time Fourier Transform (STFT).

§ Lecture: Streaming Windows

Recall from Lecture 10 that applying a band-pass filter to a DT signal x[n]x[n] is equivalent to multiplying its DTFT X(Ω)X(\Omega) by a box-shaped frequency response H(Ω)H(\Omega), which is itself equivalent to convolving x[n]x[n] with the unit-sample response h[n]h[n].

In the following discussion, we'll try to isolate the melody of the following.

When working with finite-length DFTs, two issues arise.

  1. The FFT runs in O(NlogN)O(N \log N) time. For very long DT signals x[n]x[n], it is not feasible to filter the entire signal at once.

  2. Filtering DT signals via circular convolution gives rise to time aliasing (see Lecture 13), yielding buggy noises.

A natural fix for the first issue is to apply STFT:

Bad Approach. Break x[n]x[n] into subsignals xi[n]x_i[n] of length NN. For each subsignal, compute xi[n]:=(xih)[n]x_i'[n] := (x_i \circledast h)[n], where h[n]h[n] is a length-NN unit-sample response of a band-pass filter. Finally, concatenate all of the xi[n]x_i'[n] together. Here's how the result sounds:

Clearly something sounds off. The main issue comes from our neglect of issue #2: circular convolution and time-aliasing.

Remark. The reason why circular convolution fails is subtle. It is true that each xi[n]x_i'[n] only contains frequencies inside the desired band. But consider the following two extensions of xi[n]x_i'[n] from the domain [0,N1][0, N - 1] to the domain N\mathbb{N}.

xi(1)[n]:=xi[n%N]    and    xi(2)[n]:={xi[n] if n[0,N1].0 otherwise.x_i'^{\,(1)}[n] := x_i'[n \% N] ~~~ \text{ and } ~~~ x_i'^{\,(2)}[n] := \begin{cases} x_i'[n] & \text{ if } n \in [0, N - 1]. \\ 0 & \text{ otherwise.} \end{cases}

All that can be said is that the DTFT of xi(1)[n]x_i'^{\,(1)}[n] contains only band frequencies—but not for xi(2)[n]x_i'^{\,(2)}[n]. Yet the concatenation of all of the xi[n]x_i'[n] is the sum of the xi(2)[n]x_i'^{\,(2)}[n]—not the xi(1)[n]x_i'^{\,(1)}[n].

Therefore, there is no reason for the DTFT of the concatenation of the xi[n]x_i'[n] to only contain band frequencies.

We really should be taking a linear convolution, not a circular convolution, meaning we need to allow time in one window to overflow into the next, rather than aliasing it back around.

Good Approach (Overlap-Add — Time Domain). Break x[n]x[n] into subsignals xi[n]x_i[n] of length ss. For each subsignal, compute the length-NN subsignal xi[n]:=(xih)[n]x_i'[n] := (x_i * h)[n], where h[n]h[n] is a length-(Ns+1)(N - s + 1) unit-sample response of a band-pass filter.

Finally, add all of the xi[n]x_i'[n] together.

Note that each window's linear convolution overlaps with the linear convolutions from other windows—hence the name “overlap-add” and not “overlap-concatenate”.

We can equivalently think of overlap-add from the frequency domain.

Good Approach (Overlap-Add — Frequency Domain). Break x[n]x[n] into subsignals xi[n]x_i[n] of length ss. For each subsignal, zero-pad xi[n]x_i[n] to have length NN, then compute its DFT Xi[k]X_i[k] of size NN. Then compute the element-wise products Xi[k]:=NXi[k]H[k]X_i'[k] := N \cdot X_i[k] \cdot H[k], where H[k]H[k] is a length-NN frequency response of a band-pass filter.

Finally, compute the length-NN subsignals xi:=DFT1(Xi)x_i' := \mathrm{DFT}^{-1}(X_i') and sum them together.

Note that H[k]H[k] is the DFT of size NN of h[n]h[n], where the length of h[n]h[n] is only Ns+1N - s + 1. (Implicitly, we zero-pad h[n]h[n] first…)

There are two reasons for wanting to think from the perspective of the frequency domain.

We'll discuss that second point in the next section: designing H[k]H[k] and h[n]h[n].

§ Lecture: Short-Time Filter Design

The challenge is that H[k]=DFT(h[n])H[k] = \mathrm{DFT}(h[n]), yet h[n]h[n] has some length Nf=Ns+1N_f = N - s + 1 that is less than the length of H[k]H[k]. We must compromise in our design of H[k]H[k] so that the last NNfN - N_f entries of DFT1(H[k])\mathrm{DFT}^{-1}(H[k]) are all zeroes.

Box Approach. Let's work in reverse: we'll design an h[n]h[n] of length NfN_f, then hope the H[k]H[k] we get is an effective filter.

  1. Take a perfect (continuous) filtering frequency response H1(Ω)H_1(\Omega). No compromises here.

  2. Define h1[n]h_1[n] to be the discretized version of the impulse response DTFT1(H1(Ω))\mathrm{DTFT}^{-1}(H_1(\Omega)), truncated to length NfN_f.

  3. Define h2[n]h_2[n] to be a version of h1[n]h_1[n] that is zero-padded to have length NN.

  4. Define H2[k]:=DFT(h2[n])H_2[k] := \mathrm{DFT}(h_2[n]) of length NN.

Then H2[k]H_2[k] is our designed frequency response H[k]H[k]. Here's how the result sounds when used with overlap-add:

That works pretty well! But if you listen closely, you can still faintly hear some of the frequencies from the harmony, especially in the second half. You can see why in the graph of H2[k]H_2[k]: the graph has “ripples” that make it an imperfect filter.

These ripples come from Step #2: ideally, we would take h1[n]:=DTFT1(H1(Ω))h_1[n] := \mathrm{DTFT}^{-1}(H_1(\Omega)) to be an infinite DT signal, but instead, we must compromise by truncating to have length NfN_f.

Here's the trick, though: what if we truncated a bit more smoothly?

Hann Window Approach. We take the same approach as before, but we instead define h1[n]h_1[n] as follows.

h1[n]:=wh[n]DTFT1(H1(Ω))    where    wh[n]:={sin(πnNf)2 if n[0,Nf1]0 otherwise.h_1[n] := w_h[n] \cdot \mathrm{DTFT}^{-1}(H_1(\Omega)) ~~~ \text{ where } ~~~ w_h[n] := \begin{cases} \sin\left(\frac{\pi n}{N_f}\right)^2 & \text{ if } n \in [0, N_f - 1] \\ 0 & \text{ otherwise.} \end{cases}

The signal wh[n]w_h[n] is called a Hann Window, in contrast to the typical rectangular window

wr[n]:={1 if n[0,Nf1]0 otherwise.w_r[n] := \begin{cases} 1 & \text{ if } n \in [0, N_f - 1] \\ 0 & \text{ otherwise.} \end{cases}

used in the previous approach. Yet another alternative choice is a triangle window; you can observe the efficacy of each of these truncation methods through the diagram below.

In the previous approach, the frequencies present in h1[n]h_1[n] would be the result of convolving our perfect filter H1(Ω)H_1(\Omega) with the ripple-filled signal DTFT(wr[n])\mathrm{DTFT}(w_r[n]). No wonder the result H2[k]H_2[k] had so many ripples!

Expectedly, using the Hann window to construct the truncation h1[n]h_1[n] gives a much cleaner H2[k]H_2[k].

And it sounds much better, too—no more harmonies still lingering around.

§ Recitation: Windows and Decibels

We already saw how the rectangular, triangular, and Hann windows compare. But let's compare them at a logarithmic scale.

In the above, decibels are a relative unit of measurement. (So turning the volume knob up won't alter these graphs.)

Definition. Given a signal x[n]x[n], say its highest value is MM. Then x[n]x[n] in decibels is 10log10(x[n]M)10 \log_{10}\left(\frac{x[n]}{M}\right).

So a measurement of 20-20 dB corresponds to a measurement in the signal that is ×1100\times \frac{1}{100} the highest measurement. For reference, measurements of 60-60 dB are essentially inaudible, whereas measurements of 25\approx -25 dB are still weakly perceptible.

§ Recitation: Short-Time Fourier Transform

We never actually formally defined the STFT. Let's do that.

Definition. Given a signal x[n]x[n] and a window w[n]w[n], the STFT is the two-dimensional array:

X[k,m]:=1Nn=0N1x[n+ms]w[n]ejk2πNn.X[k, m] := \frac{1}{N} \sum_{n = 0}^{N - 1} x[n + ms] \cdot w[n] \cdot e^{-jk \frac{2\pi}{N} n}.

Note that kk and mm each only appear once on the RHS. The value of kk controls the frequency being measured, and the value of mm controls the time being measured. A spectrogram is a diagram that displays X[k,m]2|X[k, m]|^2.

Note that the STFT of x[n]x[n] depends on three different parameters:

w[n]: the type of window       N: the DFT size       s: the step size w[n]: \text{ the type of window } ~~~ \parallel ~~~ N: \text{ the DFT size } ~~~ \parallel ~~~ s: \text{ the step size }

Importantly, len(w[n])\mathrm{len}(w[n]), NN, and ss do not have to be equal!

Compare the cleanliness of a rectangular window (at left) versus a Hann window (at right).

Expectedly, the parameter settings affect the spectrogram as follows.

Of course, these improvements to parameter settings come at a cost of time complexity.