Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
| Download

📚 The CoCalc Library - books, templates and other resources

Views: 96181
License: OTHER
Kernel: Python 3

ThinkDSP

This notebook contains code examples from Chapter 3: Non-periodic signals

Copyright 2015 Allen Downey

License: Creative Commons Attribution 4.0 International

from __future__ import print_function, division %matplotlib inline import thinkdsp import thinkplot import numpy as np from ipywidgets import interact, interactive, fixed import ipywidgets as widgets

Chirp

Make a linear chirp from A3 to A5.

signal = thinkdsp.Chirp(start=220, end=880) wave1 = signal.make_wave(duration=2) wave1.make_audio()

Here's what the waveform looks like near the beginning.

wave1.segment(start=0, duration=0.01).plot()

And near the end.

wave1.segment(start=0.9, duration=0.01).plot()

Here's an exponential chirp with the same frequency range and duration.

signal = thinkdsp.ExpoChirp(start=220, end=880) wave2 = signal.make_wave(duration=2) wave2.make_audio()

Leakage

Spectral leakage is when some of the energy at one frequency appears at another frequency (usually nearby).

Let's look at the effect of leakage on a sine signal (which only contains one frequency component).

signal = thinkdsp.SinSignal(freq=440)

If the duration is an integer multiple of the period, the beginning and end of the segment line up, and we get minimal leakage.

duration = signal.period * 30 wave = signal.make_wave(duration) wave.plot()
spectrum = wave.make_spectrum() spectrum.plot(high=880) thinkplot.config(xlabel='frequency (Hz)', ylabel='amplitude', legend=False)

If the duration is not a multiple of a period, the leakage is pretty bad.

duration = signal.period * 30.25 wave = signal.make_wave(duration) wave.plot()
spectrum = wave.make_spectrum() spectrum.plot(high=880) thinkplot.config(xlabel='Frequency (Hz)')

Windowing helps (but notice that it reduces the total energy).

wave.hamming() spectrum = wave.make_spectrum() spectrum.plot(high=880) thinkplot.config(xlabel='Frequency (Hz)')

Spectrogram

If you blindly compute the DFT of a non-periodic segment, you get "motion blur".

signal = thinkdsp.Chirp(start=220, end=440) wave = signal.make_wave(duration=1) spectrum = wave.make_spectrum() spectrum.plot(high=700) thinkplot.config(xlabel='frequency (Hz)')

A spectrogram is a visualization of a short-time DFT that lets you see how the spectrum varies over time.

def plot_spectrogram(wave, seg_length): spectrogram = wave.make_spectrogram(seg_length) print('Time resolution (s)', spectrogram.time_res) print('Frequency resolution (Hz)', spectrogram.freq_res) spectrogram.plot(high=700) thinkplot.show(xlabel='Time(s)', ylabel='Frequency (Hz)')
signal = thinkdsp.Chirp(start=220, end=440) wave = signal.make_wave(duration=1, framerate=11025) plot_spectrogram(wave, 512)

If you increase the segment length, you get better frequency resolution, worse time resolution.

plot_spectrogram(wave, 1024)

If you decrease the segment length, you get better time resolution, worse frequency resolution.

plot_spectrogram(wave, 256)
slider = widgets.IntSlider(min=128, max=4096, value=100, step=128) interact(plot_spectrogram, wave=fixed(wave), seg_length=slider);

Spectrum of a chirp

The following interaction lets you customize the Eye of Sauron as you vary the start and end frequency of the chirp.

def eye_of_sauron(start, end): """Plots the spectrum of a chirp. start: initial frequency end: final frequency """ signal = thinkdsp.Chirp(start=start, end=end) wave = signal.make_wave(duration=0.5) spectrum = wave.make_spectrum() spectrum.plot(high=1200) thinkplot.config(xlabel='frequency (Hz)', ylabel='amplitude') #TODO: add player
slider1 = widgets.FloatSlider(min=100, max=1000, value=100, step=50) slider2 = widgets.FloatSlider(min=100, max=1000, value=200, step=50) interact(eye_of_sauron, start=slider1, end=slider2);