function [TE,YE,IE] = learntouseevents(pos1,pos2,distance,speed1,speed2);
%learntouseevents(pos1,pos2,distance,speed1,speed2);
%This program shows how to use events in ode integrators to keep track of
%user-defined significant time-points
%
%In this example, two cars are RACING and when either crosses the finish
%line the odeintegrator ends and the winner is announced
%
% { pos1 }
% -------------------------------------------------------------------------
% >1> X
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -X
% >2> X
% -------------------------------------------------------------------------
% { pos2 }
% { distance }
%
%EXAMPLE
%car1 gets a head start but car2 is faster...for the win!
%[TE,YE,IE] = learntouseevents(10,0,100,1,5)
%
%WARNING: MATLAB's event handling doesn't seem as robust as I'd like it as
%I have had program failure when more than one event triggers at a time...
%such as when both cars start at the same position and when both cars
%finish at the same time
%I have heard that this bug has been fixed in some verisons of Matlab
tmax = 100000; %maximum integration time
x0 = [pos1,pos2]; %initial car positions
param.finish = 100; %distance raced to
param.v1 = speed1;
param.v2 = speed2;
options = odeset('Events',@playbyplay);
[t,x,TE,YE,IE] = ode45(@speedfunction,[0,tmax],x0,options,param);
%[t,x] = ode45(fun,[0,tmax],x0);
numberofevents = length(IE);
%determine what happened, event information is stored in TE, YE, and IE
%TE stores the times events happened
%YE stores the function values f at each event
%IE stores the index of the event function triggered
for(i = 1:numberofevents);
switch IE(i);
case 1;
disp(['The Race is on! at t =',num2str(TE(i))]);
disp(['Car1 and Car2 are in positions ',num2str(YE(i,1)),...
' and ',num2str(YE(i,2))]);
case 2;
disp(['The Race is over at t =',num2str(TE(i))]);
disp(['Car1 WINS!!!!!!']);
disp(['Car1 and Car2 are in positions ',num2str(YE(i,1)),...
' and ',num2str(YE(i,2))]);
case 3;
disp(['The Race is over at t =',num2str(TE(i))]);
disp(['Car2 WINS!!!!!!']);
disp(['Car1 and Car2 are in positions ',num2str(YE(i,1)),...
' and ',num2str(YE(i,2))]);
case 4;
disp(['Car1 passes Car2 at t =',num2str(TE(i))]);
disp(['Car1 and Car2 are in positions ',num2str(YE(i,1)),...
' and ',num2str(YE(i,2))]);
case 5;
disp(['Car2 passes Car1 at t =',num2str(TE(i))]);
disp(['Car1 and Car2 are in positions ',num2str(YE(i,1)),...
' and ',num2str(YE(i,2))]);
otherwise;
error('illegal case value');
end
end
plot(x,t);
xlabel('position');
ylabel('time');
legend('car1','car2');
return;
%in this simple example, the two cars move at constant speeds for all
%times (acceleration and time/position dependence could easily be added)
function velocities = speedfunction(t,x,param);
velocities = [0 0]';
velocities(1) = param.v1;
velocities(2) = param.v2;
return;
function [value,isterminal,direction]=playbyplay(t,x,param);
%The events function is triggered whenever a zero is reached
%We will have five functions, one for the beginning of the race,
%one for car 1, one for car 2, and two for cars passing each other
car1position = x(1);
car2position = x(2);
%these are our four possible events. The last two look the same, but we
%will distinguish between them later by looking at the direction zero is
%approached from and left from
racestarted = t;
car1finished = car1position - param.finish;
car2finished = car2position - param.finish;
car1passedcar2 = car1position - car2position;
car2passedcar1 = car1position - car2position;
%value is the result returned by the event function, zeros => events
value = [racestarted; car1finished; car2finished; car1passedcar2; car2passedcar1;];
%isterminal tells whether a given event causes the integrator to stop
% we want to stop when a racer finishes but not when a racer passes
isterminal = [ 0; 1; 1; 0; 0;];
%direction acts as a filter to distinguish between some zeros
% if direction is zero, we care about all zeros
% if +1, we care about cases where the event function increases
% if -1, we care about cases where the event function decreases
direction = [ 0; 0; 0; 1; -1;];
return;