Rebin large set of x-y data on log-scale

//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

//*****************************************************************************************************************

Forum

Support

Gallery

Igor Pro 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More