#!/usr/bin/env python
# coding: utf-8
# # Continuous Wavelet Spectrum
# # Example for sine waves
# First written on Nov,19, 2014:
# Author: tmiyama at gmail
# # Introduction
# Wavelet anaysis tool by Torrence and Compo [1998] is very popular in climatology. However, Liu et al. [2007] has pointed out that the method by Torrence and Compo [1998] has a bias in favor of large scales.
#
# This notebook is the translation of Liu et al.'s matlab test program
# http://ocgweb.marine.usf.edu/~liu/wavelet_test_ElNino3_YLiu.m
# to python.
#
# This notebook use an artificial sine curve for a test correponding to Liu et al. [2007].
#
# Notebook for NINO3 SST is here: http://nbviewer.ipython.org/urls/dl.dropbox.com/s/ryeoz3wxrkg1hhz/wavelet_test_ElNino3_Liu.ipynb?dl=0
# __References:__
#
# * Liu, Y., X.S. Liang, and R.H. Weisberg, 2007: Rectification of the bias in the wavelet power spectrum. Journal of Atmospheric and Oceanic Technology, 24(12), 2093-2102. http://ocgweb.marine.usf.edu/~liu/wavelet.html
#
# * Torrence, C., and G. P. Compo, 1998: A practical guide to wavelet analysis. Bull. Amer. Meteor. Soc., 79, 6178. http://paos.colorado.edu/research/wavelets/
# Here is the comment in the original matlab script.
#
# % Rectification of the bias in the Wavelet power spectrum with the data set
# % (Nino3.dat) given by Torrence and Compo (1998). This code is modified
# % from wavetest.m, the example script provided by Torrence and Compo
# % (1998), to demonstrate how to rectify the bias in wavelet power spectrum.
# % This code generates Figure 4 of Liu et al. (2007).
# %
# % Yonggang Liu, 2006.4.12
# %
# % E-mail: yliu18@gmail.com
# % http://ocgweb.marine.usf.edu/~liu/wavelet.html
# %
# % References:
# %
# % Liu, Y., X.S. Liang, and R.H. Weisberg, 2007: Rectification of the bias
# % in the wavelet power spectrum. Journal of Atmospheric and Oceanic
# % Technology, 24(12), 2093-2102.
# %
# % Torrence, C., and G. P. Compo, 1998: A practical guide to wavelet
# % analysis. Bull. Amer. Meteor. Soc., 79, 61�78.
# %========================================================================
# % Here starts with the original file header:
#
#
# %WAVETEST Example Matlab script for WAVELET, using NINO3 SST dataset
# %
# % See "http://paos.colorado.edu/research/wavelets/"
# % Written January 1998 by C. Torrence
# %
# % Modified Oct 1999, changed Global Wavelet Spectrum (GWS) to be sideways,
# % changed all "log" to "log2", changed logarithmic axis on GWS
# % a normal axis.
#
# # Reading modules and data
# __Read usual modules__
# In[1]:
import numpy as np
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
# __Read Wavelet module__
# This module is the translation from the matlab tools by Torrence and Compo (1998).
# http://paos.colorado.edu/research/wavelets/software.html
#
# See the bottom of this notebook for the inside of this module.
# In[2]:
from wavelet import wavelet
# __Construct sine waves__
# Section 5 in Liu et al. [2007]
# In[3]:
dt=1./24. # 1 hour
t1=1.
t2=8.
t3=32.
t4=128.
t5=365.
n=365*24*13
t=np.arange(n)*dt
pi2=np.pi*2.
#5 sine waves
sst=np.sin(t/t1*pi2)+np.sin(t/t2*pi2)+np.sin(t/t3*pi2)+np.sin(t/t4*pi2)+np.sin(t/t5*pi2)
time = t/365. + 1993.0 # construct time array
xlim = [time[0],time[-1]] # plotting range
plt.plot(time,sst)
xrange=plt.xlim(xlim)
# # Wavelet Spectrum by Torrence and Compo [1998]
# __Set wavelet parameters__
# In[4]:
pad = 1 # pad the time series with zeroes (recommended)
dj = 1./8. # this will do 8 sub-octaves per octave
s0 = 6.*dt # this says start at a scale of 6hour
j1 = 12./dj # this says do 12 powers-of-two with dj sub-octaves each
mother = 'Morlet'
# __Wavelet transform__
# In[5]:
wave,period,scale,coi = wavelet(sst,dt,pad,dj,s0,j1,mother);
power = (np.abs(wave))**2 # compute wavelet power spectrum
# __Global wavelet spectrum__
# In[6]:
global_ws = power.sum(axis=1)/float(n) # time-average over all times
# # Wavelet Spectrum by Liu et al [2007]
# __Bias rectification__
#
# divided by scales
# In[7]:
########################
# Spectrum
########################
powers=np.zeros_like(power)
for k in range(len(scale)):
powers[k,:] = power[k,:]/scale[k]
########################
# Global Spectrum
########################
global_wss = global_ws/scale
# # PLOT
# Corresponding to Fig. 2 in Liu et al. (2007)
# In[10]:
#figure size
fig=plt.figure(figsize=(10,10))
# subplot positions
width= 0.65
height = 0.28;
pos1a = [0.1, 0.75, width, 0.2]
pos1b = [0.1, 0.4, width, height]
pos1c = [0.79, 0.4, 0.18, height]
pos1d = [0.1, 0.02, width, height]
pos1e = [0.79,0.02, 0.18, height]
#########################################
#---- a) Original signal
#########################################
ax=fig.add_axes(pos1a)
ax.plot(time,sst,"r-")
ax.set_ylabel('')
plt.title('a) Original Sine curve')
#########################################
# b) Wavelet spectrum
#########################################
#--- Contour plot wavelet power spectrum
bx=fig.add_axes(pos1b,sharex=ax)
Yticks = 2.**(np.arange(np.int(np.log2(np.min(period))),np.int(np.log2(np.max(period)))+1))
bx.contourf(time,np.log2(period),np.log2(power))
bx.set_xlabel('Time (year)')
bx.set_ylabel('Period (days)')
import matplotlib.ticker as ticker
ymajorLocator=ticker.FixedLocator(np.log2(Yticks))
bx.yaxis.set_major_locator( ymajorLocator )
ticks=bx.yaxis.set_ticklabels(Yticks)
plt.title('b) Wavelet Power Spectrum')
# cone-of-influence, anything "below" is dubious
ts = time;
coi_area = np.concatenate([[np.max(scale)], coi, [np.max(scale)],[np.max(scale)]])
ts_area = np.concatenate([[ts[0]], ts, [ts[-1]] ,[ts[0]]]);
L = bx.plot(ts_area,np.log2(coi_area),'k',linewidth=3)
F=bx.fill(ts_area,np.log2(coi_area),'k',alpha=0.3,hatch="x")
#########################################
# c) Global Wavelet spectrum
#########################################
#--- Plot global wavelet spectrum
cx=fig.add_axes(pos1c,sharey=bx)
cx.plot(np.log2(global_ws),np.log2(period),"r-")
ylim=cx.set_ylim(np.log2([period.min(),period.max()]))
cx.invert_yaxis()
plt.title('c) Global Wavelet Spectrum')
xrangec=cx.set_xlim([0,1.25*np.max(np.log2(global_ws))])
#########################################
# d) Wavelet spectrum
#########################################
#--- Contour plot wavelet power spectrum
dx=fig.add_axes(pos1d,sharex=ax)
dx.contourf(time,np.log2(period),np.log2(powers))
dx.set_xlabel('Time (year)')
dx.set_ylabel('Period (days)')
ymajorLocator=ticker.FixedLocator(np.log2(Yticks))
dx.yaxis.set_major_locator( ymajorLocator )
dx.yaxis.set_ticklabels(Yticks)
plt.title('d) Wavelet Power Spectrum')
# cone-of-influence, anything "below" is dubios
L = dx.plot(ts_area,np.log2(coi_area),'k',linewidth=3)
F=dx.fill(ts_area,np.log2(coi_area),'k',alpha=0.3,hatch="x")
#########################################
# e) Global Wavelet spectrum
#########################################
#--- Plot global wavelet spectrum
ex=fig.add_axes(pos1e,sharey=dx)
ex.plot(np.log2(global_wss),np.log2(period),"r-")
ylim=ex.set_ylim(np.log2([period.min(),period.max()]))
ex.invert_yaxis()
plt.title('e) Global Wavelet Spectrum')
xrangec=ex.set_xlim([0,1.25*np.max(np.log2(global_wss))])
#########################################
# Save fig
#########################################
plt.savefig("wavelet_test_sine.png")
# # List of Modules
# In[11]:
get_ipython().system('cat wavelet.py')
# In[12]:
get_ipython().system('cat wave_bases.py')
# In[ ]:
# In[ ]:
# In[ ]:
# In[ ]:
# In[ ]: