[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Signal processing in IDL



In article <oTSp3.1211$Ffg.181237760@news.telia.no>,
  roy.hansen@triad.no (Roy E. Hansen) wrote:
> Hi,
Hi!

> I am specifically looking for spectral estimation routines
> and time-frequency / time-scale analysis routines.
> --RoyH

In article <oTSp3.1211$Ffg.181237760@news.telia.no>,
  roy.hansen@triad.no (Roy E. Hansen) wrote:
> Hi,
> (snip)
> I am specifically looking for spectral estimation routines
> and time-frequency / time-scale analysis routines.

Below is code that calculates the S-Transform.
(NOTE: I think I'll have text-wrap problems posting
from Dejanews. If so, email me and I'll send the code
through email)


input: a timeseries (1-D array)
output: a 2-D complex valued matrix
output with keyword /abs or /pow, a 2-D float matrix
output with keyword /samplingrate, a structure with
 three arrays,(1)1-D time array (2) 1-D frequency array
 (3) the ST 2-D matrix.

USAGE:
IDL> r = s_trans(/example)  ; plots an example timeseries and ST

IDL> r = s_trans(/help)  ; prints information

IDL> contour,s_trans(cos(findgen(100)),/abs)

email me for futher info.


reference:
@article{R_G_Stockwell_1996_44_998_1001,
Author = {R.G. Stockwell and L. Mansinha and R.P. Lowe},
Title = {Localization of the Complex Spectrum: The S Transform},
Year = {1996},
Journal = {IEEE Transactions on Signal Processing},
Volume = {44},
Number = {4},
Pages = {998-1001}
}

--
¤º°`°º¤ø,¸¸,ø¤º°`°º¤ø¤º°`°º¤ø,¸¸,ø¤º°`
R.G. Stockwell
Colorado Research Associates
3380 Mitchell Lane
Boulder Colorado
(mysurname)(at)co-ra(dot)com
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^



; The S transform function
; written by bob stockwell, 1993
;
; Returns a matrix if succesful
; a structure  if a sampling rate is given
;    The structure is {st:, Freq:, Time:}
;	 where st is the S Transform, freq is a vector containing the
;    frequencies
;
;    Optional Paramters
;   WIDTH   size of time resolution
;			if not set, width = 1
;
;
;    Keywords
;   \HELP				explains all the keywords and
parameters
;   \VERBOSE			flags errors and size
;	\SAMPLINGRATE   	if set returns array of frequency
;	\MAXFREQ
;	\MINFREQ
;	\FREQSAMPLINGRATE
;	\PIECEWISENUMBER    divides the time series, and passes back
array
; 	\POWER				 returns the power spectrum
; 	\ABS				 returns the absolute value
spectrum
;	\REMOVEEDGE		 removes the edge with a 5% taper, and
takes
;							 out
least-sqares fit parabola

; added a "mask out edges" keyword,
; which STs a line (ie st of edges) and thresholds the returned st
matrix.
; The value of masked edges is the percent at which to  make the
threshold
; default = 5 %.

; added an EXAMPLE keyword, will display a time series and the
; amplitude of the ST to the current graphics device
; WARNING, will call !P.multi=0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; modified hilbert transform
;;;;;;;;;;;;;;;;;;;;;
;+
; NAME:
;       HILBERT
;
; PURPOSE:
;       Return a series that has all periodic terms shifted by 90
degrees.
;

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; REVISION HISTORY:
;       JUNE, 1985,     Written, Leonard Kramer, IPST (U. of Maryland)
on site
;                       contractor to NASA(Goddard Sp. Flgt. Cntr.)
;-
;=======================================================================
=========
;  MODIFIED:   APRIL 20 1994 by RGS
;                  - returns real function only
;                  - added keyword     /ANALYTIC
;                    to return the analytic signal



FUNCTION HILBERT,X,D, ANALYTIC = a   ; performs the Hilbert transform of
some data.
        ON_ERROR,2           ; Return to caller if an error occurs
        Y=FFT(X,-1)          ; go to freq. domain.
        N=N_ELEMENTS(Y)

        I=COMPLEX(0.0,-1.0)

        IF N_PARAMS(X) EQ 2 THEN I=I*D
        N2=ceil(N/2.)-1             ; effect of odd and even # of
elements
                             ; considered here.
        y(0) = complex(0,0)  ; zero the DC value (required for hilbert
trans.)
        Y(1)=Y(1:N2)*I       ; multiplying by I rotates counter c.w. 90
deg.
	    if (n mod 2) eq 0  then Y(N2+1) = complex(0,0)     ; don't
need this
        N2=N-N2
		Y(N2)=Y(N2:N-1)/I
        Y=float(FFT(Y,1))  ; go back to time domain
        if keyword_set(a) then y = complex(x,y)
 RETURN,y

END




;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; Gaussian Window Function
; Accepts variables length and width
; Returns the spectrum of the Gaussian window
; note this is length/2piw 11ll11ll
FUNCTION gaussian_window, l, w
 if w ne 0.0 then sigma = l/(2*!PI*w) else MESSAGE,'width is zero!'
 g = fltarr(l)
 iarr = findgen(l)
 ex = (iarr - l/2)^2/(2*sigma^2)
 wl = where(ex lt 25)  ; probably not needed, I ran into a problem about
6 years ago, and I do not remeber what it was!!
 g(wl) = exp(-ex(wl))
 g = shift(g,-l/2)
 return, complex(g,0)
end


;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; the S Transform function
FUNCTION s_trans, ts, factor, HELP =
HELP,VERBOSE=VERBOSE,SAMPLINGRATE=SAMPLINGRATE $
    ,MAXFREQ=MAXFREQ,MINFREQ=MINFREQ  $
    ,FREQSAMPLINGRATE=FREQSAMPLINGRATE     $
    ,POWER=POWER,ABS=ABS,REMOVEEDGE=REMOVEEDGE   $
    , maskedges=maskedges,EXAMPLE=EXAMPLE


if keyword_set(EXAMPLE) then begin  ; show example of a chirp function
	ex_len = 512
	ex_time = findgen(ex_len)
	ex_freq = 5;ex_len/16
	ex_ts =  cos(2*!Pi*ex_freq*ex_time/ex_len)
	ex_ts =  cos(2*!Pi*(ex_len/5+2*ex_ts)*ex_time/ex_len)
	; crossed chirp example commented out
		;ex_ts =
cos(2*!Pi*ex_freq*ex_time*(1+2*ex_time/ex_len)/ex_len)
		;ex_ts = ex_ts + reverse(ex_ts)
	!P.multi=[0,1,2]
	plot,ex_ts,xtitle='Time (units)',title='Time Series [h(t) =
cos(cos(wt))]'
	s = s_trans(ex_ts,/samp, /abs)  ; returns structure, amplitudes
only returned
	contour,s.st,ex_time,s.freq,nlevels=14,/fill,xtitle='Time
(units)', $
		ytitle='Frequency (1/unit)',title='Amplitude of
S-Transform'
	return,0
	!P.multi=0
endif

if keyword_set(HELP) then begin
	Print,"S_TRANS()  HELP COMMAND"
	Print,"S_trans() returns a matrix if succesful or a structure if
required"
	Print,"S_trans() returns  - 1 or an error message if it fails"
	Print,"USAGE::    localspectra = s_trans(timeseries)
	Print," "
	Print,"Optional Parameters"
	Print,"WIDTH  -size of time resolution"
	Print,"       -if not set, default WIDTH = 1"
	Print," "
	Print,"Keywords:
	Print,"\HELP          -explains all the keywords and parameters
	Print,"\VERBOSE       -flags errors and size, tells time left
etc.
	Print,"\SAMPLINGRATE -if set returns array of frequency
	Print,"\MAXFREQ
	Print,"\MINFREQ
	Print,"\FREQSAMPLINGRATE
	Print,"\POWER            -returns the power spectrum
	Print,"\ABS              -returns the absolute value spectrum
	Print,"\REMOVEEDGE      -removes the edge with a 5% taper, and
takes
	Print,"                  -out least-squares fit parabola
	return, -1
endif

;print,'paramters',N_params()
;Check number of arguments.
CASE N_PARAMS() OF
	1: begin
		if n_elements(ts) eq 0 then MESSAGE, 'Invalid timeseries
(check your spelling).'
		factor = 1
	end
	2: if n_elements(factor) ne 1 then begin ;Two-argument case.
		 factor = 1                          ;Make sure factor
is a number.
	   if keyword_set(VERBOSE)then print,'Error in second parameter.
Using default values.'
	   endif
ELSE: MESSAGE, 'Wrong number of arguments'
ENDCASE


if n_elements(ts) eq 0 then MESSAGE, 'Invalid timeseries (check your
spelling).'
time_series = ts ; don't change the original dataset passed to this
function

; check to see if it is a vector, not a 1 x N matrix
sz = size(time_series)
if sz(0) ne 1 then begin
    if sz(1) eq 1 and sz(2) gt 1 then begin
       time_series = reform(time_series)  ; a column vector, change it
       if keyword_set(VERBOSE)then print,'Reforming timeseries'
	endif else MESSAGE, 'Must enter an array of data'
endif

if keyword_set(VERBOSE) then print
if keyword_set(VERBOSE) then print,'Performing S transform:'

if keyword_set(REMOVEEDGE)  then begin
	 if keyword_set(VERBOSE) then  print,'Removing edges'
 	 ind = findgen(n_elements(time_series))
 	 r = poly_fit(ind,time_series,2,fit,yband,sigma,AM)
 	 ts_power =
sqrt(total(float(time_series)^2)/n_elements(time_series))
 	 if keyword_set(VERBOSE) then  print,'Sigma
is:',sigma,'power',ts_power,'ratio',sigma/ts_power
 	 if keyword_set(VERBOSE) then print, 'total
error',total(yband)/n_elements(yband)
 	 time_series = time_series - fit
 	 sh_len = n_elements(time_series)/10
	if sh_len gt 1 then begin
	 wn = hanning(sh_len)
 	 time_series(0:sh_len/2-1) =
time_series(0:sh_len/2-1)*wn(0:sh_len/2-1)
 	 time_series(n_elements(time_series)-sh_len/2:*) =
time_series(n_elements(time_series)-sh_len/2:*)*wn(sh_len/2:*)
 	endif
endif


; here its dimension is one
sz = size(time_series)
if sz(2) ne 6 then begin
	if keyword_set(VERBOSE) then print,'Not complex data, finding
analytic signal.'
	;take hilbert transfrom
	time_series = (hilbert(time_series,/analytic))
	; the /2 is because the  spectrum is  *2 from an. sig.
	; note that the nyquist point and DC are 2*normal in AS(t)
endif


length = n_elements(time_series)
spe_length = length/2
b = complexarr(length)
gw = complexarr(length)
h = fft(time_series,-1)

; do the different sampling cases here:
if (keyword_set(MAXFREQ))  then begin
	if maxfreq lt 1 then maxfreq = fix(length*maxfreq)
endif
if not(keyword_set(MINFREQ))  then begin
		if keyword_set(VERBOSE) then print,'Minimum Frequency is
0.'
		MINFREQ = 0  ; loop starts at 0
endif else begin
		if MINFREQ gt spe_length then begin
				MINFREQ = spe_length
				print,'MINFREQ too large, using default
value'
		endif
		if keyword_set(VERBOSE) then print,strcompress('Minimum
Frequency is '+string(MINFREQ)+'.')
endelse
if not(keyword_set(MAXFREQ))  then begin
		if keyword_set(VERBOSE) then print,strcompress('Maximum
Frequency is '+string(spe_length)+'.')
		MAXFREQ = spe_length
endif else begin
		if MAXFREQ gt spe_length then begin
				MAXFREQ = spe_length
				print,'MAXFREQ too large, using default
value'
		endif
		if keyword_set(VERBOSE) then print,strcompress('Maximum
Frequency is '+string(MAXFREQ)+'.')
endelse
if not(keyword_set(FREQSAMPLINGRATE))  then begin
		if keyword_set(VERBOSE) then print,'Frequency sampling
rate is 1.'
		FREQSAMPLINGRATE = 1
endif else if keyword_set(VERBOSE) then print,strcompress('Frequency
sampling rate is '+string(FREQSAMPLINGRATE)+'.')

if FREQSAMPLINGRATE eq 0 then FREQSAMPLINGRATE = 1     ; if zero then
use default

; check for errors in frequency parameters
if MAXFREQ lt MINFREQ then begin  ; if min > max, switch them
	temp = MAXFREQ
	MAXFREQ = MINFREQ
    MINFREQ= temp
    temp = 0
    print,'Switching frequency limits.'+strcompress(' Now, (MINFREQ =
'+string(MINFREQ) + ') and (MAXFREQ ='+string(MAXFREQ)+').')
endif

if MAXFREQ ne MINFREQ then begin
	if FREQSAMPLINGRATE gt (MAXFREQ - MINFREQ)   then  begin

print,strcompress('FreqSamplingRate='+string(FREQSAMPLINGRATE)+' too
big, using default = 1.')
		FREQSAMPLINGRATE = 1 ; if too big then use default
	endif
endif else FREQSAMPLINGRATE = 1 ; if there is only one frequency

spe_nelements = floor((MAXFREQ - MINFREQ )/FREQSAMPLINGRATE)+1
if keyword_set(VERBOSE) then print,strcompress('The number of frequency
elements is'+string(spe_nelements)+'.')


; Calculate the ST of the data
if keyword_set(ABS) and keyword_set(POWER) then begin
	print,'You are a moron! Defaulting to Local Amplitude Spectra
calculation'
	Power = 0
endif

if keyword_set(ABS) or keyword_set(POWER) then begin
    loc = fltarr(length,spe_nelements)
	if keyword_set(ABS)  then if keyword_set(VERBOSE) then
print,'Calculating Local Amplitude Spectra.'  $
		else if keyword_set(VERBOSE) then print,'Calculating
Local Power Spectra.'
	h = shift(h,-MINFREQ)
	if MINFREQ eq 0 then  begin
		gw = fltarr(length)
		gw(0) = 1
		loc(*,0) = abs(fft(h*gw,1))
	endif else begin
		f = float(MINFREQ)
    	width = factor * length/f
		gw = gaussian_window(length,width)
		b = h * gw
    	loc(*,0) = abs(fft(b,1))
	endelse
	for index = 1,spe_nelements-1 do begin
 		f = float(MINFREQ) + index*FREQSAMPLINGRATE
    	width = factor * length/f
		gw = gaussian_window(length,width)
		h = shift(h,-FREQSAMPLINGRATE)
    	b = h * gw
    	loc(*,index) = abs(fft(b,1))
 	endfor
	if keyword_set(POWER) then loc = loc^2
endif else begin  ; calculate complex ST
	if keyword_set(VERBOSE) then print,'Calculating Local Complex
Spectra'
	loc = complexarr(length,spe_nelements)
	h = shift(h,-MINFREQ)
	if MINFREQ eq 0 then begin
		gw = fltarr(length)
		gw(0) = 1
		loc(*,0) = fft(h*gw,1)     ; 0 freq. equal to DC level
	endif else begin
		f = float(MINFREQ)
    	width = factor * length/f
		gw = gaussian_window(length,width)
		b = h * gw
    	loc(*,0) = fft(b,1)
	endelse
 	for index = 1,spe_nelements-1  do begin
 		f = float(MINFREQ) + index*FREQSAMPLINGRATE
		width = factor * length/f
    	gw = gaussian_window(length,width)
	    h = shift(h,-FREQSAMPLINGRATE)
    	b = h * gw
    	loc(*,index) = fft(b,1)
    endfor
endelse

if keyword_set(maskedges) then begin
	if maskedges eq 1 then maskthreshold=0.05
	if maskedges gt 0 and maskedges lt 1 then
maskthreshold=maskedges
	if maskedges gt 1 and maskedges le 100 then
maskthreshold=float(maskedges)/100. $
		else  maskthreshold=0.05
	edgets = findgen(length)/length
	st = s_trans(edgets,/abs)
	mask=where(st gt maskthreshold,maskcount) ; 5 % is good = 0.05
based on snooping around
	loc(mask) = 0
endif

if keyword_set(SAMPLINGRATE) then begin  ; make structure
;
	frequencies = (MINFREQ +
findgen(spe_nelements)*FREQSAMPLINGRATE)/(SAMPLINGRATE*length)
	time = findgen(length)*SAMPLINGRATE
	a = {st: loc, time: time,freq: frequencies}
	return,a
endif else return, loc



end ; end of function


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.