# ThinkDSP¶

by Allen Downey (think-dsp.com)

This notebook contains examples and demos for a SciPy 2015 talk.

In [1]:
from __future__ import print_function, division

import thinkdsp
import thinkplot

import numpy

%matplotlib inline


A Signal represents a function that can be evaluated at an point in time.

In [2]:
cos_sig = thinkdsp.CosSignal(freq=440)


A cosine signal at 440 Hz has a period of 2.3 ms.

In [3]:
cos_sig.plot()
thinkplot.config(xlabel='time (s)', legend=False)


make_wave samples the signal at equally-space time steps.

In [4]:
wave = cos_sig.make_wave(duration=0.5, framerate=11025)


make_audio creates a widget that plays the Wave.

In [5]:
wave.apodize()
wave.make_audio()

Out[5]:

make_spectrum returns a Spectrum object.

In [6]:
spectrum = wave.make_spectrum()


A cosine wave contains only one frequency component (no harmonics).

In [7]:
spectrum.plot()
thinkplot.config(xlabel='frequency (Hz)', legend=False)


A SawTooth signal has a more complex harmonic structure.

In [8]:
saw_sig = thinkdsp.SawtoothSignal(freq=440)
saw_sig.plot()


Here's what it sounds like:

In [9]:
saw_wave = saw_sig.make_wave(duration=0.5)
saw_wave.make_audio()

Out[9]:

And here's what the spectrum looks like:

In [10]:
saw_wave.make_spectrum().plot()


Here's a short violin performance from jcveliz on freesound.org:

In [11]:
violin = thinkdsp.read_wave('92002__jcveliz__violin-origional.wav')
violin.make_audio()

Out[11]:

The spectrogram shows the spectrum over time:

In [12]:
spectrogram = violin.make_spectrogram(seg_length=1024)
spectrogram.plot(high=5000)


We can select a segment where the pitch is constant:

In [13]:
start = 1.2
duration = 0.6
segment = violin.segment(start, duration)


And compute the spectrum of the segment:

In [14]:
spectrum = segment.make_spectrum()
spectrum.plot()


The dominant and fundamental peak is at 438.3 Hz, which is a slightly flat A4 (about 7 cents).

In [15]:
spectrum.peaks()[:5]

Out[15]:
[(2052.3878454763076, 438.33333333333337),
(1504.1231272792359, 876.66666666666674),
(1313.4058092162209, 878.33333333333337),
(1024.7130064064424, 2193.3333333333335),
(809.76238398486601, 2195.0)]

As an aside, you can use the spectrogram to help extract the Parson's code and then identify the song.

Parson's code: DUUDDUURDR

Send it off to http://www.musipedia.org

A chirp is a signal whose frequency varies continuously over time (like a trombone).

In [16]:
import math
PI2 = 2 * math.pi

class SawtoothChirp(thinkdsp.Chirp):
"""Represents a sawtooth signal with varying frequency."""

def _evaluate(self, ts, freqs):
"""Helper function that evaluates the signal.

ts: float array of times
freqs: float array of frequencies during each interval
"""
dts = numpy.diff(ts)
dps = PI2 * freqs * dts
phases = numpy.cumsum(dps)
phases = numpy.insert(phases, 0, 0)
cycles = phases / PI2
frac, _ = numpy.modf(cycles)
ys = thinkdsp.normalize(thinkdsp.unbias(frac), self.amp)
return ys


Here's what it looks like:

In [17]:
signal = SawtoothChirp(start=220, end=880)
wave = signal.make_wave(duration=2, framerate=10000)
segment = wave.segment(duration=0.06)
segment.plot()


Here's the spectrogram.

In [18]:
spectrogram = wave.make_spectrogram(1024)
spectrogram.plot()
thinkplot.config(xlabel='time (s)',
ylabel='frequency (Hz)',
legend=False)


What do you think it sounds like?

In [19]:
wave.apodize()
wave.make_audio()

Out[19]:

Up next is one of the coolest examples in Think DSP. It uses LTI system theory to characterize the acoustics of a recording space and simulate the effect this space would have on the sound of a violin performance.

In [20]:
response = thinkdsp.read_wave('180960__kleeb__gunshot.wav')

start = 0.12
response = response.segment(start=start)
response.shift(-start)

response.normalize()
response.plot()
thinkplot.config(xlabel='time (s)',
ylabel='amplitude',
ylim=[-1.05, 1.05],
legend=False)


If you play this recording, you can hear the initial shot and several seconds of echos.

In [21]:
response.make_audio()

Out[21]: