;******************************************************************* WAVELET
;+
; NAME: WAVELET
;
; PURPOSE: Compute the WAVELET transform of a 1D time series.
;
;
; CALLING SEQUENCE:
;
; wave = WAVELET(Y,DT)
;
;
; INPUTS:
;
; Y = the time series of length N.
;
; DT = amount of time between each Y value, i.e. the sampling time.
;
;
; OUTPUTS:
;
; WAVE is the WAVELET transform of Y. This is a complex array
; of dimensions (N,J+1). FLOAT(WAVE) gives the WAVELET amplitude,
; ATAN(IMAGINARY(WAVE),FLOAT(WAVE)) gives the WAVELET phase.
; The WAVELET power spectrum is ABS(WAVE)^2.
;
;
; OPTIONAL KEYWORD INPUTS:
;
; S0 = the smallest scale of the wavelet. Default is 2*DT.
;
; DJ = the spacing between discrete scales. Default is 0.125.
; A smaller # will give better scale resolution, but be slower to plot.
;
; J = the # of scales minus one. Scales range from S0 up to S0*2^(J*DJ),
; to give a total of (J+1) scales. Default is J = (LOG2(N DT/S0))/DJ.
;
; MOTHER = A string giving the mother wavelet to use.
; Currently, 'Morlet','Paul','DOG' (derivative of Gaussian)
; are available. Default is 'Morlet'.
;
; PARAM = optional mother wavelet parameter.
; For 'Morlet' this is k0 (wavenumber), default is 6.
; For 'Paul' this is m (order), default is 4.
; For 'DOG' this is m (m-th derivative), default is 2.
;
; PAD = if set, then pad the time series with enough zeroes to get
; N up to the next higher power of 2. This prevents wraparound
; from the end of the time series to the beginning, and also
; speeds up the FFT's used to do the wavelet transform.
; This will not eliminate all edge effects (see COI below).
;
; LAG1 = LAG 1 Autocorrelation, used for SIGNIF levels. Default is 0.0
;
; SIGLVL = significance level to use. Default is 0.95
;
; VERBOSE = if set, then print out info for each analyzed scale.
;
; RECON = if set, then reconstruct the time series, and store in Y.
; Note that this will destroy the original time series,
; so be sure to input a dummy copy of Y.
;
; FFT_THEOR = theoretical background spectrum as a function of
; Fourier frequency. This will be smoothed by the
; wavelet function and returned as a function of PERIOD.
;
;
; OPTIONAL KEYWORD OUTPUTS:
;
; PERIOD = the vector of "Fourier" periods (in time units) that corresponds
; to the SCALEs.
;
; SCALE = the vector of scale indices, given by S0*2^(j*DJ), j=0...J
; where J+1 is the total # of scales.
;
; COI = if specified, then return the Cone-of-Influence, which is a vector
; of N points that contains the maximum period of useful information
; at that particular time.
; Periods greater than this are subject to edge effects.
; This can be used to plot COI lines on a contour plot by doing:
; IDL> CONTOUR,wavelet,time,period
; IDL> PLOTS,time,coi,NOCLIP=0
;
; YPAD = returns the padded time series that was actually used in the
; wavelet transform.
;
; DAUGHTER = if initially set to 1, then return the daughter wavelets.
; This is a complex array of the same size as WAVELET. At each scale
; the daughter wavelet is located in the center of the array.
;
; SIGNIF = output significance levels as a function of PERIOD
;
; FFT_THEOR = output theoretical background spectrum (smoothed by the
; wavelet function), as a function of PERIOD.
;
;
; [ Defunct INPUTS:
; [ OCT = the # of octaves to analyze over. ]
; [ Largest scale will be S0*2^OCT. ]
; [ Default is (LOG2(N) - 1). ]
; [ VOICE = # of voices in each octave. Default is 8. ]
; [ Higher # gives better scale resolution, ]
; [ but is slower to plot. ]
; ]
;
;----------------------------------------------------------------------------
;
; EXAMPLE:
;
; IDL> ntime = 256
; IDL> y = RANDOMN(s,ntime) ;*** create a random time series
; IDL> dt = 0.25
; IDL> time = FINDGEN(ntime)*dt ;*** create the time index
; IDL>
; IDL> wave = WAVELET(y,dt,PERIOD=period,COI=coi,/PAD,SIGNIF=signif)
; IDL> nscale = N_ELEMENTS(period)
; IDL> LOADCT,39
; IDL> CONTOUR,ABS(wave)^2,time,period, $
; XSTYLE=1,XTITLE='Time',YTITLE='Period',TITLE='Noise Wavelet', $
; YRANGE=[MAX(period),MIN(period)], $ ;*** Large-->Small period
; /YTYPE, $ ;*** make y-axis logarithmic
; NLEVELS=25,/FILL
; IDL>
; IDL> signif = REBIN(TRANSPOSE(signif),ntime,nscale)
; IDL> CONTOUR,ABS(wave)^2/signif,time,period, $
; /OVERPLOT,LEVEL=1.0,C_ANNOT='95%'
; IDL> PLOTS,time,coi,NOCLIP=0 ;*** anything "below" this line is dubious
;
;
;----------------------------------------------------------------------------
; Copyright (C) 1995-2004, Christopher Torrence and Gilbert P. Compo
;
; This software may be used, copied, or redistributed as long as it is not
; sold and this copyright notice is reproduced on each copy made.
; This routine is provided as is without any express or implied warranties
; whatsoever.
;
; Notice: Please acknowledge the use of the above software in any publications:
; ``Wavelet software was provided by C. Torrence and G. Compo,
; and is available at URL: http://paos.colorado.edu/research/wavelets/''.
;
; Reference: Torrence, C. and G. P. Compo, 1998: A Practical Guide to
; Wavelet Analysis. Bull. Amer. Meteor. Soc., 79, 61-78.
;
; Please send a copy of such publications to either C. Torrence or G. Compo:
; Dr. Christopher Torrence Dr. Gilbert P. Compo
; Research Systems, Inc. Climate Diagnostics Center
; 4990 Pearl East Circle 325 Broadway R/CDC1
; Boulder, CO 80301, USA Boulder, CO 80305-3328, USA
; E-mail: chris[AT]rsinc[DOT]com E-mail: compo[AT]colorado[DOT]edu
;----------------------------------------------------------------------------
;-
FUNCTION morlet, $ ;*********************************************** MORLET
k0,scale,k,period,coi,dofmin,Cdelta,psi0
IF (k0 EQ -1) THEN k0 = 6d
n = N_ELEMENTS(k)
expnt = -(scale*k - k0)^2/2d*(k GT 0.)
dt = 2*!PI/(n*k(1))
norm = SQRT(2*!PI*scale/dt)*(!PI^(-0.25)) ; total energy=N [Eqn(7)]
morlet = norm*EXP(expnt > (-100d))
morlet = morlet*(expnt GT -100) ; avoid underflow errors
morlet = morlet*(k GT 0.) ; Heaviside step function (Morlet is complex)
fourier_factor = (4*!PI)/(k0 + SQRT(2+k0^2)) ; Scale-->Fourier [Sec.3h]
period = scale*fourier_factor
coi = fourier_factor/SQRT(2) ; Cone-of-influence [Sec.3g]
dofmin = 2 ; Degrees of freedom with no smoothing
Cdelta = -1
IF (k0 EQ 6) THEN Cdelta = 0.776 ; reconstruction factor
psi0 = !PI^(-0.25)
; PRINT,scale,n,SQRT(TOTAL(ABS(morlet)^2,/DOUBLE))
RETURN,morlet
END
FUNCTION paul, $ ;************************************************** PAUL
m,scale,k,period,coi,dofmin,Cdelta,psi0
IF (m EQ -1) THEN m = 4d
n = N_ELEMENTS(k)
expnt = -(scale*k)*(k GT 0.)
dt = 2d*!PI/(n*k(1))
norm = SQRT(2*!PI*scale/dt)*(2^m/SQRT(m*FACTORIAL(2*m-1)))
paul = norm*((scale*k)^m)*EXP(expnt > (-100d))*(expnt GT -100)
paul = paul*(k GT 0.)
fourier_factor = 4*!PI/(2*m+1)
period = scale*fourier_factor
coi = fourier_factor*SQRT(2)
dofmin = 2 ; Degrees of freedom with no smoothing
Cdelta = -1
IF (m EQ 4) THEN Cdelta = 1.132 ; reconstruction factor
psi0 = 2.^m*FACTORIAL(m)/SQRT(!PI*FACTORIAL(2*m))
; PRINT,scale,n,norm,SQRT(TOTAL(paul^2,/DOUBLE))*SQRT(n)
RETURN,paul
END
FUNCTION dog, $ ;*************************************************** DOG
m,scale,k,period,coi,dofmin,Cdelta,psi0
IF (m EQ -1) THEN m = 2
n = N_ELEMENTS(k)
expnt = -(scale*k)^2/2d
dt = 2d*!PI/(n*k(1))
norm = SQRT(2*!PI*scale/dt)*SQRT(1d/GAMMA(m+0.5))
I = DCOMPLEX(0,1)
gauss = -norm*(I^m)*(scale*k)^m*EXP(expnt > (-100d))*(expnt GT -100)
fourier_factor = 2*!PI*SQRT(2./(2*m+1))
period = scale*fourier_factor
coi = fourier_factor/SQRT(2)
dofmin = 1 ; Degrees of freedom with no smoothing
Cdelta = -1
psi0 = -1
IF (m EQ 2) THEN BEGIN
Cdelta = 3.541 ; reconstruction factor
psi0 = 0.867325
ENDIF
IF (m EQ 6) THEN BEGIN
Cdelta = 1.966 ; reconstruction factor
psi0 = 0.88406
ENDIF
; PRINT,scale,n,norm,SQRT(TOTAL(ABS(gauss)^2,/DOUBLE))*SQRT(n)
RETURN,gauss
END
;****************************************************************** WAVELET
FUNCTION wavelet,y1,dt, $ ;*** required inputs
S0=s0,DJ=dj,J=j, $ ;*** optional inputs
PAD=pad,MOTHER=mother,PARAM=param, $
VERBOSE=verbose,NO_WAVE=no_wave,RECON=recon, $
LAG1=lag1,SIGLVL=siglvl,DOF=dof,GLOBAL=global, $ ;*** optional inputs
SCALE=scale,PERIOD=period,YPAD=ypad, $ ;*** optional outputs
DAUGHTER=daughter,COI=coi, $
SIGNIF=signif,FFT_THEOR=fft_theor, $
OCT=oct,VOICE=voice ;*** defunct inputs
ON_ERROR,2
r = CHECK_MATH(0,1)
n = N_ELEMENTS(y1)
n1 = n
base2 = FIX(ALOG(n)/ALOG(2) + 0.4999) ; power of 2 nearest to N
;....check keywords & optional inputs
IF (N_ELEMENTS(s0) LT 1) THEN s0 = 2.0*dt
IF (N_ELEMENTS(voice) EQ 1) THEN dj = 1./voice
IF (N_ELEMENTS(dj) LT 1) THEN dj = 1./8
IF (N_ELEMENTS(oct) EQ 1) THEN J = FLOAT(oct)/dj
IF (N_ELEMENTS(J) LT 1) THEN J=FIX((ALOG(FLOAT(n)*dt/s0)/ALOG(2))/dj) ;[Eqn(10)]
IF (N_ELEMENTS(mother) LT 1) THEN mother = 'MORLET'
IF (N_ELEMENTS(param) LT 1) THEN param = -1
IF (N_ELEMENTS(siglvl) LT 1) THEN siglvl = 0.95
IF (N_ELEMENTS(lag1) LT 1) THEN lag1 = 0.0
lag1 = lag1(0)
verbose = KEYWORD_SET(verbose)
do_daughter = KEYWORD_SET(daughter)
do_wave = NOT KEYWORD_SET(no_wave)
recon = KEYWORD_SET(recon)
IF KEYWORD_SET(global) THEN MESSAGE, $
'Please use WAVE_SIGNIF for global significance tests'
;....construct time series to analyze, pad if necessary
ypad = y1 - TOTAL(y1)/n ; remove mean
IF KEYWORD_SET(pad) THEN BEGIN ; pad with extra zeroes, up to power of 2
ypad = [ypad,FLTARR(2L^(base2 + 1) - n)]
n = N_ELEMENTS(ypad)
ENDIF
;....construct SCALE array & empty PERIOD & WAVE arrays
na = J + 1 ; # of scales
scale = DINDGEN(na)*dj ; array of j-values
scale = 2d0^(scale)*s0 ; array of scales 2^j [Eqn(9)]
period = FLTARR(na,/NOZERO) ; empty period array (filled in below)
wave = COMPLEXARR(n,na,/NOZERO) ; empty wavelet array
IF (do_daughter) THEN daughter = wave ; empty daughter array
;....construct wavenumber array used in transform [Eqn(5)]
k = (DINDGEN(n/2) + 1)*(2*!PI)/(DOUBLE(n)*dt)
k = [0d,k,-REVERSE(k(0:(n-1)/2 - 1))]
;....compute FFT of the (padded) time series
yfft = FFT(ypad,-1,/DOUBLE) ; [Eqn(3)]
IF (verbose) THEN BEGIN ;verbose
PRINT
PRINT,mother
PRINT,'#points=',n1,' s0=',s0,' dj=',dj,' J=',FIX(J)
IF (n1 NE n) THEN PRINT,'(padded with ',n-n1,' zeroes)'
PRINT,['j','scale','period','variance','mathflag'], $
FORMAT='(/,A3,3A11,A10)'
ENDIF ;verbose
IF (N_ELEMENTS(fft_theor) EQ n) THEN fft_theor_k = fft_theor ELSE $
fft_theor_k = (1-lag1^2)/(1-2*lag1*COS(k*dt)+lag1^2) ; [Eqn(16)]
fft_theor = FLTARR(na)
;....loop thru each SCALE
FOR a1=0,na-1 DO BEGIN ;scale
psi_fft=CALL_FUNCTION(mother, $
param,scale(a1),k,period1,coi,dofmin,Cdelta,psi0)
IF (do_wave) THEN $
wave(*,a1) = FFT(yfft*psi_fft,1,/DOUBLE) ;wavelet transform[Eqn(4)]
period(a1) = period1 ; save period
fft_theor(a1) = TOTAL((ABS(psi_fft)^2)*fft_theor_k)/n
IF (do_daughter) THEN $
daughter(*,a1) = FFT(psi_fft,1,/DOUBLE) ; save daughter
IF (verbose) THEN PRINT,a1,scale(a1),period(a1), $
TOTAL(ABS(wave(*,a1))^2),CHECK_MATH(0), $
FORMAT='(I3,3F11.3,I6)'
ENDFOR ;scale
coi = coi*[FINDGEN((n1+1)/2),REVERSE(FINDGEN(n1/2))]*dt ; COI [Sec.3g]
IF (do_daughter) THEN $ ; shift so DAUGHTERs are in middle of array
daughter = [daughter(n-n1/2:*,*),daughter(0:n1/2-1,*)]
;....significance levels [Sec.4]
sdev = (MOMENT(y1))(1)
fft_theor = sdev*fft_theor ; include time-series variance
dof = dofmin
signif = fft_theor*CHISQR_CVF(1. - siglvl,dof)/dof ; [Eqn(18)]
IF (recon) THEN BEGIN ; Reconstruction [Eqn(11)]
IF (Cdelta EQ -1) THEN BEGIN
y1 = -1
MESSAGE,/INFO, $
'Cdelta undefined, cannot reconstruct with this wavelet'
ENDIF ELSE BEGIN
y1=dj*SQRT(dt)/(Cdelta*psi0)*(FLOAT(wave) # (1./SQRT(scale)))
y1 = y1[0:n1-1]
ENDELSE
ENDIF
RETURN,wave(0:n1-1,*) ; get rid of padding before returning
END
;************************************************************** WAVE_SIGNIF
;+
; NAME: WAVE_SIGNIF
;
; PURPOSE: Compute the significance levels for a wavelet transform.
;
;
; CALLING SEQUENCE:
;
; result = WAVE_SIGNIF(y,dt,scale,sigtest)
;
;
; INPUTS:
;
; Y = the time series, or, the VARIANCE of the time series.
; (If this is a single number, it is assumed to be the variance...)
;
; DT = amount of time between each Y value, i.e. the sampling time.
;
; SCALE = the vector of scale indices, from previous call to WAVELET.
;
; SIGTEST = 0, 1, or 2. If omitted, then assume 0.
;
; If 0 (the default), then just do a regular chi-square test,
; i.e. Eqn (18) from Torrence & Compo.
; If 1, then do a "time-average" test, i.e. Eqn (23).
; In this case, DOF should be set to NA, the number
; of local wavelet spectra that were averaged together.
; For the Global Wavelet Spectrum, this would be NA=N,
; where N is the number of points in your time series.
; If 2, then do a "scale-average" test, i.e. Eqns (25)-(28).
; In this case, DOF should be set to a
; two-element vector [S1,S2], which gives the scale
; range that was averaged together.
; e.g. if one scale-averaged scales between 2 and 8,
; then DOF=[2,8].
;
;
; OUTPUTS:
;
; result = significance levels as a function of SCALE,
; or if /CONFIDENCE, then confidence intervals
;
;
; OPTIONAL KEYWORD INPUTS:
;
; MOTHER = A string giving the mother wavelet to use.
; Currently, 'Morlet','Paul','DOG' (derivative of Gaussian)
; are available. Default is 'Morlet'.
;
; PARAM = optional mother wavelet parameter.
; For 'Morlet' this is k0 (wavenumber), default is 6.
; For 'Paul' this is m (order), default is 4.
; For 'DOG' this is m (m-th derivative), default is 2.
;
; LAG1 = LAG 1 Autocorrelation, used for SIGNIF levels. Default is 0.0
;
; SIGLVL = significance level to use. Default is 0.95
;
; DOF = degrees-of-freedom for signif test.
; IF SIGTEST=0, then (automatically) DOF = 2 (or 1 for MOTHER='DOG')
; IF SIGTEST=1, then DOF = NA, the number of times averaged together.
; IF SIGTEST=2, then DOF = [S1,S2], the range of scales averaged.
;
; Note: IF SIGTEST=1, then DOF can be a vector (same length as SCALEs),
; in which case NA is assumed to vary with SCALE.
; This allows one to average different numbers of times
; together at different scales, or to take into account
; things like the Cone of Influence.
; See discussion following Eqn (23) in Torrence & Compo.
;
; GWS = global wavelet spectrum. If input then this is used
; as the theoretical background spectrum,
; rather than white or red noise.
;
; CONFIDENCE = if set, then return a Confidence INTERVAL.
; For SIGTEST=0,2 this will be two numbers, the lower & upper.
; For SIGTEST=1, this will return an array (J+1)x2,
; where J+1 is the number of scales.
;
;
; OPTIONAL KEYWORD OUTPUTS:
;
; PERIOD = the vector of "Fourier" periods (in time units) that corresponds
; to the SCALEs.
;
; FFT_THEOR = output theoretical red-noise spectrum as fn of PERIOD.
;
;
;----------------------------------------------------------------------------
;
; EXAMPLE:
;
; IDL> wave = WAVELET(y,dt,PERIOD=period,SCALE=scale)
; IDL> signif = WAVE_SIGNIF(y,dt,scale)
; IDL> signif = REBIN(TRANSPOSE(signif),ntime,nscale)
; IDL> CONTOUR,ABS(wave)^2/signif,time,period, $
; LEVEL=1.0,C_ANNOT='95%'
;
;
;----------------------------------------------------------------------------
; Copyright (C) 1995-1998, Christopher Torrence and Gilbert P. Compo,
; University of Colorado, Program in Atmospheric and Oceanic Sciences.
; This software may be used, copied, or redistributed as long as it is not
; sold and this copyright notice is reproduced on each copy made. This
; routine is provided as is without any express or implied warranties whatsoever.
;
; Notice: Please acknowledge the use of the above software in any publications:
; ``Wavelet software was provided by C. Torrence and G. Compo,
; and is available at URL: http://paos.colorado.edu/research/wavelets/''.
;
;----------------------------------------------------------------------------
;-
;************************************************************* WAVE_SIGNIF
FUNCTION wave_signif,y,dt,scale,sigtest, $ ;*** required inputs
MOTHER=mother,PARAM=param, $ ;*** optional inputs
LAG1=lag1,SIGLVL=siglvl,DOF=dof, $ ;*** optional inputs
GWS=gws,CONFIDENCE=confidence, $ ;*** optional inputs
FFT_THEOR=fft_theor,PERIOD=period, $ ;*** optional outputs
SAVG=Savg,SMID=Smid,CDELTA=CDelta,PSI0=psi0 ;*** optional outputs
ON_ERROR,2
IF (N_ELEMENTS(y) LT 1) THEN MESSAGE,'Time series Y must be input'
IF (N_ELEMENTS(dt) LT 1) THEN MESSAGE,'DT must be input'
IF (N_ELEMENTS(scale) LT 1) THEN MESSAGE,'Scales must be input'
IF (N_PARAMS() LT 4) THEN sigtest = 0 ; the default
IF (N_ELEMENTS(y) EQ 1) THEN variance=y ELSE variance=(MOMENT(y))(1)
;....check keywords & optional inputs
IF (N_ELEMENTS(mother) LT 1) THEN mother = 'MORLET'
IF (N_ELEMENTS(param) LT 1) THEN param = -1
IF (N_ELEMENTS(siglvl) LT 1) THEN siglvl = 0.95
IF (N_ELEMENTS(lag1) LT 1) THEN lag1 = 0.0
confidence = KEYWORD_SET(confidence)
lag1 = lag1(0)
J = N_ELEMENTS(scale) - 1
s0 = MIN(scale)
dj = ALOG(scale(1)/scale(0))/ALOG(2)
CASE (STRUPCASE(mother)) OF
'MORLET': BEGIN
IF (param EQ -1) THEN k0=6d ELSE k0=param
fourier_factor = (4*!PI)/(k0 + SQRT(2+k0^2)) ; [Sec.3h]
empir = [2.,-1,-1,-1]
IF (k0 EQ 6) THEN empir(1:3)=[0.776,2.32,0.60]
END
'PAUL': BEGIN ;****************** PAUL
IF (param EQ -1) THEN m=4d ELSE m=param
fourier_factor = 4*!PI/(2*m+1)
empir = [2.,-1,-1,-1]
IF (m EQ 4) THEN empir(1:3)=[1.132,1.17,1.5]
END
'DOG': BEGIN ;******************* DOG
IF (param EQ -1) THEN m=2 ELSE m=param
fourier_factor = 2*!PI*SQRT(2./(2*m+1))
empir = [1.,-1,-1,-1]
IF (m EQ 2) THEN empir(1:3) = [3.541,1.43,1.4]
IF (m EQ 6) THEN empir(1:3) = [1.966,1.37,0.97]
END
ENDCASE
period = scale*fourier_factor
dofmin = empir(0) ; Degrees of freedom with no smoothing
Cdelta = empir(1) ; reconstruction factor
gamma = empir(2) ; time-decorrelation factor
dj0 = empir(3) ; scale-decorrelation factor
;....significance levels [Sec.4]
freq = dt/period ; normalized frequency
fft_theor = (1-lag1^2)/(1-2*lag1*COS(freq*2*!PI)+lag1^2) ; [Eqn(16)]
fft_theor = variance*fft_theor ; include time-series variance
IF (N_ELEMENTS(gws) EQ (J+1)) THEN fft_theor = gws
signif = fft_theor
CASE (sigtest) OF
0: BEGIN ; no smoothing, DOF=dofmin
dof = dofmin
signif = fft_theor*CHISQR_CVF(1. - siglvl,dof)/dof ; [Eqn(18)]
IF confidence THEN BEGIN
sig = (1. - siglvl)/2.
chisqr = dof/[CHISQR_CVF(sig,dof),CHISQR_CVF(1.-sig,dof)]
signif = fft_theor # chisqr
ENDIF
END
1: BEGIN ; time-averaged, DOFs depend upon scale [Sec.5a]
IF (N_ELEMENTS(dof) LT 1) THEN dof = dofmin
IF (gamma EQ -1) THEN MESSAGE, $
'Gamma (decorrelation factor) not defined for '+mother+ $
' with param='+STRTRIM(param,2)
IF (N_ELEMENTS(dof) EQ 1) THEN dof = FLTARR(J+1) + dof
dof = dof > 1
dof = dofmin*SQRT( 1 + (dof*dt/gamma/scale)^2 ) ; [Eqn(23)]
dof = dof > dofmin ; minimum DOF is dofmin
IF (NOT confidence) THEN BEGIN
FOR a1=0,J DO BEGIN
chisqr = CHISQR_CVF(1. - siglvl,dof(a1))/dof(a1)
signif(a1) = fft_theor(a1)*chisqr
ENDFOR
ENDIF ELSE BEGIN
signif = FLTARR(J+1,2)
sig = (1. - siglvl)/2.
FOR a1=0,J DO BEGIN
chisqr = dof(a1)/ $
[CHISQR_CVF(sig,dof(a1)),CHISQR_CVF(1.-sig,dof(a1))]
signif(a1,*) = fft_theor(a1)*chisqr
ENDFOR
ENDELSE
END
2: BEGIN ; scale-averaged, DOFs depend upon scale range [Sec.5b]
IF (N_ELEMENTS(dof) NE 2) THEN $
MESSAGE,'DOF must be set to [S1,S2], the range of scale-averages'
IF (Cdelta EQ -1) THEN MESSAGE, $
'Cdelta & dj0 not defined for '+mother+ $
' with param='+STRTRIM(param,2)
s1 = dof(0)
s2 = dof(1)
avg = WHERE((scale GE s1) AND (scale LE s2),navg)
IF (navg LT 1) THEN MESSAGE,'No valid scales between ' + $
STRTRIM(s1,2) + ' and ' + STRTRIM(s2,2)
s1 = MIN(scale(avg))
s2 = MAX(scale(avg))
Savg = 1./TOTAL(1./scale(avg)) ; [Eqn(25)]
Smid = EXP((ALOG(s1)+ALOG(s2))/2.) ; power-of-two midpoint
dof = (dofmin*navg*Savg/Smid)*SQRT(1 + (navg*dj/dj0)^2) ; [Eqn(28)]
fft_theor = Savg*TOTAL(fft_theor(avg)/scale(avg)) ; [Eqn(27)]
chisqr = CHISQR_CVF(1. - siglvl,dof)/dof
IF confidence THEN BEGIN
sig = (1. - siglvl)/2.
chisqr = dof/[CHISQR_CVF(sig,dof),CHISQR_CVF(1.-sig,dof)]
ENDIF
signif = (dj*dt/Cdelta/Savg)*fft_theor*chisqr ; [Eqn(26)]
END
ENDCASE
RETURN,signif
END
;****************************************************** WAVE_COHERENCY
;+
; WAVE_COHERENCY
;
; PURPOSE: Compute the wavelet coherency between two time series.
;
;
; CALLING SEQUENCE:
;
; WAVE_COHERENCY, $
; wave1,time1,scale1, $
; wave2,time2,scale2, $
; WAVE_COHER=wave_coher,WAVE_PHASE=wave_phase, $
; TIME_OUT=time_out,SCALE_OUT=scale_out
;
;
; INPUTS:
;
; WAVE1 = wavelet power spectrum for time series #1
; TIME1 = a vector of times for time series #1
; SCALE1 = a vector of scales for time series #1
; WAVE2 = wavelet power spectrum for time series #2
; TIME2 = a vector of times for time series #2
; SCALE2 = a vector of scales for time series #2
;
;
; OPTIONAL KEYWORD INPUTS:
;
; DT = amount of time between each Y value, i.e. the sampling time.
; If not input, then calculated from TIME1(1)-TIME1(0)
;
; DJ = the spacing between discrete scales.
; If not input, then calculated from SCALE1
;
; VERBOSE = if set, then print out the scales and system time
;
; NOSMOOTH = if set, then just compute the GLOBAL_COHER, GLOBAL_PHASE,
; and the unsmoothed CROSS_WAVELET and return
;
;
; OPTIONAL KEYWORD OUTPUTS:
;
; WAVE_COHER = the wavelet coherency, as a function of
; TIME_OUT and SCALE_OUT
;
; TIME_OUT = the time vector, given by the overlap of TIME1 and TIME2
;
; SCALE_OUT = the scale vector of scale indices, given by the overlap
; of SCALE1 and SCALE2
;
; COI_OUT = the vector of the cone-of-influence
;
; GLOBAL_COHER = the global (or mean) coherence averaged over all times.
;
; GLOBAL_PHASE = the global (or mean) phase averaged over all times
;
; CROSS_WAVELET = the cross wavelet between the time series
;
; POWER1 = the wavelet power spectrum; should be the same as WAVE1
; if TIME1 and TIME2 are identical, otherwise it is only the
; overlapping portion. If NOSMOOTH is set,
; then this is unsmoothed, otherwise it is smoothed.
;
; POWER2 = same as POWER1 but for time series #2
;
;
;----------------------------------------------------------------------------
; Copyright (C) 1998-2005, Christopher Torrence
; This software may be used, copied, or redistributed as long as it is not
; sold and this copyright notice is reproduced on each copy made. This
; routine is provided as is without any express or
; implied warranties whatsoever.
;
; Reference: Torrence, C. and P. J. Webster, 1999: Interdecadal changes in the
; ENSO-monsoon system. J. Climate, 12, 2679-2690.
;
; Please send a copy of any publications to C. Torrence:
; Dr. Christopher Torrence
; Research Systems, Inc.
; 4990 Pearl East Circle
; Boulder, CO 80301, USA
; E-mail: chris[AT]rsinc[DOT]com
;----------------------------------------------------------------------------
;-
;****************************************************************** WAVELET
PRO wave_coherency, $
wave1,time1,scale1,wave2,time2,scale2, $ ;*** required inputs
COI1=coi1, $
DT=dt,DJ=dj, $
WAVE_COHER=wave_coher,WAVE_PHASE=wave_phase, $
TIME_OUT=time_out,SCALE_OUT=scale_out,COI_OUT=coi_out, $
GLOBAL_COHER=global_coher,GLOBAL_PHASE=global_phase, $
CROSS_WAVELET=cross_wavelet,POWER1=power1,POWER2=power2, $
NOSMOOTH=nosmooth, $
VERBOSE=verbose
; ON_ERROR,2
verbose = KEYWORD_SET(verbose)
;*** find overlapping times
time_start = MIN(time1) > MIN(time2)
time_end = MAX(time1) < MAX(time2)
time1_start = MIN(WHERE((time1 GE time_start)))
time1_end = MAX(WHERE((time1 LE time_end)))
time2_start = MIN(WHERE((time2 GE time_start)))
time2_end = MAX(WHERE((time2 LE time_end)))
;*** find overlapping scales
scale_start = MIN(scale1) > MIN(scale2)
scale_end = MAX(scale1) < MAX(scale2)
scale1_start = MIN(WHERE((scale1 GE scale_start)))
scale1_end = MAX(WHERE((scale1 LE scale_end)))
scale2_start = MIN(WHERE((scale2 GE scale_start)))
scale2_end = MAX(WHERE((scale2 LE scale_end)))
;*** cross wavelet & individual wavelet power
cross_wavelet = wave1(time1_start:time1_end,scale1_start:scale1_end)*$
CONJ(wave2(time2_start:time2_end,scale2_start:scale2_end))
power1 = ABS(wave1(time1_start:time1_end,scale1_start:scale1_end))^2
power2 = ABS(wave2(time2_start:time2_end,scale2_start:scale2_end))^2
IF (N_ELEMENTS(dt) LE 0) THEN dt = time1(1) - time1(0)
ntime = time1_end - time1_start + 1
nj = scale1_end - scale1_start + 1
IF (N_ELEMENTS(dj) LE 0) THEN dj = ALOG(scale1(1)/scale1(0))/ALOG(2)
scale = scale1(scale1_start:scale1_end)
IF (verbose) THEN PRINT,dt,ntime,dj,nj
time_out = time1(time1_start:time1_end)
scale_out = scale1(scale1_start:scale1_end)
IF (N_ELEMENTS(coi1) EQ N_ELEMENTS(time1)) THEN $
coi_out = coi1(time1_start:time1_end)
; calculate global coherency before doing local smoothing
global1 = TOTAL(power1,1)
global2 = TOTAL(power2,1)
global_cross = TOTAL(cross_wavelet,1)
global_coher = ABS(global_cross)^2/(global1*global2)
global_phase = 180./!PI*ATAN(IMAGINARY(global_cross),FLOAT(global_cross))
IF KEYWORD_SET(nosmooth) THEN RETURN
FOR j=0,nj-1 DO BEGIN ;*** time-smoothing
st1 = SYSTIME(1)
nt = LONG(4L*scale(j)/dt)/2L*4 + 1L
time_wavelet = (FINDGEN(nt) - nt/2)*dt/scale(j)
wave_function = EXP(-time_wavelet^2/2.) ;*** Morlet
wave_function = FLOAT(wave_function/TOTAL(wave_function)) ; normalize
nz = nt/2
zeros = COMPLEX(FLTARR(nz),FLTARR(nz))
cross_wave_slice = [zeros,cross_wavelet(*,j),zeros]
cross_wave_slice = CONVOL(cross_wave_slice,wave_function)
cross_wavelet(*,j) = cross_wave_slice(nz:ntime+nz-1)
zeros = FLOAT(zeros)
power_slice = [zeros,power1(*,j),zeros]
power_slice = CONVOL(power_slice,wave_function)
power1(*,j) = power_slice(nz:ntime + nz - 1)
power_slice = [zeros,power2(*,j),zeros]
power_slice = CONVOL(power_slice,wave_function)
power2(*,j) = power_slice(nz:ntime + nz - 1)
IF (verbose) THEN PRINT,j,scale(j),SYSTIME(1)-st1;,FORMAT='(I4,$)'
ENDFOR ;*** time-smoothing
;*** normalize by scale
scales = REBIN(TRANSPOSE(scale),ntime,nj)
cross_wavelet = TEMPORARY(cross_wavelet)/scales
power1 = TEMPORARY(power1)/scales
power2 = TEMPORARY(power2)/scales
nweights = FIX(0.6/dj/2 + 0.5)*2 - 1 ; closest (smaller) odd integer
weights = REPLICATE(1.,nweights)
weights = weights/TOTAL(weights) ; normalize
FOR i=0,ntime-1 DO BEGIN ;*** scale-smoothing
cross_wavelet(i,*) = CONVOL((cross_wavelet(i,*))(*),weights)
power1(i,*) = CONVOL((power1(i,*))(*),weights)
power2(i,*) = CONVOL((power2(i,*))(*),weights)
ENDFOR ;*** scale-smoothing
wave_phase = 180./!PI*ATAN(IMAGINARY(cross_wavelet),FLOAT(cross_wavelet))
wave_coher = (ABS(cross_wavelet)^2)/(power1*power2 > 1E-9)
; wave_phase = wave_phase + 360.*(wave_phase LT 0.)
END