Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 7344
1
"""This file contains code used in "Think DSP",
2
by Allen B. Downey, available from greenteapress.com
3
4
Copyright 2014 Allen B. Downey
5
License: GNU GPLv3 http://www.gnu.org/licenses/gpl.html
6
"""
7
8
from __future__ import print_function, division
9
10
import thinkdsp
11
import thinkplot
12
13
import numpy as np
14
import pandas as pd
15
16
import scipy.signal
17
18
PI2 = np.pi * 2
19
20
21
def plot_bitcoin():
22
"""Plot BitCoin prices and a smoothed time series.
23
"""
24
nrows = 1625
25
df = pandas.read_csv('coindesk-bpi-USD-close.csv',
26
nrows=nrows, parse_dates=[0])
27
ys = df.Close.values
28
29
window = np.ones(30)
30
window /= sum(window)
31
smoothed = np.convolve(ys, window, mode='valid')
32
33
N = len(window)
34
smoothed = thinkdsp.shift_right(smoothed, N//2)
35
36
thinkplot.plot(ys, color='0.7', label='daily')
37
thinkplot.plot(smoothed, label='30 day average')
38
thinkplot.config(xlabel='time (days)',
39
ylabel='price',
40
xlim=[0, nrows],
41
loc='lower right')
42
thinkplot.save(root='convolution1')
43
44
45
GRAY = "0.7"
46
47
def plot_facebook():
48
"""Plot Facebook prices and a smoothed time series.
49
"""
50
names = ['date', 'open', 'high', 'low', 'close', 'volume']
51
df = pd.read_csv('fb_1.csv', header=0, names=names, parse_dates=[0])
52
close = df.close.values[::-1]
53
dates = df.date.values[::-1]
54
days = (dates - dates[0]) / np.timedelta64(1,'D')
55
56
M = 30
57
window = np.ones(M)
58
window /= sum(window)
59
smoothed = np.convolve(close, window, mode='valid')
60
smoothed_days = days[M//2: len(smoothed) + M//2]
61
62
thinkplot.plot(days, close, color=GRAY, label='daily close')
63
thinkplot.plot(smoothed_days, smoothed, label='30 day average')
64
65
last = days[-1]
66
thinkplot.config(xlabel='Time (days)',
67
ylabel='Price ($)',
68
xlim=[-7, last+7],
69
legend=True,
70
loc='lower right')
71
thinkplot.save(root='convolution1')
72
73
74
def plot_boxcar():
75
"""Makes a plot showing the effect of convolution with a boxcar window.
76
"""
77
# start with a square signal
78
signal = thinkdsp.SquareSignal(freq=440)
79
wave = signal.make_wave(duration=1, framerate=44100)
80
81
# and a boxcar window
82
window = np.ones(11)
83
window /= sum(window)
84
85
# select a short segment of the wave
86
segment = wave.segment(duration=0.01)
87
88
# and pad with window out to the length of the array
89
N = len(segment)
90
padded = thinkdsp.zero_pad(window, N)
91
92
# compute the first element of the smoothed signal
93
prod = padded * segment.ys
94
print(sum(prod))
95
96
# compute the rest of the smoothed signal
97
smoothed = np.zeros(N)
98
rolled = padded
99
for i in range(N):
100
smoothed[i] = sum(rolled * segment.ys)
101
rolled = np.roll(rolled, 1)
102
103
# plot the results
104
segment.plot(color=GRAY)
105
smooth = thinkdsp.Wave(smoothed, framerate=wave.framerate)
106
smooth.plot()
107
thinkplot.config(xlabel='Time(s)', ylim=[-1.05, 1.05])
108
thinkplot.save(root='convolution2')
109
110
# compute the same thing using np.convolve
111
segment.plot(color=GRAY)
112
ys = np.convolve(segment.ys, window, mode='valid')
113
smooth2 = thinkdsp.Wave(ys, framerate=wave.framerate)
114
smooth2.plot()
115
thinkplot.config(xlabel='Time(s)', ylim=[-1.05, 1.05])
116
thinkplot.save(root='convolution3')
117
118
# plot the spectrum before and after smoothing
119
spectrum = wave.make_spectrum()
120
spectrum.plot(color=GRAY)
121
122
ys = np.convolve(wave.ys, window, mode='same')
123
smooth = thinkdsp.Wave(ys, framerate=wave.framerate)
124
spectrum2 = smooth.make_spectrum()
125
spectrum2.plot()
126
thinkplot.config(xlabel='Frequency (Hz)',
127
ylabel='Amplitude',
128
xlim=[0, 22050])
129
thinkplot.save(root='convolution4')
130
131
# plot the ratio of the original and smoothed spectrum
132
amps = spectrum.amps
133
amps2 = spectrum2.amps
134
ratio = amps2 / amps
135
ratio[amps<560] = 0
136
thinkplot.plot(ratio)
137
138
thinkplot.config(xlabel='Frequency (Hz)',
139
ylabel='Amplitude ratio',
140
xlim=[0, 22050])
141
thinkplot.save(root='convolution5')
142
143
144
# plot the same ratio along with the FFT of the window
145
padded = thinkdsp.zero_pad(window, len(wave))
146
dft_window = np.fft.rfft(padded)
147
148
thinkplot.plot(abs(dft_window), color=GRAY, label='DFT(window)')
149
thinkplot.plot(ratio, label='amplitude ratio')
150
151
thinkplot.config(xlabel='Frequency (Hz)',
152
ylabel='Amplitude ratio',
153
xlim=[0, 22050])
154
thinkplot.save(root='convolution6')
155
156
157
def plot_gaussian():
158
"""Makes a plot showing the effect of convolution with a boxcar window.
159
"""
160
# start with a square signal
161
signal = thinkdsp.SquareSignal(freq=440)
162
wave = signal.make_wave(duration=1, framerate=44100)
163
spectrum = wave.make_spectrum()
164
165
# and a boxcar window
166
boxcar = np.ones(11)
167
boxcar /= sum(boxcar)
168
169
# and a gaussian window
170
gaussian = scipy.signal.gaussian(M=11, std=2)
171
gaussian /= sum(gaussian)
172
173
thinkplot.preplot(2)
174
thinkplot.plot(boxcar, label='boxcar')
175
thinkplot.plot(gaussian, label='Gaussian')
176
thinkplot.config(xlabel='Index', legend=True)
177
thinkplot.save(root='convolution7')
178
179
ys = np.convolve(wave.ys, gaussian, mode='same')
180
smooth = thinkdsp.Wave(ys, framerate=wave.framerate)
181
spectrum2 = smooth.make_spectrum()
182
183
# plot the ratio of the original and smoothed spectrum
184
amps = spectrum.amps
185
amps2 = spectrum2.amps
186
ratio = amps2 / amps
187
ratio[amps<560] = 0
188
189
# plot the same ratio along with the FFT of the window
190
padded = thinkdsp.zero_pad(gaussian, len(wave))
191
dft_gaussian = np.fft.rfft(padded)
192
193
thinkplot.plot(abs(dft_gaussian), color=GRAY, label='Gaussian filter')
194
thinkplot.plot(ratio, label='amplitude ratio')
195
196
thinkplot.config(xlabel='Frequency (Hz)',
197
ylabel='Amplitude ratio',
198
xlim=[0, 22050])
199
thinkplot.save(root='convolution8')
200
201
202
def fft_convolve(signal, window):
203
"""Computes convolution using FFT.
204
"""
205
fft_signal = np.fft.fft(signal)
206
fft_window = np.fft.fft(window)
207
return np.fft.ifft(fft_signal * fft_window)
208
209
210
def fft_autocorr(signal):
211
"""Computes the autocorrelation function using FFT.
212
"""
213
N = len(signal)
214
signal = thinkdsp.zero_pad(signal, 2*N)
215
window = np.flipud(signal)
216
217
corrs = fft_convolve(signal, window)
218
corrs = np.roll(corrs, N//2+1)[:N]
219
return corrs
220
221
222
def plot_fft_convolve():
223
"""Makes a plot showing that FFT-based convolution works.
224
"""
225
names = ['date', 'open', 'high', 'low', 'close', 'volume']
226
df = pd.read_csv('fb_1.csv',
227
header=0, names=names, parse_dates=[0])
228
close = df.close.values[::-1]
229
230
# compute a 30-day average using np.convolve
231
window = scipy.signal.gaussian(M=30, std=6)
232
window /= window.sum()
233
smoothed = np.convolve(close, window, mode='valid')
234
235
# compute the same thing using fft_convolve
236
N = len(close)
237
padded = thinkdsp.zero_pad(window, N)
238
239
M = len(window)
240
smoothed4 = fft_convolve(close, padded)[M-1:]
241
242
# check for the biggest difference
243
diff = smoothed - smoothed4
244
print(max(abs(diff)))
245
246
# compute autocorrelation using np.correlate
247
corrs = np.correlate(close, close, mode='same')
248
corrs2 = fft_autocorr(close)
249
250
# check for the biggest difference
251
diff = corrs - corrs2
252
print(max(abs(diff)))
253
254
# plot the results
255
lags = np.arange(N) - N//2
256
thinkplot.plot(lags, corrs, color=GRAY, linewidth=7, label='np.convolve')
257
thinkplot.plot(lags, corrs2.real, linewidth=2, label='fft_convolve')
258
thinkplot.config(xlabel='Lag',
259
ylabel='Correlation',
260
xlim=[-N//2, N//2])
261
thinkplot.save(root='convolution9')
262
263
264
def main():
265
plot_facebook()
266
plot_boxcar()
267
plot_gaussian()
268
plot_fft_convolve()
269
#plot_bitcoin()
270
271
272
if __name__ == '__main__':
273
main()
274
275