;+ ;NAME: ; dpwrspc ;PURPOSE: ; Called with times time and data quantity, dpwrspc returns a dps ; spectrum at frequencies fdps. A Hanning window is applied to the ; input data, and its power is divided out of the returned ; spectrum. A straight line is subtracted from the data to reduce ; spurious power due to sawtooth behavior of a background. UNITS ; ARE (UNITS)^2 WHERE UNITS ARE THE UNITS OF time. fdps is in ; Hz. THUS THE OUTPUT REPRESENTS THE MEAN SQUARED AMPLITUDE OF THE ; SIGNAL AT EACH SPECIFIC FREQUENCY. THE TOTAL (SUM) POWER UNDER ; THE CURVE IS EQUAL TO THE MEAN (OVER TIME) POWER OF THE ; OSCILLATION IN TIME DOMAIN. NOTE: IF KEYWORD notperhz IS SET, ; THEN POWER IS IN UNITS OF NT^2 ELSE IT IS IN UNITS OF NT^2/HZ. ;CALLING SEQUENCE: ; dpwrspc, time, quantity, tdps, fdps, dps, nboxpoints = nboxpoints, $ ; nshiftpoints = nshiftpoints, bin = bin, tbegin = tbegin,$ ; tend = tend, noline = noline, nohanning = nohanning, $ ; notperhz = notperhz ;INPUT: ; time = the time array ; quantity = the function for which you want to obtain a power ; spectrum ;OUTPUT: ; tps = the time array for the dynamic power spectrum, the center time ; of the interval used for the spectrum ; fdps = the frequency array (units =1/time units) ; dps = the power spectrum, (units of quantity)^2/frequency_units ;KEYWORDS: ; nboxpoints = the number of points to use for the hanning window, the ; default is 256 ; nshiftpoints = this is the number of points to shift for each ; spectrum, the first spectrum will cover the range ; from 0 to nboxpoints, then next will cover the range ; from nshiftpoints to nshiftpoints+nboxpoints, etc.. ; the default is 128. ; bin = a binsize for binning of the data along the frequency domain, ; the default is 3 ; tbegin = a start time, the default is time[0] ; tend = an end time, the default is time[n_elements(time)-1] ; noline = if set, no straight line is subtracted ; nohanning = if set, then no hanning window is applied to the input ; notperhz = if set, the output units are simply the square of the ; input units ; noTmVariance = if set replaces output spectrum for any windows that ; have variable cadence with NaNs ; tm_sensitivity = If noTmVariance is set, this number controls ; how much of a dt anomaly is accepted. The ; program will flag a time resolution ; discontinuity if the time resolution dt ; changes by a value greater than ; dt/dt_sensitivity; the default ; is 100.0; i.e. If, for a given spectrum, if ; there are points with abs(dt[i]-median(dt) ; Gt median(dt)/100.0, then this will ; be set to NaN. A larger value means ; more sensitivity. If you want to flag round-off ; errors then try a value of 1.0e8. ; fail = if set to a named variable, returns 1 if an error occurs, 0 otherwise ; ;$LastChangedBy: $ ;$LastChangedDate: $ ;$LastChangedRevision: $ ;$URL: $ ; ;- pro dpwrspc, time, quantity, tdps, fdps, dps, nboxpoints = nboxpoints, $ nshiftpoints = nshiftpoints, bin = bin, tbegin = tbegin, $ tend = tend, noline = noline, nohanning = nohanning, $ notperhz = notperhz, fail = fail, noTmVariance = noTmVariance,$ tm_sensitivity = tm_sensitivity, _extra = _extra ; fail = 1 tdps = -1 & fdps = -1 & dps = -1 ;init output variables if keyword_set(tend) then begin t2 = tend endif else begin t2 = time[n_elements(time)-1] endelse ; if keyword_set(tbegin) then begin t1 = tbegin endif else begin t1 = time[0] endelse ; igood = where((time ge t1) and (time le t2), jgood) if (jgood gt 0) then begin time2process = time[igood] quantity2process = quantity[igood] endif else begin dprint, 'tbegin or tend incompatible with time array' return endelse ; if keyword_set(nboxpoints) then begin nboxpnts = nboxpoints endif else begin nboxpnts = 256 endelse ; if keyword_set(nshiftpoints) then begin nshiftpnts = nshiftpoints endif else begin nshiftpnts = 128 endelse ; if keyword_set(bin) then begin binsize = bin endif else begin binsize = 3 endelse ; if not(keyword_set(nohanning)) then window = hanning(nboxpnts) ; nboxpnts = long(nboxpnts) nshiftpnts = long(nshiftpnts) totalpoints = n_elements(time2process) nspectra = long((totalpoints-nboxpnts/2l)/nshiftpnts) ;test nspectra, if the value of nshiftpnts is much smaller than ;nboxpnts/2 strange things happen nbegin = nshiftpnts*lindgen(nspectra) nend = nbegin+nboxpnts-1l okspec = where(nend le totalpoints-1, nspectra) if(nspectra le 0) then begin dprint, 'Not enough points for a calculation' return endif tdps = dblarr(nspectra) nfreqs = long((long(nboxpnts/2l))/binsize) if(nfreqs Le 1) then begin dprint, 'Not enough frequencies for a calculation' return endif dps = fltarr(nspectra, nfreqs) fdps = dps ; for nthspectrum = 0l, nspectra-1l do begin ; nbegin = long(nthspectrum*nshiftpnts) nend = nbegin+nboxpnts-1l ; if(nend le totalpoints-1) then begin t = double(time2process[nbegin:nend]) t0 = t[0] t = t-t0 x = double(quantity2process[nbegin:nend]) ;Use center time tdps[nthspectrum] = double(time2process[nbegin]+time2process[nend])/2.0 if not(keyword_set(noline)) then begin c = linfit(t, x, yfit = line) ;8-oct-2008, jmm x = x-line endif ; if not(keyword_set(nohanning)) then x = x * window ; bign = nboxpnts if (bign-(bign/2l)*2l ne 0) then begin dprint, 'needs an even number of data points, dropping last point...' t = t[0:bign-2] x = x[0:bign-2] bign = bign - 1 endif ; n_tm = n_elements(t) ;time variance can break power spectrum, this keyword skips over those gaps if keyword_set(noTmVariance) && n_tm gt 1 then begin ;if 1 && n_tm gt 1 then begin if keyword_set(tm_sensitivity) then tmsn = tm_sensitivity[0] else tmsn = 100.0 tdiff = t[1:n_tm-1]-t[0:n_tm-2] med_diff = median(tdiff,/double) ;if there is any signifcant difference from the median time, then skip this iteration. idx = where(abs(tdiff/med_diff -1.) gt 1.0/tmsn,c) ;if there is a cadence change insert NaNs if c gt 0 then begin dps[nthspectrum, *] = !VALUES.D_NAN fdps[nthspectrum, *] = !VALUES.D_NAN ;if this isn't the final window, then also put NaNs in the window after the gap so that data plots correctly if nthspectrum lt nspectra-1 then begin nthspectrum++ ;this effectively skips the next iteration of the loop nbegin = long(nthspectrum*nshiftpnts) ;rebuild any quantities that we need to ensure valid results nend = nbegin+nboxpnts-1l if(nend le totalpoints-1) then begin dps[nthspectrum, *] = !VALUES.D_NAN fdps[nthspectrum, *] = !VALUES.D_NAN tdps[nthspectrum] = double(time2process[nbegin]+time2process[nend])/2.0 endif endif continue endif endif ; following Numerical recipes in Fortran, p. 421, sort of... ; dbign = double(bign) k = [0, dindgen(bign/2)+1] tres = median(t[1:n_elements(t)-1]-t[0:n_elements(t)-2]) fk = k/(bign*tres) ; xs2 = abs(fft(x, 1))^2 ; pwr = dblarr(bign/2+1) pwr[0] = xs2[0]/dbign^2 pwr[1:bign/2-1] = (xs2[1:bign/2-1] + xs2[bign - dindgen(bign/2-1)])/dbign^2 pwr[bign/2] = xs2[bign/2]/dbign^2 ; if not keyword_set(nohanning) then begin wss = dbign*total(window^2) pwr = dbign^2*pwr/wss endif ; ; Now reduce variance by summing bin neighbors in frequency domain... ; dfreq = binsize*(fk[1]-fk[0]) ; npwr = n_elements(pwr)-1 nfinal = long(npwr/binsize) iarray = lindgen(nfinal) power = dblarr(nfinal) ; ; Note: zeroth point includes zero freq. power. freqcenter = (fk[iarray*binsize+1]+fk[iarray*binsize+binsize])/2. ; for i = 0l, binsize-1 do begin power = power+pwr[iarray*binsize+i+1] endfor ; if not(keyword_set(notperhz)) then begin power = power[*] / dfreq power0 = pwr[0] / (fk[1]-fk[0]) ; must also include zero freq power endif ; dps[nthspectrum, *] = power[*] fdps[nthspectrum, *] = freqcenter endif endfor ; fail = 0 ; return end