Solving coupled differential equations with time delay - matlab

I'm trying to model the motion of a particle in a potential and incorporate feedback. The problem I'm having is adding a delay to the feedback. So, working in Matlab, I have a basic script which looks like:
clear all; close all;
qx = .3;
qy = .4;
qz = .5;
om_D = 1.2e8;
ep = 1e-10;
t = 0:1e-11:1e-5;
[t,rss]=ode45(#ion_test, t, [1e-7 .45 2e-7 -.45 0.5e-7 .45],[], qx, qy, qz, om_D, ep);
where ion_test.m is a function file which reads as follows:
function dr = ion_test(t,r, qx, qy, qz, om_D, ep)
dr = zeros(6,1);
dr(1) = r(2);
dr(2) = (2*qx*cos(om_D.*t) + ep.*2*r(3)*r(5));
dr(3) = r(4);
dr(4) = (2*qy*cos(om_D.*t) + ep.*2*r(1)*r(5));
dr(5) = r(6);
dr(6) = (2*qz*cos(om_D.*t) + ep.*2*r(1)*r(3));
end
So as you can see, the differential equations for each of the coordinates of r are coupled. The thing which I need to add is the ability for each equation to call upon the values of other coordinates at previous times, not just their current values. The purpose of this is to build in a delayed feedback mechanism.
Any help very much appreciated!

I think the answer to my question was basically that I needed to use dde23 instead of ode45.

Related

Solving ODEs with Event function in Matlab

I am working on a project right now where I have modeled the motion of a multibody mechanical system. It is a complex, non-smooth system, and the motion of the system is not always described by the same set of equations, which means if I solve this numerically I have to stop the integration at times (and start it up again with new initial conditions and equations).
Now I would like to implement this in code using Matlab's event functions. The concept is easy, but as always the documentation is a bit nondescriptive when it comes to implementing it for a real problem. (There is a example in the documentation, but I cannot see the source code for some reason). I have nonetheless made some code, now I am just stuck at how to put it all together: I want the ODE-solver (e.g. ode45) to solve my equations, then stop when a event occurs, and begin to integrate again with a new set of ODEs and initial condtions, but I don't know how to pass the ODE-solver what equations to solve next and what the new intital conditions are!
Code:
function dy = firstODE(t,y)
dy = zeros(2,1);
dy(1) = y(2);
dy(2) = 1/(A1)*(B1-c*y(1));
end
function dy = secondODE(t,y)
dy = zeros(4,1);
dy(1) = y(2);
dy(2) = -c/A2*y(1);
dy(3) = y(4);
dy(4) = D2/B2 + c*C2/(A2*B2)*y(1);
end
function [value,isterminal,direction] = myEventsFcn(t,y)
value = [y(1)-K1, y(1)+K1, y(1)+K2, y(1)+K1, y(1)-K1];
isterminal = [1, 1, 1, 1, 1];
direction = [-1, -1, -1, 1, 1];
end
How do I tell the ODE-solver what new initial conditions and equations to use after an event occurs?
Call two different solutions. i.e.
sol1 = ode45(#(t,x)firstODE(t,x),tspan1,init1);
% set some conditions
sol2 = ode45(#(t,x)secondODE(t,x),tspan2,init2);
If you want tspan2 to start where the previous one left off and go to the end of your originally defined tspan1, set tspan2 = [sol1.xe,tspan1(end)].

Input equations into Matlab for Simulink Function

I am currently working on an assignment where I need to create two different controllers in Matlab/Simulink for a robotic exoskeleton leg. The idea behind this is to compare both of them and see which controller is better at assisting a human wearing it. I am having a lot of trouble putting specific equations into a Matlab function block to then run in Simulink to get results for an AFO (adaptive frequency oscillator). The link has the equations I'm trying to put in and the following is the code I have so far:
function [pos_AFO, vel_AFO, acc_AFO, offset, omega, phi, ampl, phi1] = LHip(theta, eps, nu, dt, AFO_on)
t = 0;
% syms j
% M = 6;
% j = sym('j', [1 M]);
if t == 0
omega = 3*pi/2;
theta = 0;
phi = pi/2;
ampl = 0;
else
omega = omega*(t-1) + dt*(eps*offset*cos(phi1));
theta = theta*(t-1) + dt*(nu*offset);
phi = phi*(t-1) + dt*(omega + eps*offset*cos(phi*core(t-1)));
phi1 = phi*(t-1) + dt*(omega + eps*offset*cos(phi*core(t-1)));
ampl = ampl*(t-1) + dt*(nu*offset*sin(phi));
offset = theta - theta*(t-1) - sym(ampl*sin(phi), [1 M]);
end
pos_AFO = (theta*(t-1) + symsum(ampl*(t-1)*sin(phi* (t-1))))*AFO_on; %symsum needs input argument for index M and range
vel_AFO = diff(pos_AFO)*AFO_on;
acc_AFO = diff(vel_AFO)*AFO_on;
end
https://www.pastepic.xyz/image/pg4mP
Essentially, I don't know how to do the subscripts, sigma, or the (t+1) function. Any help is appreciated as this is due next week
You are looking to find the result of an adaptive process therefore your algorithm needs to consider time as it progresses. There is no (t-1) operator as such. It is just a mathematical notation telling you that you need to reuse an old value to calculate a new value.
omega_old=0;
theta_old=0;
% initialize the rest of your variables
for [t=1:N]
omega[t] = omega_old + % here is the rest of your omega calculation
theta[t] = theta_old + % ...
% more code .....
% remember your old values for next iteration
omega_old = omega[t];
theta_old = theta[t];
end
I think you forgot to apply the modulo operation to phi judging by the original formula you linked. As a general rule, design your code in small pieces, make sure the output of each piece makes sense and then combine all pieces and make sure the overall result is correct.

MATLAB script runs slowly: Solving System of Equations

EDIT: I used the profiler as suggested, and it looks like Matlab was spending a significant amount of time dealing with symbols and solving the system of equations. So, I will change my question slightly: is there a faster way to implement this system of equations, perhaps one that does not involve declaring symbols?
function [As_rad, Ae_rad] = pos_to_angle(x_pos, y_pos)
% Converts given x and y coordinates into angles (using link lengths)
Ls = 0.4064; % in meters
Le = 0.51435; % in meters
x_offset = 0.0;
y_offset = -0.65; % from computer running the robot
syms angle_s angle_e
x = x_pos + x_offset; % Account for offset of origins
y = y_pos + y_offset; % between motor and workspace
eqn1 = x == Ls*cos(angle_s) + Le*cos(angle_e); % Actual conversion
eqn2 = y == Ls*sin(angle_s) + Le*sin(angle_e);
sol1 = solve([eqn1, eqn2], [angle_s, angle_e]);
As_rad_mat = sol1.angle_s;
Ae_rad_mat = sol1.angle_e;
if As_rad_mat(1) > Ae_rad_mat(1);
As_rad = As_rad_mat(1);
Ae_rad = Ae_rad_mat(1);
else
As_rad = As_rad_mat(2);
Ae_rad = Ae_rad_mat(2);
end
end
To be more specific, it looked like a function mupadmex (which I believe is associated with symbols) took up about 80% of the computing time. The above is just an example of how I solved systems of equations throughout the script.
Thanks everyone for the responses! I ended up using profiler and found that the computation time was coming from solving the system of equations every time the program went through the loop. So I used a separate script to solve for the equation symbolically, so the script only has to do algebra. It is running MUCH quicker now.

Input & Coefficients from time domain to frequency, add them together and back to time domain

I am currently studying computer science and i have a task to solve for my lab project. I have to transfer input's signal & coefficients' from time domain to frequency domain, add them together and transfer back to time domain. My results have to match filter function output. However i cannot seem to find what am doing wrong here. I think its something wrong when i add two frequency via conj function. Unfortunately neither my teacher nor my lab supervisor are interested in actually teaching anything so i have to find answers on my own. Hope you guys can help.
clc
clear
B = [0.2];
A = [1,-0.5];
xt = ones(1,20);
xt = padarray(xt,[0,100])
A1 = 1;
A2 = 1;
f1 = 1;
f2 = 25;
fs = 1000;
xd = fft(xt);
wd = freqz(B,A,length(xt));
y = filter(B,A,xt);
yd = conj((wd)').*xd;
yt = real(ifft(yd));
subplot(4,2,1);
plot(xt)
title('Input signal')
subplot(4,2,2);
plot(abs(xd))
title('Input in frequency domain')
subplot(4,2,4);
plot(abs(wd))
title('Coefficients in frequency domain')
subplot(4,2,7);
plot(y)
title('Output using FILTER function')
subplot(4,2,6);
plot(yd)
title('Adding input with coefficients in frequency domain')
subplot(4,2,8);
plot(yt)
title('Back to time domain using IFFT')
The matlab function freqz() can be a little misleading. The "FFT" domain of your coefficients needs to be generated differently. Replace your stuff with the following code, and it should give you what you want:
xt = xt.';
xd = fft(xt);
wd = freqz(B,A,length(xt),'whole');
y = filter(B,A,xt);
yd = wd.*xd;
yt = ifft(yd);
figure
plot(abs(xd))
hold on
plot(abs(wd))
figure
plot(y,'.k','markersize',20)
hold on
plot(yt,'k')
hold off
Also, a note on the ' operator with complex vectors: unless you use the .' operator (e.g., x = x.'), it will transpose the vector while taking the complex conjugate, i.e., (1+1i).' = (1+1i) while (1+1i)' = (1-1i)

matlab ode45 retrieving parameters

I'm experimenting with ode45 in Matlab. I've learned how to pass parameters to the ode function but I still have a question. Let's suppose that I want to compute the trajectory (speed profile) of a Car and I have a function, e.g. getAcceleration, that gives me the acceleration of the car but also the right gear: [acceleration, gear] = getAcceleration(speed,modelStructure) where modelStructure represents the model of the car.
The ode function would be:
function [dy] = car(t,y,modelStructure)
dy = zeros(2,1);
dy(1) = y(2);
[dy(2),gear] = getAcceleration(y(1),modelStructure);
Then I call the Ode45 integrator in this way:
tInit = 0;
tEnd = 5,
[t,y] = ode45(#car,[tInit tEnd], [speedInitial,accelerationInitial],options,modelStructure);
The problem is: how do I get the vector storing gears? Should I have something like [t,y,gear]=ode45(....) or should gear be within the y vector?
I've been working on my code and using the events function I'm now able to get the car 'gears' changes (as events).
Now I have a new problem related to the same code.
Imagine that when I evaluate de 'dy' vector I'm able to get a further value Z which let me to have a massive speed up calling the acceleration computation (getAcceleration):
function [dy] = car(t,y,modelStructure)
dy = zeros(2,1);
dy(1) = y(2);
[dy(2),Z(t)] = getAcceleration(y(1),modelStructure,Z(t-1));
and suppose that I'm also able to compute Z at the initial condition. The problem is that I'm not able to compute the Z derivative.
Is there a way to pass Z value throw the stepping without integrating it?
Thanks guys.
First off: why are the initial values to the differential equation the initial speed (speedInitial) and the initial acceleration (accelerationInitial)? That means that the differential equation car will be computing the acceleration (y(1)) and the jerk (y(2)), the time-derivative of the acceleration, at each time t. That seems incorrect...I would say the initial values should be the initial position (positionInitial) and the initial speed (speedInitial). But, I don't know your model, I could be wrong.
Now, getting the gear in the solution directlty: you can't, not without hacking ode45. This is also logical; you also cannot get dy at all times directly, can you? That's just not how ode45 is set up.
There's two ways out I see here:
Global variable
DISCLAIMER: don't use this method. It's only here to show what most people would do as a first attempt.
You can store gear in a global variable. It's probably the least amount of coding, but also the least convenient outcome:
global ts gear ii
ii = 1;
tInit = 0;
tEnd = 5,
[t,y] = ode45(...
#(t,y) car(t,y,modelStructure), ...
[tInit tEnd], ...
[speedInitial, accelerationInitial], options);
...
function [dy] = car(t,y,modelStructure)
global ts gear ii
dy = zeros(2,1);
dy(1) = y(2);
[dy(2),gear(ii)] = getAcceleration(y(1),modelStructure);
ts(ii) = t;
ii = ii + 1;
But, due to the nature of ode45, this will get you an array of times ts and associated gear which contains intermediate points and/or points that got rejected by ode45. So, you'll have to filter for those afterwards:
ts( ~ismember(ts, t) ) = [];
I'll say it again: this is NOT the method I'd recommend. Only use global variables when testing or doing some quick-n-dirty stuff, but always very quickly shift towards other solutions. Also, the global variables grow at each (sub-)iteration of ode45, which is an unacceptable performance penalty.
It's better to use the next method:
Post-solve call
This is also not too hard for your case, and the way I'd recommend you to go. First, modify the differential equation as below, and solve as normal:
tInit = 0;
tEnd = 5,
[t,y] = ode45(...
#(t,y) car(t,y,modelStructure), ...
[tInit tEnd], ...
[speedInitial, accelerationInitial], options);
...
function [dy, gear] = car(t,y,modelStructure)
dy = [0;0];
dy(1) = y(2);
[dy(2),gear] = getAcceleration(y(1),modelStructure);
and then after ode45 completes, do this:
gear = zeros(size(t));
for ii = 1:numel(t)
[~, gear(ii)] = car(t(ii), y(ii,:).', modelStructure);
end
That will get you all the gears the car would have at times t.
The only drawback that I can see here is that you'll have many more function evaluations of car than ode45 would use by itself. But this is only a real problem if each evaluation of car takes in the order of seconds or longer, which I suspect is not the case in your setup.