Basic Procrustes Analysis

#pragma rtGlobals=3     // Use modern global access method and strict wave access.

// Very basic example of Procrustes Analysis.
// wave1 and wave2 are expected to have two columns representing
// X and Y components.
Function procrustes(wave1,wave2)
Wave wave1,wave2

    Variable rows1=dimsize(wave1,0)
    Variable cols1=dimsize(wave1,1)
    Variable rows2=dimsize(wave2,0)
    Variable cols2=dimsize(wave2,1)
   
    // Step 1:
    // do not modify the original waves.  Create local waves w1
    // and w2.  Subtract the mean from each column.  That shifts
    // each shape to its origin.
    MatrixOP/O w1=subtractMean(wave1,1)
    MatrixOP/O w2=subtractMean(wave2,1)
   
    // Step 2: perform scaling by dividing by stdv.
    //  Get the scaling factors and arrange as col wave.
    MatrixOP/O/FREE stdv1=sqrt(varcols(w1))^t    
    MatrixOP/O/FREE stdv2=sqrt(varcols(w2))^t
    //  Scale
    MatrixOP/O w1=scaleCols(w1,rec(stdv1))
    MatrixOP/O w2=scaleCols(w2,rec(stdv2))
   
    // test here:
    MatrixOP/O/FREE v1=sum(varCols(w1)+varCols(w2))
    if(v1[0]!=4)
        Print "Bad scaling factors."
    endif
   
    // At this point we removed position and scale.  Next comes rotation.
    if(rows1==rows2)
        MatrixOP/O/FREE x1=col(w1,0)
        MatrixOP/O/FREE x2=col(w2,0)
        MatrixOP/O/FREE y1=col(w1,1)
        MatrixOP/O/FREE y2=col(w2,1)
        MatrixOP/O yc=sum(x2*y1-y2*x1)
        MatrixOP/O xc=sum(x2*x1+y2*y1)
        Variable theta=atan2(yc[0],xc[0])
        // create the rotation matrix:
        Make/O/D/N=(2,2) rotMat
        set2DRotMatrix(rotMat,theta)

        // find the initial procrustes distance
        variable dist=getProcrustesDist(w1,w2)
        print " before dist=",dist

        // Step 3. rotate w2 to match w1:
        MatrixOP/O w2=(rotMat x w2^t)^t
        dist=getProcrustesDist(w1,w2)
        print " after dist=",dist
        print "theta=",theta, "rad"
    endif
End

Function set2DRotMatrix(rotMat,theta)
    Wave rotMat
    Variable theta
   
        rotMat[0][0]=cos(theta)
        rotMat[1][1]=cos(theta)
        rotMat[0][1]=-sin(theta)
        rotMat[1][0]=sin(theta)
End

Function getProcrustesDist(w1,w2)
    Wave w1,w2
   
    Matrixop/o/free aa=sum(powr(w1-w2,2))
    return sqrt(aa[0])
End


Here is a simple example inspired by the "big W":
Make/N=(5,2) wave1,wave2
wave1[0][0]= {0,0.326797,0.0588235,0.326797,0}
wave1[0][1]= {1,0.703947,0.486842,0.217105,0}
wave2[0][0]= {1.9281,1.59477,1.86275,1.62092,1.87582}
wave2[0][1]= {0.263158,0.375,0.559211,0.756579,0.901316}
Display wave1[][1] vs wave1[][0]
AppendToGraph wave2[][1] vs wave2[][0]


Now execute the function above:
procrustes(wave1,wave2)

Display the results:
Display w1[][1] vs w1[][0]
AppendToGraph w2[][1] vs w2[][0]


I couldn't get this to compile. The problem line seems to be: set2DRotMatrix(rotMat,theta)
Help would be appreciated.

My error. You are correct it compiles correctly

Forum

Support

Gallery

Igor Pro 8

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More