Chirps And Frequency Contours

Def. Sinusoid

$ y(t) = \cos(2 \pi f t + \phi) $

Def. Chirp

A chirp is a more general sinuoid where any function of time is put inside of a cosine, not just a line

$ y(t) = \cos(2 \pi f(t) ) $, where $f(t)$ is some arbitrary function of time

Ex) A sinusoid is a chirp

$f(t) = at + b$

$y(t) = \cos(2 \pi (at + b)) = \cos(2 \pi a t + 2 \pi b)$

$f = a$, $\phi = 2 \pi b$

Ex) $f(t) = 440t^2$

$ y(t) = \cos(2 \pi * 440t^2)$

In [2]:
import numpy as np
import matplotlib.pyplot as plt
import IPython.display as ipd

sr = 44100
t = np.arange(sr)/sr
y = np.cos(2*np.pi*440*t**2)
ipd.Audio(y, rate = sr)
Out[2]:

Ex) $f(t) = 440t^3$

$ y(t) = \cos(2 \pi * 440t^3)$

In [3]:
y2 = np.cos(2*np.pi*440*t**3)
ipd.Audio(y2, rate = sr)
Out[3]:

Ex) $f(t) = 440t^4$

$ y(t) = \cos(2 \pi * 440t^4)$

In [4]:
y3 = np.cos(2*np.pi*440*t**4)
ipd.Audio(y3, rate = sr)
Out[4]:

What's interesitng about these is that their functions all start at 0 and end at 440, but we can clearly hear that the ending note is higher in each successive example

In [6]:
plt.plot(t, 440*t**2)
plt.plot(t, 440*t**3)
plt.plot(t, 440*t**4)
plt.xlabel("time (Seconds)")
plt.legend(["$t^2$", "$t^3$", "$t^4$"])
Out[6]:
<matplotlib.legend.Legend at 0x1e4663b4e48>

Def. Instantaneous frequency = $\frac{d}{dt} f(t)$

We actually don't hear the frequency of f, but the derivative of f! This explains both why the frequencies moved up faster, but also why the ended up higher for higher powers of $t$ over the interval $[0, 1]$, due to the power rule of calculus

Ex) $f(t) = 440t$, $f'(t) = 440$

Ex) $f(t) = 440t^2$, $f'(t) = 880t$

Ex) $f(t) = 440t^3$, $f'(t) = 1320t^2$

Ex) $f(t) = 440t^4$, $f'(t) = 1680t^3$

We can use this idea to design frequency trajectories in audio by specifying the derivative of f, and then taking its antiderivative

Ex) I want to start at 220hz and end at 1680 hz over an interval of 3 seconds, going linearly in frequency

$f'(t) = 220 + (1680-220)*t/3$

$f(t) = 220t + 1460*t^2/6 + c$

We can specify the antiderivative uniquely up to a phase here, but the phase doesn't affect the frequency we hear for a single chirp

In [9]:
sr = 44100
t = np.arange(sr*3)/sr
f = 220*t + 1460*t**2/6
y = np.cos(2*np.pi*f)
ipd.Audio(y, rate=sr)
Out[9]:

Ex) Let's now say we want a chirp that starts at 220hz and ends at 1680hz and that takes a linear increase in pitch over an interval of 3 seconds. This means that we actually want an exponential increase in frequency

$f'(t) = 220*2^{t}$

Because we're lazy, we can actually integrate by taking a numerical approximation which is the cumulative sum of a bunch of thin rectangles, whose widths are the time interval between successive samples and whose heights are the values of the derivative fo frequency. The function "cumsum" helps us to perform such a cumulative sum for the numerical integration (NOTE: There are better schemes such as the trapezoidal scheme and Simpson's rule, but this will do for now). We indeed hear that we go up exactly one octave every second now

In [11]:
df = 220*2**t
f = np.cumsum((t[1]-t[0])*df) # Integral numerically in python using rectangles
y2 = np.cos(2*np.pi*f)
ipd.Audio(y2, rate=sr)
Out[11]:
In [ ]: