;******************************************************************* 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. ; Its units are sigma^2 (the time series variance). ; ; ; 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 ; ; DOF = degrees-of-freedom for signif test. Default is 2 (1 for DOG), which ; indicates no smoothing. If one has averaged over N times, ; then /GLOBAL should be set, and DOF should be set to N (*not* 2N). ; The actual DOFs are then computed using Eqn(23). ; ; GLOBAL = if set, then assume that wavelet has been globally smoothed, or ; averaged in time (see DOF above), and use Eqn(23). ; ; VERBOSE = if set, then print out info for each analyzed scale. ; ; ; 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 red-noise spectrum as fn 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-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/''. ; ; Reference: Torrence, C. and G. P. Compo, 1998: A Practical Guide to ; Wavelet Analysis. Bull. Amer. Meteor. Soc., 79, xx-xx. ; ; Please send a copy of such publications to either C. Torrence or G. Compo: ; Dr. Christopher Torrence Dr. Gilbert P. Compo ; Advanced Study Program Campus Box 311 ; National Center for Atmos. Research Program in Atmos. and Oceanic Sciences ; P.O. Box 3000 University of Colorado at Boulder ; Boulder CO 80307--3000, USA. Boulder CO 80309-0311, USA. ; E-mail: torrence@ucar.edu E-mail: compo@monsoon.colorado.edu ;---------------------------------------------------------------------------- ;- FUNCTION morlet,k0,a,k,period,coi,dofmin,gamma ;*********************** MORLET IF (k0 EQ -1) THEN k0 = 6d n = N_ELEMENTS(k) expnt = -(a*k - k0)^2/2d*(k GT 0.) norm = SQRT(a*k(1))*(!PI^(-0.25))*SQRT(n) ; 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 = a*fourier_factor coi = fourier_factor/SQRT(2) ; Cone-of-influence [Sec.3g] dofmin = 2 ; Degrees of freedom with no smoothing IF (k0 EQ 6) THEN gamma = 2.32 ELSE gamma=-1 ; decorrelation factor ; PRINT,a,SQRT(TOTAL(morlet^2,/DOUBLE))*SQRT(n) RETURN,morlet END FUNCTION paul,m,a,k,period,coi,dofmin,gamma ;************************** PAUL IF (m EQ -1) THEN m = 4d n = N_ELEMENTS(k) expnt = -(a*k)*(k GT 0.) norm = SQRT(a*k(1))*(2^m/SQRT(m*FACTORIAL(2*m-1)))*SQRT(n) paul = norm*((a*k)^m)*EXP(expnt > (-100d))*(expnt GT -100) paul = paul*(k GT 0.) fourier_factor = 4*!PI/(2*m+1) period = a*fourier_factor coi = fourier_factor dofmin = 2 ; Degrees of freedom with no smoothing IF (m EQ 4) THEN gamma=1.17 ELSE gamma=-1 ; decorrelation factor ; PRINT,a,N_ELEMENTS(k),SQRT(TOTAL(paul^2,/DOUBLE))*SQRT(n) RETURN,paul END FUNCTION dog,m,a,k,period,coi,dofmin,gamma ;*************************** DOG IF (m EQ -1) THEN m = 2 n = N_ELEMENTS(k) expnt = -(a*k)^2/2d norm = SQRT(a*k(1)/GAMMA(m+0.5))*SQRT(n) I = DCOMPLEX(0,1) gauss = -norm*(I^m)*(a*k)^m*EXP(expnt > (-100d))*(expnt GT -100) fourier_factor = 2*!PI*SQRT(2./(2*m+1)) period = a*fourier_factor coi = fourier_factor dofmin = 1 ; Degrees of freedom with no smoothing gamma = -1 IF (m EQ 2) THEN gamma=1.43 ; decorrelation factor IF (m EQ 6) THEN gamma=1.37 ; decorrelation factor ; PRINT,a,N_ELEMENTS(k),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, $ ;*** optional inputs SCALE=scale,PERIOD=period,YPAD=ypad, $ ;*** optional outputs DAUGHTER=daughter,COI=coi, $ ;*** optional outputs LAG1=lag1,SIGLVL=siglvl,DOF=dof,GLOBAL=global, $ ;*** optional inputs SIGNIF=signif,FFT_THEOR=fft_theor, $ ;*** optional outputs YFFT = yfft, $ ;*** optional output NO_WAVE=no_wave, $ ;*** optional inputs OCT=oct,VOICE=voice ;*** defunct inputs r = CHECK_MATH(0,1) n = N_ELEMENTS(y1) n1 = n ;....check keywords & optional inputs IF (N_ELEMENTS(s0) LT 1) THEN s0 = 2*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 = oct/dj IF (N_ELEMENTS(J) LT 1) THEN J=FIX((ALOG(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 verbose = KEYWORD_SET(verbose) do_daughter = KEYWORD_SET(daughter) do_wave = NOT KEYWORD_SET(no_wave) ;....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 if pad eq 1 then base2 = FIX(ALOG(n)/ALOG(2) + 0.4999)+1 ; power of 2 nearest to N if pad eq 2 then base2= FIX(ALOG(n)/ALOG(2))+1 ; next highest power of 2base2-1 ypad = [ypad,FLTARR(2L^(base2) - 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)/n/dt*2*!PI 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=',J IF (n1 NE n) THEN PRINT,'(padded with ',n-n1,' zeroes)' PRINT,['a1','a','period','totvar','mathflag'], $ FORMAT='(/,A2,A6,A10,A9,A9)' ENDIF ;verbose ;....loop thru each SCALE FOR a1=0,na-1 DO BEGIN ;scale psi_fft=CALL_FUNCTION(mother,param,scale(a1),k,period1,coi,dofmin,gamma) IF (do_wave) THEN $ wave(*,a1) = FFT(yfft*psi_fft,1,/DOUBLE) ;wavelet transform[Eqn(4)] period(a1) = period1 ; save period 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='(I2,f,f,f,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,*)] ;....confidence 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 = STDEV(y1)^2*fft_theor ; include time-series variance signif = fft_theor IF (N_ELEMENTS(dof) LT 1) THEN dof = dofmin IF (NOT(KEYWORD_SET(global))) THEN BEGIN ; no smoothing, DOF=2 signif = fft_theor*CHISQR_CVF(1. - siglvl,dof)/dof ; [Eqn(18)] ENDIF ELSE BEGIN ; smoothing, DOFs depend upon scale [Sec.5] 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(na) + dof dof = dof > 1 dof = dofmin*SQRT( 1 + (dof*dt/gamma/scale)^2 ) ; [Eqn(23)] dof = dof > dofmin ; minimum DOF is dofmin FOR a1=0,na-1 DO BEGIN chisqr = CHISQR_CVF(1. - siglvl,dof(a1))/dof(a1) signif(a1) = fft_theor(a1)*chisqr ENDFOR ENDELSE RETURN,wave(0:n1-1,*) ; get rid of padding before returning END