I think what you want is called a piece-wise linear interpolation. I'm not sure what platform might produce a formula for that, but you can do something similar like this. Do your own testing if you use this!
dt = Open( "$desktop/ab.jmp" ); // table with unaligned times for a and b measurements
dt << sort( by( time ), replacetable( 1 ) ); // make sure time is ascending
aRows = dt << getrowswhere( SourceTable == "a" ); // get all the a
bRows = dt << getrowswhere( SourceTable == "b" ); // and b row indexes
aTimes = dt:time[aRows]; // get all the a and b times and positions in
aPositions = dt:position[aRows]; // matrices for the interpolate function
bTimes = dt:time[bRows];
bPositions = dt:position[bRows];
apos = Function( {time}, // tiny wrappers for interpolate
Interpolate( time, aTimes, aPositions )
);
bpos = Function( {time},
Interpolate( time, bTimes, bPositions )
);
dtnew = New Table( "new_ab", // new table is similar to old table
New Column( "Source Table", Character( 1 ), "Nominal" ),
New Column( "time", Numeric, "Continuous", Format( "Best", 12 ) ),
New Column( "position", Numeric, "Continuous", Format( "Best", 12 ) )
);
bigdif = 0; // track the largest difference so it can have a ref line
bigtime = .;
// make a new table covering the range of the data
For( i = min(min(aTimes),min(bTimes))-10, i <= max(max(aTimes),max(bTimes))+10, i += 1,
dtnew << addrows( 1 ); // interpolate a at time i
dtnew:SourceTable = "a";
dtnew:time = i;
dtnew:position = apos( i );
dtnew << addrows( 1 ); // interpolate b at time i
dtnew:SourceTable = "b";
dtnew:time = i;
dtnew:position = bpos( i );
dtnew << addrows( 1 ); // difference at time i
dtnew:SourceTable = "diff";
dtnew:time = i;
dtnew:position = apos( i ) - bpos( i );
If( Abs( dtnew:position ) > bigdif, // capture biggest diff
bigdif = Abs( dtnew:position );
bigtime = i;
);
);
dtnew << Graph Builder(
Size( 518, 448 ),
Show Control Panel( 0 ),
Variables( X( :time ), Y( :position ), Overlay( :Source Table ) ),
Elements( Points( X, Y, Legend( 21 ) ), Smoother( X, Y, Legend( 22 ), Lambda( 0.000001 ) ) ),
SendToReport(
Dispatch( {}, "time", ScaleBox, {Add Ref Line( bigtime, "Solid", "Black", "big=" || Char( bigtime ), 1 )} ),
Dispatch( {}, "Graph Builder", FrameBox, {Marker Size( 2 )} )
)
);
Input data like this
And the interpolated data like this
Producing a graph like this:
The green curve is blue - red; the ref line is at the first biggest difference.
If this was a race, a won in 71 seconds and b lost in 99 seconds. a was furthest ahead at 43 seconds (well, maybe. You can't be too sure about b's position at time 43 in the original data.)
You can't get that from a simple linear fit on the original data:
Original data with linear fit.
Craige