Source Material:

The following exercises are adapted from Chapter 7 of Mark Newman’s book, “Computational Physics”

Exercises: DFTs of Various Signals

In this notebook, you will be generating samples from various functions, f(t) over a given duration t[0,T) and for a specified number of samples N. I.e. the samples are yn=f(tn).

Then you will use the discrete Fourier transform to compute (ck)k=0N2 for those samples, and then convert these to (|ak|)k=0N2 and (|φk|)k=0N2

You will plot both the sampled wave form of f – a scatter plot of (tn,yn) – and the Fourier spectrum of f – a histogram/stem chart of (|ak|)k=0N2 vs (|νk|)k=0N2

Make sure that your time values tn and frequencies νk all have the appropriate physical units for the specified signal. E.g. most wave form plots should have “seconds” on the x axis, and most Fourier spectra should have “1/seconds (Hz)” on the x axis.

For all problems, take N=1,000 as the number of samples

[ ]:
import numpy as np
import matplotlib.pyplot as plt
from typing import Tuple

%matplotlib notebook

(1.5.1) Generate N=1,000 samples of a single period of a square wave of amplitude 1, whose period lasts for 5 seconds. A square wave is like a sine-wave, except a square wave only takes on values of 1 (wherever sin(x) is positive) or 1 (wherever sin(x) is negative). An example of eight samples of a single period of a square wave with amplitude 1 is:

[1, 1, 1, 1, -1, -1, -1, -1]

Also compute the Fourier coefficients, (|ak|)k=0N2, for these samples.

Plot the sampled wave form of this square wave versus time and plot the Fourier spectrum, |ak| vs νk.

Here is some code that you can use to plot these side-by-side:

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(8, 4))
ax1.plot(t, y, marker="o")  # plot time (t) and waveform-samples (y)
ax1.grid()
ax1.set_xlabel("t (seconds)")  # make sure `t` actually represents seconds!

ax2.stem(freqs, amps, basefmt=" ", use_line_collection=True) # plot frequency (freqs) and amplitudes (amps)
ax2.set_xlim(0, 10)
ax2.grid()
ax2.set_ylabel(r"$|a_{k}|$")
ax2.set_xlabel(r"$\nu_{k}$ (Hz)")  # make sure `freqs` actually represents Hertz!
fig.tight_layout()
[ ]:
# STUDENT CODE HERE

(1.5.2) f is a simple linear function f(t)=t on t[0,1000) seconds. Using N=1,000 samples, plot both the sampled waveform and the Fourier spectrum, |ak| vs νk.

[ ]:
# STUDENT CODE HERE

(1.5.3) f is the modulated wave: sin(2π12Qt)sin(2π10Qt), where Q=5seconds. Sample this signal starting from t=0 over one period of the lower-frequency term (a.k.a the modulating term): sin(2π12Qt), using N=1,000 samples.

  • What are the frequencies of the respective terms in our modulated wave, in Hz?

  • Do you expect that these two frequencies present in the Fourier spectrum? Why might we expect for different frequencies to be prominent in our series (hint: compare the functional form of this waveform to that of a Fourier series)?

  • Use the relationship sin(a)sin(b)=12(cos(ab)cos(a+b)) to rewrite this modulated wave as a sum of cosines. From this, predict the number, locations, and heights of the peaks in your Fourier spectrum.

  • Plot the wave form vs time and plot the Fourier spectrum, |ak| vs νk. Be sure to zoom in on your peaks and check that they are located where you expect them to be.

SOLUTION HERE

[ ]:
# STUDENT CODE HERE

(1.5.4) f is a signal that produced uniform random noise on [1,1). np.random.rand generates random numbers on [0,1). Define a Python function noise:

def noise(t: np.ndarray) -> np.ndarray:
    # t is a shape-(N,) array
    # Use np.random.rand to draw a shape-(N,)
    # array of uniform random numbers on [0, 1)
    #
    # Modify these numbers so that they instead fall
    # on the range [-1, 1)
    #
    # return these random samples

Use this to generate N=1,000 samples of a noisy signal last for 5 seconds. Plot the sampled wave form and Fourier spectrum. Do you see any pattern in the Fourier spectrum?

[ ]:
# STUDENT CODE HERE