To find a series of Maxima

Hello

I have data for which I would like to determine the width of the pulses from valley to peak, for all pulses in the data. So I need to know X of the minimum and X of the maximum. The pulses are asymmetric, which is why smoothing, differentiating, and finding 0 levels comes with an inaccuracy (please see example).

The valleys are acceptable to me, but the so determined peaks have to much offset. Obviously this is due to the smoothing. And I have tried various smoothing approaches, but non leaves the max where it really is.

Can you think of another approach to determine (mainly) the Xs of the maxima? Maybe an asymmetric peak fit?

Many thanks

 

Remo

 

 

 

example data and min/max from smooth-dif-findlevel0 example.pxp (26.12 KB)

in the mean time I just thought I could do wavestats on a range defined by to valleys. This works well.

Could you smooth the data, differentiate it and look for crossings of zero in positive and negative directions?  Do you have to use the peak and valley positions? You could look for the positions of the maximum positive and negative slopes instead. That might shift less when you smooth the data.

Fourier transforming the data might also be helpful if the pulses are all in registry with each other, meaning there is no phase shift over time.

You could also do some version of highpass and lowpass filtering. Below is an extremely simplified example:

Function TestFunction()

	Wave example
	duplicate/O/R=[0,715] example exampleFFT
	FFT exampleFFT
	Duplicate/C/O exampleFFT exampleInvFFT
	exampleInvFFT[0, x2pnt(exampleInvFFT, 2e7)]=cmplx(0, 0)
	exampleInvFFT[x2pnt(exampleInvFFT, 15e7), *]=cmplx(0, 0)
	IFFT exampleInvFFT
	SetScale/P x, DimOffset(example, 0), DimDelta(example, 0), "",   exampleInvFFT
	Display example, exampleInvFFT
	ModifyGraph rgb(exampleInvFFT)=(29440,0,58880)
	
end

 

Thanks,

currently I am satisfied with the following approach:

 

Function test(w)
	wave w
	Duplicate/O w,w_smth
	Smooth/E=1/S=2 23, w_smth
	Differentiate w_smth/D=w_smth_DIF
	FindLevels /P /D=peaksP  /EDGE=2   w_smth_DIF, 0
	FindLevels /P /D=valleysP  /EDGE=1   w_smth_DIF, 0
	Accurate_test(w,valleysP,peaksP)
End

Function Accurate_test(w,w_valleys,w_peaks)
	wave w,w_valleys	,w_peaks
	Variable  count
	count=dimsize(w_valleys,0)
	
	make /o/N=(count-1) peaksP_acc
	Variable i
	count=dimsize(w_valleys,0)
	
	for (i=0; i<count; i+=1)
		wavestats/q /R=[w_valleys[i],w_valleys[i+1]] w 
		peaksP_acc[i]= V_maxRowLoc	   	
        endfor
	
	
	make /o/N=(count-1) valleysP_Acc
	Variable j
	
	for (j=0; j<count; j+=1)
		wavestats/q /R=[w_peaks[j],w_peaks[j+1]] w 
		valleysP_Acc[j]= V_minRowLoc	   	
        endfor
	
	duplicate /o peaksP_acc peaksX_acc
	duplicate /o valleysP_acc valleysX_acc
	duplicate /o w wX
	wX=x	
	peaksX_acc=wX[peaksX_acc]
	valleysX_acc=wX[valleysX_acc]
End

 

Presuming the period is constant, you could fit a sin or cosine wave equation to the data.

y = A*sin(2*Pi*w*(x - xo))

This approach will give you an average period w and its uncertainty.

Here is another approach to consider that is based on template matching:

Choose a "typical" pulse and match it against the full wave.  Here is what I did:

duplicate/r=[334,360] example,onePeak
Duplicate/O example,W_Correlation
Correlate onePeak, W_Correlation
Display W_Correlation

The last wave is pretty easy to analyze.

 

AG

Forum

Support

Gallery

Igor Pro 10

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More