pro thm_lsp_get_spec, tvar, units = units, prefix = prefix, fftlen = fftlen, $
yrange = yrange, ufactor = ufactor, instr_resp = instr_resp, $
checkenergy = checkenergy, phase = phase, ft = ft
compile_opt idl2
get_data, tvar, data=data, dlim = dlim
if ~keyword_set(units) then begin
str_element, dlim, 'data_att', success = s0
if ~s0 then units = 'unknown' else begin
str_element, dlim.data_att, 'units', success = s1
if ~s1 then units = 'unknown' else units = dlim.data_att.units
endelse
endif
tmp1 = size(units, /type) ne 7
tmp2 = n_elements(units) ne 1
tmp = tmp1 + tmp2
if tmp ne 0 then begin
print, 'THM_LSP_GET_PSD: ' + $
'Valid units of the input tplot variable must be a string scalar. '+$
'Exiting...'
return
endif
units0 = units[0]
if n_elements(ufactor) eq 0 then ufactor = 1d
if n_elements(prefix) eq 0 then pre = tvar else begin
pre = prefix
if size(pre, /type) ne 7 then pre = tvar
if n_elements(pre) ne 1 then pre = tvar
if pre ne prefix then begin
print, 'THM_LSP_GET_PSD: ' + $
'WARNING -- No valid prefix is given. The default prefix is used.'
endif
endelse
pre = pre[0]
wrongfftlen = 0
if n_elements(fftlen) ne 1 then begin
wrongfftlen = 1
fftlen = 512
endif
if size(fftlen, /type) lt 2 or size(fftlen, /type) gt 5 then begin
wrongfftlen = 1
fftlen = 512
endif
if wrongfftlen then $
print, 'THM_LSP_GET_PSD: ' + $
'WARNING -- No valid fftlen is given. The default fftlen (512) is used.'
if n_elements(instr_resp) ne (fftlen/2 + 1L) then instr_resp = 1d
dt = median(data.x[1:*] - data.x)
tarr = data.x
dim = size(data.y,/dim)
nyquist = 0.5 / dt
if ~keyword_set(yrange) then yrange = [1d/(fftlen * dt), nyquist]
if n_elements(dim) eq 2 then ncomp = dim[1] else ncomp = 1
if ncomp eq 3 then begin
name = pre + ['_xspec', '_yspec', '_zspec']
name2 = pre + ['_xphase', '_yphase', '_zphase']
name3 = pre + ['_xft', '_yft', '_zft']
endif else begin
tmp = indgen(ncomp) + 1
name = pre + '_'+string(tmp, for='(I0)') + 'spec'
name3 = pre + '_'+string(tmp, for='(I0)') + 'ft'
endelse
nslide = fftlen/2
time_units = 1.
freq_units = 1.
data_units = 1.
df = 1. / (fftlen * dt)
nf = fftlen/2 + 1L
farr = dindgen(nf) * df
fftdata_units = data_units
psd_units = fftdata_units^2 / df
win = hanning(fftlen, /double)
wx = fftlen / total(win^2)
btrange = thm_jbt_get_btrange(tvar, nb=nb, tind=tind)
for ib = 0L, nb -1L do begin
ista = tind[ib, 0]
iend = tind[ib, 1]
nt = iend - ista + 1L
if nt lt fftlen then continue
if n_elements(ibstart) eq 0 then ibstart = ib
nsec = long((nt - fftlen) / nslide) + 1L
tmptime = dindgen(nsec) * (dt * nslide) + tarr[nslide+ista]
if n_elements(time) lt 1 then time = tmptime else time=[time,tmptime]
endfor
if n_elements(time) lt 1 then begin
print, 'THM_LSP_GET_SPEC: ' + $
'No continuous section is longer than a fftlen. No spectrum is stored.'
print, 'Exiting...'
return
endif
time_energy = time
freq_energy = time
tmpenergy = time
psdunits = '(' + units0 + ')^2 / Hz'
coord = cotrans_get_coord(tvar)
att = {units:psdunits, coord_sys:coord, data_type:'calibrated'}
att2 = {units:'degree', coord_sys:coord, data_type:'calibrated'}
att3 = {coord_sys:coord, data_type:'calibrated'}
ztitle = '(' + units0 + ')!E2!N / Hz'
ztitle2 = 'Phase [degree]'
dlim = {spec:1B, log:1B, data_att:att, ylog:1, zlog:1, $
ztitle:ztitle, yrange:yrange, ysubtitle:'[Hz]'}
dlim2 = {spec:1B, log:1B, data_att:att2, ylog:1, zlog:1, $
ztitle:ztitle2, yrange:yrange, ysubtitle:'[Hz]'}
dlim3 = {spec:1B, log:1B, data_att:att3}
for icom = 0L, ncomp-1L do begin
psdname = name[icom]
for ib = 0L, nb-1L do begin
ista = tind[ib, 0]
iend = tind[ib, 1]
nt = iend - ista + 1L
if nt lt fftlen then continue
nsec = long((nt - fftlen) / nslide) + 1L
dat = data.y[ista:iend, icom]
tmppsd = dblarr(nf, nsec)
if keyword_set(phase) then tmpphase = dblarr(nf, nsec)
if keyword_set(ft) then tmpft = dcomplexarr(nf, nsec)
tmp_tenergy = dblarr(nsec)
tmp_fenergy = dblarr(nsec)
for isec = 0L, nsec - 1 do begin
iista = isec * nslide
iiend = iista + fftlen - 1L
xdat = dat[iista:iiend]
tmp_tenergy[isec] = total(xdat)
fx = fft(xdat * win)
sqrfx = real_part(fx * conj(fx))
if keyword_set(phase) then $
tmpphase[*,isec] = (atan(fx,/phase) * 180. / !pi)[0:nf-1]
if keyword_set(ft) then tmpft[*,isec] = fx[0:nf-1]
tmppsd[0,isec] = sqrfx[0]
tmppsd[1:fftlen/2-1,isec] = sqrfx[1:fftlen/2-1] + $
reverse(sqrfx[fftlen/2+1:fftlen-1])
tmppsd[fftlen/2,isec] = sqrfx[fftlen/2]
tmppsd[*,isec] = tmppsd[*,isec] * wx / (instr_resp^2)
tmp_tenergy[isec] = total(xdat^2) * dt
tmp_fenergy[isec] = total(sqrfx) * psd_units * wx
endfor
xpsd = transpose(tmppsd)
if keyword_set(phase) then xphase = transpose(tmpphase)
if keyword_set(ft) then xft = transpose(tmpft)
if ib eq ibstart then begin
psd=xpsd
if keyword_set(phase) then phase_all = xphase
if keyword_set(ft) then ft_all = xft
tenergy = tmp_tenergy
fenergy = tmp_fenergy
endif else begin
psd=[psd, xpsd]
if keyword_set(phase) then phase_all = [phase_all, xphase]
if keyword_set(ft) then ft_all = [ft_all, xft]
tenergy = [tenergy, tmp_tenergy]
fenergy = [fenergy, tmp_fenergy]
endelse
endfor
psd = psd * psd_units * ufactor
store_data, psdname, data={x:time, y:psd, v:farr}, dlim=dlim
options, psdname, ystyle = 1
if keyword_set(phase) then begin
phasename = name2[icom]
store_data, phasename, data = {x:time, y:phase_all, v:farr}, dlim = dlim2
options, phasename, ystyle = 1
endif
if keyword_set(ft) then begin
ftname = name3[icom]
store_data, ftname, data = {x:time, y:ft_all, v:farr}, dlim = dlim3
options, ftname, ystyle = 1
endif
if keyword_set(checkenergy) then begin
store_data, psdname + '_checkenergy', data = {x:time, y:fenergy / tenergy}
options, psdname + '_checkenergy', yrange=[0.5, 1.5], ystyle=1
endif
endfor
end