Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 7307
Kernel: Python 3

ThinkDSP

This notebook contains solutions to exercises in Chapter 11: Modulation and sampling

Copyright 2015 Allen Downey

License: Creative Commons Attribution 4.0 International

# Get thinkdsp.py import os if not os.path.exists('thinkdsp.py'): !wget https://github.com/AllenDowney/ThinkDSP/raw/master/code/thinkdsp.py
import numpy as np import matplotlib.pyplot as plt from thinkdsp import decorate

Exercise 1

As we have seen, if you sample a signal at too low a framerate, frequencies above the folding frequency get aliased. Once that happens, it is no longer possible to filter out these components, because they are indistinguishable from lower frequencies.

It is a good idea to filter out these frequencies before sampling; a low-pass filter used for this purpose is called an ``anti-aliasing filter''.

Returning to the drum solo example, apply a low-pass filter before sampling, then apply the low-pass filter again to remove the spectral copies introduced by sampling. The result should be identical to the filtered signal.

Solution: I'll load the drum solo again.

if not os.path.exists('263868__kevcio__amen-break-a-160-bpm.wav'): !wget https://github.com/AllenDowney/ThinkDSP/raw/master/code/263868__kevcio__amen-break-a-160-bpm.wav
from thinkdsp import read_wave wave = read_wave('263868__kevcio__amen-break-a-160-bpm.wav') wave.normalize() wave.plot()
Image in a Jupyter notebook

This signal is sampled at 44100 Hz. Here's what it sounds like.

wave.make_audio()

And here's the spectrum:

spectrum = wave.make_spectrum(full=True) spectrum.plot()
Image in a Jupyter notebook

I'll reduce the sampling rate by a factor of 3 (but you can change this to try other values):

factor = 3 framerate = wave.framerate / factor cutoff = framerate / 2 - 1

Before sampling we apply an anti-aliasing filter to remove frequencies above the new folding frequency, which is framerate/2:

spectrum.low_pass(cutoff) spectrum.plot()
Image in a Jupyter notebook

Here's what it sounds like after filtering (still pretty good).

filtered = spectrum.make_wave() filtered.make_audio()

Here's the function that simulates the sampling process:

from thinkdsp import Wave def sample(wave, factor): """Simulates sampling of a wave. wave: Wave object factor: ratio of the new framerate to the original """ ys = np.zeros(len(wave)) ys[::factor] = np.real(wave.ys[::factor]) return Wave(ys, framerate=wave.framerate)

The result contains copies of the spectrum near 20 kHz; they are not very noticeable:

sampled = sample(filtered, factor) sampled.make_audio()

But they show up when we plot the spectrum:

sampled_spectrum = sampled.make_spectrum(full=True) sampled_spectrum.plot()
Image in a Jupyter notebook

We can get rid of the spectral copies by applying the anti-aliasing filter again:

sampled_spectrum.low_pass(cutoff) sampled_spectrum.plot()
Image in a Jupyter notebook

We just lost half the energy in the spectrum, but we can scale the result to get it back:

sampled_spectrum.scale(factor) spectrum.plot() sampled_spectrum.plot()
Image in a Jupyter notebook

Now the difference between the spectrum before and after sampling should be small.

spectrum.max_diff(sampled_spectrum)
1.8189894035458565e-12

After filtering and scaling, we can convert back to a wave:

interpolated = sampled_spectrum.make_wave() interpolated.make_audio()

And the difference between the interpolated wave and the filtered wave should be small.

filtered.plot() interpolated.plot()
Image in a Jupyter notebook
filtered.max_diff(interpolated)
5.56290642113787e-16