Rebin large set of x-y data on log-scale
ilavsky
//This routine will rebin approximately linearly distributed data into approximately logarithmically spaced data.
//It will replace the input Wx and Wy with new Wx and Wy with the required NumberOfPoints
//Code will replace all other input data also, so make sure you pass in only copies of the data.
//If MinStep > 0 it will try to set the values so the minimum step of the log scale is MinStep
//note: there are some limits on step size and number of points in and out. Basically, the step size needs to be
//approximately equivalent the linear step. It cannot be much larger. And number of new points must be significantly smaller than input num points.
//optional Wsdev and Wxsdev are standard deviation for each Wy (and Wx) value, they will be propagated through - sum(sdev^2)/numpnts for each bin.
//optional Wxwidth will generate width of each new bin in x. NOTE: the edge is half linear distance between the two points, no log
//skewing is done for edges. Therefore the width is really half of the distance between p-1 and p+1 points.
//optional W1-W5 will be averaged for each bin, so this is way to propagate other data one may need to.
//**********************************************************************************************************
Function RebinLogData(Wx,Wy,NumberOfPoints,MinStep,[Wsdev,Wxsdev,Wxwidth,W1, W2, W3, W4, W5])
Wave Wx, Wy
Variable NumberOfPoints, MinStep
Wave Wsdev, Wxsdev
Wave Wxwidth
Wave W1, W2, W3, W4, W5
variable CalcSdev, CalcxSdev, CalcWidth, CalcW1, CalcW2, CalcW3, CalcW4, CalcW5
CalcSdev = ParamIsDefault(Wsdev) ? 0 : 1
CalcxSdev = ParamIsDefault(Wxsdev) ? 0 : 1
CalcWidth = ParamIsDefault(Wxwidth) ? 0 : 1
CalcW1 = ParamIsDefault(W1) ? 0 : 1
CalcW2 = ParamIsDefault(W2) ? 0 : 1
CalcW3 = ParamIsDefault(W3) ? 0 : 1
CalcW4 = ParamIsDefault(W4) ? 0 : 1
CalcW5 = ParamIsDefault(W5) ? 0 : 1
variable OldNumPnts=numpnts(Wx)
if(3*NumberOfPoints>OldNumPnts)
print "User requested rebinning of data, but old number of points is less than 3*requested number of points, no rebinning done"
return 0
endif
variable StartX, EndX, iii, isGrowing, CorrectStart, logStartX, logEndX
if(Wx[0]<=0) //log scale cannot start at 0, so let's pick something close to what user wanted...
Wx[0] = Wx[1]/2
endif
CorrectStart = Wx[0]
if(MinStep>0)
StartX = FindCorrectLogScaleStart(Wx[0],Wx[numpnts(Wx)-1],NumberOfPoints,MinStep)
else
StartX = CorrectStart
endif
Endx = StartX +abs(Wx[numpnts(Wx)-1] - Wx[0])
isGrowing = (Wx[0] < Wx[numpnts(Wx)-1]) ? 1 : 0
make/O/D/FREE/N=(NumberOfPoints) tempNewLogDist, tempNewLogDistBinWidth
logstartX=log(startX)
logendX=log(endX)
tempNewLogDist = logstartX + p*(logendX-logstartX)/numpnts(tempNewLogDist)
tempNewLogDist = 10^(tempNewLogDist)
startX = tempNewLogDist[0]
tempNewLogDist += CorrectStart - StartX
tempNewLogDistBinWidth[1,numpnts(tempNewLogDist)-2] = tempNewLogDist[p+1] - tempNewLogDist[p-1]
tempNewLogDistBinWidth[0] = tempNewLogDistBinWidth[1]
tempNewLogDistBinWidth[numpnts(tempNewLogDist)-1] = tempNewLogDistBinWidth[numpnts(tempNewLogDist)-2]
make/O/D/FREE/N=(NumberOfPoints) Rebinned_WvX, Rebinned_WvY, Rebinned_Wv1, Rebinned_Wv2,Rebinned_Wv3, Rebinned_Wv4, Rebinned_Wv5, Rebinned_Wsdev, Rebinned_Wxsdev
Rebinned_WvX=0
Rebinned_WvY=0
Rebinned_Wv1=0
Rebinned_Wv2=0
Rebinned_Wv3=0
Rebinned_Wv4=0
Rebinned_Wv5=0
Rebinned_Wsdev=0
Rebinned_Wxsdev=0
variable i, j
variable cntPoints, BinHighEdge
//variable i will be from 0 to number of new points, moving through destination waves
j=0 //this variable goes through data to be reduced, therefore it goes from 0 to numpnts(Wx)
For(i=0;i<NumberOfPoints;i+=1)
cntPoints=0
BinHighEdge = tempNewLogDist[i]+tempNewLogDistBinWidth[i]/2
if(isGrowing)
Do
Rebinned_WvX[i] += Wx[j]
Rebinned_WvY[i] += Wy[j]
if(CalcW1)
Rebinned_Wv1[i] += W1[j]
endif
if(CalcW2)
Rebinned_Wv2[i] += W2[j]
endif
if(CalcW3)
Rebinned_Wv3[i] += W3[j]
endif
if(CalcW4)
Rebinned_Wv4[i] += W4[j]
endif
if(CalcW5)
Rebinned_Wv5[i] += W5[j]
endif
if(CalcSdev)
Rebinned_Wsdev[i] += Wsdev[j]^2
endif
if(CalcxSdev)
Rebinned_Wxsdev[i] += Wxsdev[j]^2
endif
cntPoints+=1
j+=1
While(Wx[j-1]<BinHighEdge && j<OldNumPnts)
else
Do
Rebinned_WvX[i] += Wx[j]
Rebinned_WvY[i] += Wy[j]
if(CalcW1)
Rebinned_Wv1[i] += W1[j]
endif
if(CalcW2)
Rebinned_Wv2[i] += W2[j]
endif
if(CalcW3)
Rebinned_Wv3[i] += W3[j]
endif
if(CalcW4)
Rebinned_Wv4[i] += W4[j]
endif
if(CalcW5)
Rebinned_Wv5[i] += W5[j]
endif
if(CalcSdev)
Rebinned_Wsdev[i] += Wsdev[j]^2
endif
if(CalcxSdev)
Rebinned_Wxsdev[i] += Wxsdev[j]^2
endif
cntPoints+=1
j+=1
While((Wx[j-1]>BinHighEdge) && (j<OldNumPnts))
endif
Rebinned_WvX[i]/=cntPoints
Rebinned_WvY[i]/=cntPoints
if(CalcW1)
Rebinned_Wv1[i]/=cntPoints
endif
if(CalcW2)
Rebinned_Wv2[i]/=cntPoints
endif
if(CalcW3)
Rebinned_Wv3[i]/=cntPoints
endif
if(CalcW4)
Rebinned_Wv4[i]/=cntPoints
endif
if(CalcW5)
Rebinned_Wv5[i]/=cntPoints
endif
if(CalcSdev)
Rebinned_Wsdev[i]=sqrt(Rebinned_Wsdev[i])/cntPoints
endif
if(CalcxSdev)
Rebinned_Wxsdev[i]=sqrt(Rebinned_Wxsdev[i])/cntPoints
endif
endfor
Redimension/N=(numpnts(Rebinned_WvX))/D Wx, Wy
Wx=Rebinned_WvX
Wy=Rebinned_WvY
if(CalcW1)
Redimension/N=(numpnts(Rebinned_WvX))/D W1
W1=Rebinned_Wv1
endif
if(CalcW2)
Redimension/N=(numpnts(Rebinned_WvX))/D W2
W2=Rebinned_Wv2
endif
if(CalcW3)
Redimension/N=(numpnts(Rebinned_WvX))/D W3
W3=Rebinned_Wv3
endif
if(CalcW4)
Redimension/N=(numpnts(Rebinned_WvX))/D W4
W4=Rebinned_Wv4
endif
if(CalcW5)
Redimension/N=(numpnts(Rebinned_WvX))/D W5
W5=Rebinned_Wv5
endif
if(CalcSdev)
Redimension/N=(numpnts(Rebinned_WvX))/D Wsdev
Wsdev = Rebinned_Wsdev
endif
if(CalcxSdev)
Redimension/N=(numpnts(Rebinned_WvX))/D Wsdev
Wxsdev = Rebinned_Wxsdev
endif
if(CalcWidth)
Redimension/N=(numpnts(Rebinned_WvX))/D Wxwidth
Wxwidth = tempNewLogDistBinWidth
endif
end
//**********************************************************************************************************
Function FindCorrectLogScaleStart(StartValue,EndValue,NumPoints,MinStep)
variable StartValue,EndValue,NumPoints,MinStep
Make/Free/N=3 w
w={EndValue-StartValue, NumPoints,MinStep}
Optimize /H=100/L=1e-5/I=100/T=(MinStep/10)/Q myFindStartValueFunc, w
//the optimize parameters: 10^H is last reasonable number, 10^L is really close to 1, other are open for discussion.
//Test this works if you want to make sure...
// variable startX=log(V_minloc)
// variable endX=log(V_minloc+range)
// variable LastMinStep = 10^(startX + (endX-startX)/NumPoints) - 10^(startX)
// print LastMinStep
return V_minloc
end
//**********************************************************************************************************
static Function myFindStartValueFunc(w,x1) //static to keep this form polluting names others may use.
Wave w //this is {totalRange, NumSteps,MinStep}
Variable x1 //this is startValue where we need to start with log stepping...
variable LastMinStep = 10^(log(X1) + (log(X1+w[0])-log(X1))/w[1]) - 10^(log(X1))
return abs(LastMinStep-w[2])
End
//*****************************************************************************************************************
//It will replace the input Wx and Wy with new Wx and Wy with the required NumberOfPoints
//Code will replace all other input data also, so make sure you pass in only copies of the data.
//If MinStep > 0 it will try to set the values so the minimum step of the log scale is MinStep
//note: there are some limits on step size and number of points in and out. Basically, the step size needs to be
//approximately equivalent the linear step. It cannot be much larger. And number of new points must be significantly smaller than input num points.
//optional Wsdev and Wxsdev are standard deviation for each Wy (and Wx) value, they will be propagated through - sum(sdev^2)/numpnts for each bin.
//optional Wxwidth will generate width of each new bin in x. NOTE: the edge is half linear distance between the two points, no log
//skewing is done for edges. Therefore the width is really half of the distance between p-1 and p+1 points.
//optional W1-W5 will be averaged for each bin, so this is way to propagate other data one may need to.
//**********************************************************************************************************
Function RebinLogData(Wx,Wy,NumberOfPoints,MinStep,[Wsdev,Wxsdev,Wxwidth,W1, W2, W3, W4, W5])
Wave Wx, Wy
Variable NumberOfPoints, MinStep
Wave Wsdev, Wxsdev
Wave Wxwidth
Wave W1, W2, W3, W4, W5
variable CalcSdev, CalcxSdev, CalcWidth, CalcW1, CalcW2, CalcW3, CalcW4, CalcW5
CalcSdev = ParamIsDefault(Wsdev) ? 0 : 1
CalcxSdev = ParamIsDefault(Wxsdev) ? 0 : 1
CalcWidth = ParamIsDefault(Wxwidth) ? 0 : 1
CalcW1 = ParamIsDefault(W1) ? 0 : 1
CalcW2 = ParamIsDefault(W2) ? 0 : 1
CalcW3 = ParamIsDefault(W3) ? 0 : 1
CalcW4 = ParamIsDefault(W4) ? 0 : 1
CalcW5 = ParamIsDefault(W5) ? 0 : 1
variable OldNumPnts=numpnts(Wx)
if(3*NumberOfPoints>OldNumPnts)
print "User requested rebinning of data, but old number of points is less than 3*requested number of points, no rebinning done"
return 0
endif
variable StartX, EndX, iii, isGrowing, CorrectStart, logStartX, logEndX
if(Wx[0]<=0) //log scale cannot start at 0, so let's pick something close to what user wanted...
Wx[0] = Wx[1]/2
endif
CorrectStart = Wx[0]
if(MinStep>0)
StartX = FindCorrectLogScaleStart(Wx[0],Wx[numpnts(Wx)-1],NumberOfPoints,MinStep)
else
StartX = CorrectStart
endif
Endx = StartX +abs(Wx[numpnts(Wx)-1] - Wx[0])
isGrowing = (Wx[0] < Wx[numpnts(Wx)-1]) ? 1 : 0
make/O/D/FREE/N=(NumberOfPoints) tempNewLogDist, tempNewLogDistBinWidth
logstartX=log(startX)
logendX=log(endX)
tempNewLogDist = logstartX + p*(logendX-logstartX)/numpnts(tempNewLogDist)
tempNewLogDist = 10^(tempNewLogDist)
startX = tempNewLogDist[0]
tempNewLogDist += CorrectStart - StartX
tempNewLogDistBinWidth[1,numpnts(tempNewLogDist)-2] = tempNewLogDist[p+1] - tempNewLogDist[p-1]
tempNewLogDistBinWidth[0] = tempNewLogDistBinWidth[1]
tempNewLogDistBinWidth[numpnts(tempNewLogDist)-1] = tempNewLogDistBinWidth[numpnts(tempNewLogDist)-2]
make/O/D/FREE/N=(NumberOfPoints) Rebinned_WvX, Rebinned_WvY, Rebinned_Wv1, Rebinned_Wv2,Rebinned_Wv3, Rebinned_Wv4, Rebinned_Wv5, Rebinned_Wsdev, Rebinned_Wxsdev
Rebinned_WvX=0
Rebinned_WvY=0
Rebinned_Wv1=0
Rebinned_Wv2=0
Rebinned_Wv3=0
Rebinned_Wv4=0
Rebinned_Wv5=0
Rebinned_Wsdev=0
Rebinned_Wxsdev=0
variable i, j
variable cntPoints, BinHighEdge
//variable i will be from 0 to number of new points, moving through destination waves
j=0 //this variable goes through data to be reduced, therefore it goes from 0 to numpnts(Wx)
For(i=0;i<NumberOfPoints;i+=1)
cntPoints=0
BinHighEdge = tempNewLogDist[i]+tempNewLogDistBinWidth[i]/2
if(isGrowing)
Do
Rebinned_WvX[i] += Wx[j]
Rebinned_WvY[i] += Wy[j]
if(CalcW1)
Rebinned_Wv1[i] += W1[j]
endif
if(CalcW2)
Rebinned_Wv2[i] += W2[j]
endif
if(CalcW3)
Rebinned_Wv3[i] += W3[j]
endif
if(CalcW4)
Rebinned_Wv4[i] += W4[j]
endif
if(CalcW5)
Rebinned_Wv5[i] += W5[j]
endif
if(CalcSdev)
Rebinned_Wsdev[i] += Wsdev[j]^2
endif
if(CalcxSdev)
Rebinned_Wxsdev[i] += Wxsdev[j]^2
endif
cntPoints+=1
j+=1
While(Wx[j-1]<BinHighEdge && j<OldNumPnts)
else
Do
Rebinned_WvX[i] += Wx[j]
Rebinned_WvY[i] += Wy[j]
if(CalcW1)
Rebinned_Wv1[i] += W1[j]
endif
if(CalcW2)
Rebinned_Wv2[i] += W2[j]
endif
if(CalcW3)
Rebinned_Wv3[i] += W3[j]
endif
if(CalcW4)
Rebinned_Wv4[i] += W4[j]
endif
if(CalcW5)
Rebinned_Wv5[i] += W5[j]
endif
if(CalcSdev)
Rebinned_Wsdev[i] += Wsdev[j]^2
endif
if(CalcxSdev)
Rebinned_Wxsdev[i] += Wxsdev[j]^2
endif
cntPoints+=1
j+=1
While((Wx[j-1]>BinHighEdge) && (j<OldNumPnts))
endif
Rebinned_WvX[i]/=cntPoints
Rebinned_WvY[i]/=cntPoints
if(CalcW1)
Rebinned_Wv1[i]/=cntPoints
endif
if(CalcW2)
Rebinned_Wv2[i]/=cntPoints
endif
if(CalcW3)
Rebinned_Wv3[i]/=cntPoints
endif
if(CalcW4)
Rebinned_Wv4[i]/=cntPoints
endif
if(CalcW5)
Rebinned_Wv5[i]/=cntPoints
endif
if(CalcSdev)
Rebinned_Wsdev[i]=sqrt(Rebinned_Wsdev[i])/cntPoints
endif
if(CalcxSdev)
Rebinned_Wxsdev[i]=sqrt(Rebinned_Wxsdev[i])/cntPoints
endif
endfor
Redimension/N=(numpnts(Rebinned_WvX))/D Wx, Wy
Wx=Rebinned_WvX
Wy=Rebinned_WvY
if(CalcW1)
Redimension/N=(numpnts(Rebinned_WvX))/D W1
W1=Rebinned_Wv1
endif
if(CalcW2)
Redimension/N=(numpnts(Rebinned_WvX))/D W2
W2=Rebinned_Wv2
endif
if(CalcW3)
Redimension/N=(numpnts(Rebinned_WvX))/D W3
W3=Rebinned_Wv3
endif
if(CalcW4)
Redimension/N=(numpnts(Rebinned_WvX))/D W4
W4=Rebinned_Wv4
endif
if(CalcW5)
Redimension/N=(numpnts(Rebinned_WvX))/D W5
W5=Rebinned_Wv5
endif
if(CalcSdev)
Redimension/N=(numpnts(Rebinned_WvX))/D Wsdev
Wsdev = Rebinned_Wsdev
endif
if(CalcxSdev)
Redimension/N=(numpnts(Rebinned_WvX))/D Wsdev
Wxsdev = Rebinned_Wxsdev
endif
if(CalcWidth)
Redimension/N=(numpnts(Rebinned_WvX))/D Wxwidth
Wxwidth = tempNewLogDistBinWidth
endif
end
//**********************************************************************************************************
Function FindCorrectLogScaleStart(StartValue,EndValue,NumPoints,MinStep)
variable StartValue,EndValue,NumPoints,MinStep
Make/Free/N=3 w
w={EndValue-StartValue, NumPoints,MinStep}
Optimize /H=100/L=1e-5/I=100/T=(MinStep/10)/Q myFindStartValueFunc, w
//the optimize parameters: 10^H is last reasonable number, 10^L is really close to 1, other are open for discussion.
//Test this works if you want to make sure...
// variable startX=log(V_minloc)
// variable endX=log(V_minloc+range)
// variable LastMinStep = 10^(startX + (endX-startX)/NumPoints) - 10^(startX)
// print LastMinStep
return V_minloc
end
//**********************************************************************************************************
static Function myFindStartValueFunc(w,x1) //static to keep this form polluting names others may use.
Wave w //this is {totalRange, NumSteps,MinStep}
Variable x1 //this is startValue where we need to start with log stepping...
variable LastMinStep = 10^(log(X1) + (log(X1+w[0])-log(X1))/w[1]) - 10^(log(X1))
return abs(LastMinStep-w[2])
End
//*****************************************************************************************************************
Forum
Support
Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More