📚 The CoCalc Library - books, templates and other resources
License: OTHER
"""This file contains code used in "Think DSP",1by Allen B. Downey, available from greenteapress.com23Copyright 2014 Allen B. Downey4License: GNU GPLv3 http://www.gnu.org/licenses/gpl.html5"""67from __future__ import print_function, division89import thinkdsp10import thinkplot1112import numpy as np13import pandas as pd1415import scipy.signal1617PI2 = np.pi * 2181920def plot_bitcoin():21"""Plot BitCoin prices and a smoothed time series.22"""23nrows = 162524df = pandas.read_csv('coindesk-bpi-USD-close.csv',25nrows=nrows, parse_dates=[0])26ys = df.Close.values2728window = np.ones(30)29window /= sum(window)30smoothed = np.convolve(ys, window, mode='valid')3132N = len(window)33smoothed = thinkdsp.shift_right(smoothed, N//2)3435thinkplot.plot(ys, color='0.7', label='daily')36thinkplot.plot(smoothed, label='30 day average')37thinkplot.config(xlabel='time (days)',38ylabel='price',39xlim=[0, nrows],40loc='lower right')41thinkplot.save(root='convolution1')424344GRAY = "0.7"4546def plot_facebook():47"""Plot Facebook prices and a smoothed time series.48"""49names = ['date', 'open', 'high', 'low', 'close', 'volume']50df = pd.read_csv('fb.csv', header=0, names=names, parse_dates=[0])51close = df.close.values[::-1]52dates = df.date.values[::-1]53days = (dates - dates[0]) / np.timedelta64(1,'D')5455M = 3056window = np.ones(M)57window /= sum(window)58smoothed = np.convolve(close, window, mode='valid')59smoothed_days = days[M//2: len(smoothed) + M//2]6061thinkplot.plot(days, close, color=GRAY, label='daily close')62thinkplot.plot(smoothed_days, smoothed, label='30 day average')6364last = days[-1]65thinkplot.config(xlabel='Time (days)',66ylabel='Price ($)',67xlim=[-7, last+7],68legend=True,69loc='lower right')70thinkplot.save(root='convolution1')717273def plot_boxcar():74"""Makes a plot showing the effect of convolution with a boxcar window.75"""76# start with a square signal77signal = thinkdsp.SquareSignal(freq=440)78wave = signal.make_wave(duration=1, framerate=44100)7980# and a boxcar window81window = np.ones(11)82window /= sum(window)8384# select a short segment of the wave85segment = wave.segment(duration=0.01)8687# and pad with window out to the length of the array88N = len(segment)89padded = thinkdsp.zero_pad(window, N)9091# compute the first element of the smoothed signal92prod = padded * segment.ys93print(sum(prod))9495# compute the rest of the smoothed signal96smoothed = np.zeros(N)97rolled = padded98for i in range(N):99smoothed[i] = sum(rolled * segment.ys)100rolled = np.roll(rolled, 1)101102# plot the results103segment.plot(color=GRAY)104smooth = thinkdsp.Wave(smoothed, framerate=wave.framerate)105smooth.plot()106thinkplot.config(xlabel='Time(s)', ylim=[-1.05, 1.05])107thinkplot.save(root='convolution2')108109# compute the same thing using np.convolve110segment.plot(color=GRAY)111ys = np.convolve(segment.ys, window, mode='valid')112smooth2 = thinkdsp.Wave(ys, framerate=wave.framerate)113smooth2.plot()114thinkplot.config(xlabel='Time(s)', ylim=[-1.05, 1.05])115thinkplot.save(root='convolution3')116117# plot the spectrum before and after smoothing118spectrum = wave.make_spectrum()119spectrum.plot(color=GRAY)120121ys = np.convolve(wave.ys, window, mode='same')122smooth = thinkdsp.Wave(ys, framerate=wave.framerate)123spectrum2 = smooth.make_spectrum()124spectrum2.plot()125thinkplot.config(xlabel='Frequency (Hz)',126ylabel='Amplitude',127xlim=[0, 22050])128thinkplot.save(root='convolution4')129130# plot the ratio of the original and smoothed spectrum131amps = spectrum.amps132amps2 = spectrum2.amps133ratio = amps2 / amps134ratio[amps<560] = 0135thinkplot.plot(ratio)136137thinkplot.config(xlabel='Frequency (Hz)',138ylabel='Amplitude ratio',139xlim=[0, 22050])140thinkplot.save(root='convolution5')141142143# plot the same ratio along with the FFT of the window144padded = thinkdsp.zero_pad(window, len(wave))145dft_window = np.fft.rfft(padded)146147thinkplot.plot(abs(dft_window), color=GRAY, label='DFT(window)')148thinkplot.plot(ratio, label='amplitude ratio')149150thinkplot.config(xlabel='Frequency (Hz)',151ylabel='Amplitude ratio',152xlim=[0, 22050])153thinkplot.save(root='convolution6')154155156def plot_gaussian():157"""Makes a plot showing the effect of convolution with a boxcar window.158"""159# start with a square signal160signal = thinkdsp.SquareSignal(freq=440)161wave = signal.make_wave(duration=1, framerate=44100)162spectrum = wave.make_spectrum()163164# and a boxcar window165boxcar = np.ones(11)166boxcar /= sum(boxcar)167168# and a gaussian window169gaussian = scipy.signal.gaussian(M=11, std=2)170gaussian /= sum(gaussian)171172thinkplot.preplot(2)173thinkplot.plot(boxcar, label='boxcar')174thinkplot.plot(gaussian, label='Gaussian')175thinkplot.config(xlabel='Index', legend=True)176thinkplot.save(root='convolution7')177178ys = np.convolve(wave.ys, gaussian, mode='same')179smooth = thinkdsp.Wave(ys, framerate=wave.framerate)180spectrum2 = smooth.make_spectrum()181182# plot the ratio of the original and smoothed spectrum183amps = spectrum.amps184amps2 = spectrum2.amps185ratio = amps2 / amps186ratio[amps<560] = 0187188# plot the same ratio along with the FFT of the window189padded = thinkdsp.zero_pad(gaussian, len(wave))190dft_gaussian = np.fft.rfft(padded)191192thinkplot.plot(abs(dft_gaussian), color=GRAY, label='Gaussian filter')193thinkplot.plot(ratio, label='amplitude ratio')194195thinkplot.config(xlabel='Frequency (Hz)',196ylabel='Amplitude ratio',197xlim=[0, 22050])198thinkplot.save(root='convolution8')199200201def fft_convolve(signal, window):202"""Computes convolution using FFT.203"""204fft_signal = np.fft.fft(signal)205fft_window = np.fft.fft(window)206return np.fft.ifft(fft_signal * fft_window)207208209def fft_autocorr(signal):210"""Computes the autocorrelation function using FFT.211"""212N = len(signal)213signal = thinkdsp.zero_pad(signal, 2*N)214window = np.flipud(signal)215216corrs = fft_convolve(signal, window)217corrs = np.roll(corrs, N//2+1)[:N]218return corrs219220221def plot_fft_convolve():222"""Makes a plot showing that FFT-based convolution works.223"""224names = ['date', 'open', 'high', 'low', 'close', 'volume']225df = pd.read_csv('fb.csv',226header=0, names=names, parse_dates=[0])227close = df.close.values[::-1]228229# compute a 30-day average using np.convolve230window = scipy.signal.gaussian(M=30, std=6)231window /= window.sum()232smoothed = np.convolve(close, window, mode='valid')233234# compute the same thing using fft_convolve235N = len(close)236padded = thinkdsp.zero_pad(window, N)237238M = len(window)239smoothed4 = fft_convolve(close, padded)[M-1:]240241# check for the biggest difference242diff = smoothed - smoothed4243print(max(abs(diff)))244245# compute autocorrelation using np.correlate246corrs = np.correlate(close, close, mode='same')247corrs2 = fft_autocorr(close)248249# check for the biggest difference250diff = corrs - corrs2251print(max(abs(diff)))252253# plot the results254lags = np.arange(N) - N//2255thinkplot.plot(lags, corrs, color=GRAY, linewidth=7, label='np.convolve')256thinkplot.plot(lags, corrs2.real, linewidth=2, label='fft_convolve')257thinkplot.config(xlabel='Lag',258ylabel='Correlation',259xlim=[-N//2, N//2])260thinkplot.save(root='convolution9')261262263def main():264plot_facebook()265plot_boxcar()266plot_gaussian()267plot_fft_convolve()268#plot_bitcoin()269270271if __name__ == '__main__':272main()273274275