*! cospectdens computes cross-periodogram and cross-spectral density estimate (co-spectrum) *! v.1.0 Apr 1, 2016 Huseyin Tastan (tastan@yildiz.edu.tr) *! v.1.1 May 25, 2016 Fixed the problem with saving output dta file cap program drop cospectdens program define cospectdens, rclass version 12 syntax varlist(ts) [if] [in] [, /// Meanadj /// DETrend /// Weights(string) /// Kernel(string) /// Bandwidth(integer 0) /// CONVdaniell(numlist >0 integer) /// out(string) /// noGRAPH /// Replace ] marksample touse qui count if `touse' local n = r(N) local m = floor(`n'/2) local mm = `m' + 1 if `mm'>400 { set matsize `mm' } if `n' == 0 { error 2000 } _ts timevar, sort markout `touse' `timevar' tsreport if `touse', report if r(N_gaps) { di in red "Sample may not contain gaps" exit } local nogr "`graph'" // default is graph local ww "`weights'" if "`ww'" != "" & "`kernel'" != "" & "`convdaniell'" != ""{ di in red "Choose only one: weights or kernel type-bandwidth or convolution" error 184 } if "`ww'" != "" & "`kernel'" != "" { di in red "Choose only one: weights or kernel type-bandwidth or convolution" error 184 } if "`kernel'" != "" & "`convdaniell'" != ""{ di in red "kernel type-bandwidth cannot be used with convolution" error 184 } if "`ww'" != "" & "`convdaniell'" != ""{ di in red "Weights and convdaniell cannot be used together" error 184 } if "`ww'" == "" & "`kernel'" == "" & "`convdaniell'" == "" { local kernel "daniell" // default is Daniell kernel if no option input di "Using default Daniell (uniform) kernel" } if "`ww'" != "" & "`kernel'" == "" & "`convdaniell'" == ""{ * check if weights supplied by the user include < or > if regexm("`ww'","<")==0 { di as err "missing < in weights()" di as err "weights(`weights') invalid" error 198 } if regexm("`ww'",">")==0 { di as err "missing > in weights()" di as err "weights(`weights') invalid" error 198 } if regexm("`ww'","/")==1 { di as err "Do not use / in weights()" di as err "weights(`weights') invalid" error 198 } local nw = wordcount("`ww'") if mod(`nw',2)!=1 { di as err "Total window length in weights() should be an odd number" di as err "weights(`weights') invalid" error 198 } local wei = regexr(regexr("`ww'", "<", " "), ">", " ") tempname wvec mat `wvec' = J(`nw',1,0) local bw = (`nw'-1)/2 local ind=0 foreach v of local wei { local ind = `ind'+1 mat `wvec'[`ind',1] = `v' } local nte "Weigths = `ww'" } // convolution of uniform weights if "`convdaniell'" != "" & "`ww'" == "" & "`kernel'" == "" { tempname conv wvec local bw "" local np: word count `convdaniell' tokenize `convdaniell' if `np'<1 { di in red "Convolution incorrectly specified" error 198 } if `np'==1 { // di "Using Daniell kernel with half-window `1'" _convdaniell `1' 0 mat `conv' = c } if `np'==2 { _convdaniell `1' `2' mat `conv' = c } if `np'>2 { forv k=1(1)`np' { tempname u`k' v`k' _convdaniell ``k'' 0 mat `u`k'' = c } _convvector `u1' `u2' mat `v1' = c forv k=3(1)`np' { local kk = `k'-1 local kkk = `k'-2 _convvector `v`kkk'' `u`k'' mat `v`kk'' = c } mat `conv' = `v`kk'' } mat `wvec' = `conv' local nte "Convolution of Daniell kernel, lags = `convdaniell'" return local kernel `"convdaniell"' return local lags = `"`convdaniell'"' local bw = (rowsof(`wvec')-1)/2 } if "`kernel'"!="" & "`ww'" == "" & "`convdaniell'" == ""{ if "`kernel'"=="daniell" { local bw = ceil(0.5*`mm'^(1/3)) if `bandwidth' !=0 { local bw = `bandwidth' } tempname wvec mat `wvec' = J((2*`bw'+1),1,0) local ind=0 forv q =-`bw'(1)`bw' { local bb = 1/(2*`bw'+1) local ind = `ind'+1 mat `wvec'[`ind',1] = `bb' } } if "`kernel'"=="mdaniell" { local bw = ceil(0.5*`mm'^(1/3)) if `bandwidth' !=0 { local bw = `bandwidth' } tempname wvec mat `wvec' = J((2*`bw'+1),1,0) local ind=0 forv q =-`bw'(1)`bw' { local ind = `ind'+1 if `q'==-`bw'{ mat `wvec'[`ind',1] = 1/(4*`bw') } if `q'>-`bw' & `q'<0{ mat `wvec'[`ind',1] = 1/(2*`bw') } if `q'==0{ mat `wvec'[`ind',1] = 1/(2*`bw') } if `q'<`bw' & `q'>0{ mat `wvec'[`ind',1] = 1/(2*`bw') } if `q'==`bw'{ mat `wvec'[`ind',1] = 1/(4*`bw') } } } if "`kernel'"=="bartlett" { local bw = ceil(0.5*`mm'^(1/3)) if `bandwidth' !=0 { local bw = `bandwidth' } tempname wvec mat `wvec' = J((2*`bw'+1),1,0) local ind=0 forv q =-`bw'(1)`bw' { local ind = `ind'+1 mat `wvec'[`ind',1] = 1-abs(`q'/(`bw'+1)) } } if "`kernel'"=="parzen" { local bw = ceil(`mm'^(1/5)) if `bandwidth' !=0 { local bw = `bandwidth' } tempname wvec mat `wvec' = J((2*`bw'+1),1,0) local ind=0 forv q =-`bw'(1)`bw' { local ind = `ind'+1 local c = abs(`q'/(`bw'+1)) if `c'>=0 & `c'<0.5 { local bb = 1-6*`c'^2+6*`c'^3 } else if `c'>=0.5 & `c'<=1 { local bb = 2*(1-`c')^3 } else { local bb = 0 } mat `wvec'[`ind',1] = `bb' } } if "`kernel'"=="tukey" { local bw = ceil((2/3)*`mm'^(1/5)) if `bandwidth' !=0 { local bw = `bandwidth' } tempname wvec mat `wvec' = J((2*`bw'+1),1,0) local ind=0 forv q =-`bw'(1)`bw' { local ind = `ind'+1 local c = `q'/(`bw'+1) if `c'<=1 { local bb = (1+cos(_pi*`c'))/2 } else { local bb = 0 } mat `wvec'[`ind',1] = `bb' } } if "`kernel'"=="qs" { local bw = ceil((1/2)*`mm'^(1/5)) if `bandwidth' !=0 { local bw = `bandwidth' } tempname wvec mat `wvec' = J((2*`bw'+1),1,0) local ind=0 forv q =-`bw'(1)`bw' { local ind = `ind'+1 local c = abs(`q'/`bw') if `c'!=0 { local bb = (25/(12*_pi^2*`c'^2))*((sin(6*_pi*`c'/5)/(6*_pi*`c'/5)) - cos(6*_pi*`c'/5)) } else { local bb = 1 } mat `wvec'[`ind',1] = `bb' } } local nte "kernel(lag) = `kernel'(`bw')" return local kernel `"`kernel'"' return scalar halfbw = `bw' } // change row names of the weight vector local rnames = "" local rr=(rowsof(`wvec')-1)/2 forv q =-`rr'(1)`rr' { local rnames = "`rnames' `q'" } mat rownames `wvec' = `rnames' preserve tempvar x xvar y yvar trend freq omega wave k xa xb ya yb /// Pxreal Pximaginary Px Pyreal Pyimaginary Py /// Sx Sy Jreal Jimaginary Cospect Quadspect Amp K2 /// phase phasedif gain critKsq /// tempname Pmat Pmat2 Smat local nvars : word count `varlist' if `nvars'<2{ di in red "At least 2 variables needed" error 198 exit } else if `nvars'==2{ tokenize `varlist' local y `1' local x `2' } else if `nvars'>2{ di in red "At most 2 variables needed" error 198 exit } qui{ keep if `touse' if "`meanadj'" == "" & "`detrend'" == "" { gen double `xvar' = `x' if `touse' gen double `yvar' = `y' if `touse' } if "`meanadj'" != "" & "`detrend'" == "" { sum `x' if `touse', meanonly gen double `xvar' = `x'-r(mean) if `touse' sum `y' if `touse', meanonly gen double `yvar' = `y'-r(mean) if `touse' } if "`detrend'" != "" { gen double `trend' = _n if `touse' reg `x' `trend' if `touse' predict `xvar' if `touse', resid reg `y' `trend' if `touse' predict `yvar' if `touse', resid } gen double `k' = _n - 1 in 1/`mm' gen double `freq' = `k'/`n' gen double `omega' = 2*_pi*`freq' gen double `wave' = 1/`freq' label var `omega' "Frequency" label var `wave' "Wavelength (Period)" label var `k' "k=0,1,2,...,floor(N/2)" label var `freq' "Natural frequency" fft `xvar' if `touse', gen(`xa' `xb') gen double `Pxreal' = (2/`n')*`xa' in 1/`mm' gen double `Pximaginary' = -(2/`n')*`xb' in 1/`mm' gen double `Px' = (`n'/2)*(`Pxreal'^2 + `Pximaginary'^2) label var `Pxreal' "Real part of periodogram of `x'" label var `Pximaginary' "Imaginary part of peridogram of `x'" label var `Px' "Periodogram of `x'" fft `yvar' if `touse', gen(`ya' `yb') gen double `Pyreal' = (2/`n')*`ya' in 1/`mm' gen double `Pyimaginary' = -(2/`n')*`yb' in 1/`mm' gen double `Py' = (`n'/2)*(`Pyreal'^2 + `Pyimaginary'^2) label var `Pyreal' "Real part of periodogram of `y'" label var `Pyimaginary' "Imaginary part of peridogram of `y'" label var `Py' "Periodogram of `y'" gen double `Jreal' = (`n'/2)*(`Pxreal'*`Pyreal' + `Pximaginary'*`Pyimaginary') gen double `Jimaginary' = (`n'/2)*(`Pxreal'*`Pyimaginary' - `Pximaginary'*`Pyreal') label var `Jreal' "Real part of cross-periodogram" label var `Jimaginary' "Imaginary part of cross-periodogram" // use second pergram ordinate in place of first (omega=0) for smoothing local Px1 = `Px'[1] replace `Px' = `Px'[2] in 1 local Py1 = `Py'[1] replace `Py' = `Py'[2] in 1 local Jreal1 = `Jreal'[1] replace `Jreal' = `Jreal'[2] in 1 keep in 1/`mm' gen double `Sx' = . gen double `Sy' = . gen double `Cospect' = . gen double `Quadspect' = . * use cyclical endpoints mata: smoothdens("`Px'", "`Sx'") local wssq = r(wssq) local dof = 2/`wssq' mata: smoothdens("`Py'", "`Sy'") mata: smoothdens("`Jreal'", "`Cospect'") mata: smoothdens2("`Jimaginary'", "`Quadspect'") gen double `Amp' = sqrt(`Cospect'^2 + `Quadspect'^2) gen double `K2' = `Amp'^2 / (`Sx'*`Sy') gen double `phase' = atan(`Quadspect'/`Cospect') gen double `phasedif' = `phase'/`omega' gen double `gain' = abs(`Amp')/`Sx' label var `Sx' "Spectral density of `x'" label var `Sy' "Spectral density of `y'" label var `Cospect' "Co-spectrum between `x' and `y'" label var `Quadspect' "Quadrature Spectrum" label var `Amp' "Amplitude of cross-spectrum" label var `K2' "Coherency-Squared" label var `phase' "Phase spectrum" label var `phasedif' "Phase difference in time units" // if phasedif>0 then x is leading y and vice versa label var `gain' "Gain spectrum" // slope from spectral reg of y on x replace `Px' = `Px1' in 1 // re-replace periodogram at freq 0 replace `Py' = `Py1' in 1 replace `Jreal' = `Jreal1' in 1 mkmat `k' `freq' `omega' `wave' `Jreal' `Jimaginary' `Cospect' `Quadspect' `Amp' `K2' `phase', matrix(`Pmat') //nomissing matname `Pmat' k freq omega wave Jreal Jimaginary Cospect Quadspect Amp K2 phase, c(.) e ret mat P = `Pmat' matname `wvec' weights, c(.) e ret mat W = `wvec' ret scalar N = `n' ret scalar dof = `dof' // confidence interval for phase spectrum tempvar phase_ phase_L phase_U // Formula on p.219 Bloomfield (eq.10.11) // gen double `phase_' = (1.96/2*_pi)*sqrt((`wssq'/2)*((1/`K2')-1)) // Formula on p.219 Bloomfield (eq.10.12) (better approx.) gen double `phase_' = (1/(2*_pi))*asin(invttail(`dof'-2,0.05)*sqrt((`wssq'/(2*(1-`wssq')))*(1/`K2'-1))) gen double `phase_L' = `phase' - `phase_' gen double `phase_U' = `phase' + `phase_' label var `phase_L' "Lower bound of the 95% CI for phase spectrum" label var `phase_U' "Upper bound of the 95% CI for phase spectrum" // Note that phase should be interpreted at the frequencies where K2 is significant // the following is valid if weights are equal // local Fcv = invF(2,4*`bw',0.95) // gen double `critKsq' = `Fcv'/(2*`bw'+`Fcv') // 5% threshold value for the significance of Cohsq for general weight function (Bloomfield, 2000, p.221) gen double `critKsq' = 1-20^(-(`wssq'/(1-`wssq'))) label var `critKsq' "5% Threshold value" // graph if "`nogr'" == ""{ cap graph drop _all tw (connected `K2' `freq') (line `critKsq' `freq'), ylabel(0(0.1)1) /// note("Note: Values of coherency-squared above threshold are significant at 5% level" /// "`nte'") } } if "`out'" != ""{ keep `k' `freq' `omega' `wave' `Pxreal' `Pximaginary' `Pyreal' `Pyimaginary' /// `Px' `Py' `Sx' `Sy' `Jreal' `Jimaginary' `Cospect' `Quadspect' `K2' /// `critKsq' `Amp' `phase' `phase_L' `phase_U' `phasedif' `gain' rename `k' kindex rename `freq' naturalfreq rename `omega' Fourierfreq rename `wave' period rename `Pxreal' Pxreal rename `Pximaginary' Pximag rename `Pyreal' Pyreal rename `Pyimaginary' Pyimag rename `Px' Pgramx rename `Py' Pgramy rename `Sx' Spdensx rename `Sy' Spdensy rename `Jreal' Jreal rename `Jimaginary' Jimag rename `Cospect' Cospect rename `Quadspect' Quadspect rename `K2' Cohsq rename `critKsq' Cohsq_threshold rename `Amp' Amplitude rename `phase' Phase rename `phasedif' PhaseDiff rename `gain' Gain rename `phase_L' phase_L rename `phase_U' phase_U capture confirm file "`out'.dta" if _rc==0 { if "`replace'" != "" { qui save `"`out'"', replace } else { di as error "File `out'.dta already exists" exit } } else { qui save `"`out'"' } } restore end // sub-programs program define _convdaniell args c1 c2 local m = 2*`c1'+1 local n = 2*`c2'+1 tempname a b c mat `a' = J(`m',1,1/`m') mat `b' = J(`n',1,1/`n') local h = max(`m'+`n'-1,`m',`n') mat c = J(`h',1,0) forv k=1(1)`h' { local sum = 0 forv j=1(1)`m' { if `k'>=`j' & (`k'-`j'+1)<=`n' { local sum = `sum' + `a'[`j',1]*`b'[`k'-`j'+1,1] } } mat c[`k',1] = `sum' } end program define _convvector args u v local m = rowsof(`u') local n = rowsof(`v') local h = max(`m'+`n'-1,`m',`n') mat c = J(`h',1,0) forv k=1(1)`h' { local sum = 0 forv j=1(1)`m' { if `k'>=`j' & (`k'-`j'+1)<=`n' { local sum = `sum' + `u'[`j',1]*`v'[`k'-`j'+1,1] } } mat c[`k',1] = `sum' } end version 12 mata: void smoothdens(string scalar varname1, string scalar varname2) { w = st_matrix(st_local("wvec")) w = w/colsum(w) q = rows(w) b = (q-1)/2 Pmat = st_data(., varname1) real matrix S st_view(S=.,., varname2) m = rows(Pmat) P = Pmat[(1..m),.] P = (P[(b+1..2),.]\P\P[(m-1..m-b),.]) for(i=1+b; i<=m+b; i++) { S[i-b,.] = w'*P[(i-b..i+b),.] :/(4*pi()) } st_numscalar("r(wssq)",w'*w) st_replacematrix(st_local("wvec"),w) } end version 12 mata: void smoothdens2(string scalar varname1, string scalar varname2) { w = st_matrix(st_local("wvec")) w = w/colsum(w) q = rows(w) b = (q-1)/2 Pmat = st_data(., varname1) real matrix S st_view(S=.,., varname2) m = rows(Pmat) P = Pmat[(1..m),.] P = (-1*P[(b+1..2),.]\P\-1*P[(m-1..m-b),.]) for(i=1+b; i<=m+b; i++) { S[i-b,.] = w'*P[(i-b..i+b),.] :/(4*pi()) } st_numscalar("r(wssq)",w'*w) st_replacematrix(st_local("wvec"),w) } end