How to get algebraic solution and symbolic Jacobian of this simple equation? - matlab

(Crossposted from Matlab Answers) I am trying to simplify this set of algebraic equations. Then, I would like to have Matlab calculate the Jacobian for me. But it does not seem to work as I expect.
Consider this simple MWE:
% State Variables
syms x_0 x_1 x_2 x_3
% Input Variables
syms u_1 u_2 u_3
% Constants
syms k_1 V_liq dvs
% 3 Algebraic Equations
stateEquations = [...
x_1 == (x_0*(V_liq - u_1/dvs*1e3)*1e-3 + u_1)*1e3/V_liq*exp(-k_1), ...
x_2 == (x_1*(V_liq - u_2/dvs*1e3)*1e-3 + u_2)*1e3/V_liq*exp(-k_1), ...
x_3 == (x_2*(V_liq - u_3/dvs*1e3)*1e-3 + u_3)*1e3/V_liq*exp(-k_1)];
dstate_x3 = solve(stateEquations, x_3)
dstate_du = jacobian(dstate_x3, [u_1 u_2 u_3])
Since dstate_x3 is empty, the Jacobian is also empty. But I simply want Matlab to replace x_2 in eq. 3 by its right-hand side, and x_1 by its right-hand side...
Could you please give me a hint on how to achieve this with Symbolic Math Toolbox? (Deriving it manually would be very time-consuming, especially with x_i, i > 3)

Since your system has 3 equations, you must solve it for 3 variables, not just for the variable x_3. Because solve doesn't know which variables you want so solve your system for, then it returns an empty solution.
You want to solve for x_1, x_2 and x_3, so replace the penultimate line of your code by
dstate = solve(stateEquations, [x_1 x_2 x_3])
Now dstate is an 1x1 struct with 3  sym fields: x_1, x_2 and x_3. Hence, replace the last line of your code by
dstate_du = jacobian(dstate.x_3, [u_1 u_2 u_3])
Eventually, you might want to  simplify(dstate_du).

Related

Solving 2nd order ODE, Matlab- the acceleration in the equation needs its own value in order to include another different term

I have this 2nd order ODE to solve in Matlab:
(a + f(t))·(dx/dt)·(d²x/dt²) + g(t) + ((h(t) + i(t)·(d²x/dt² > b·(c-x)))·(dx/dt) + j(t))·(dx/dt)² + k(t)·(t > d) = 0
where
a,b,c,d are known constants
f(t),g(t),h(t),i(t),j(t),k(t) are known functions dependent on t
x is the position
dx/dt is the velocity
d²x/dt² is the acceleration
and notice the two conditions that
i(t) is introduced in the equation if (d²x/dt² > b·(c-x))
k(t) is introduced in the equation if (t > d)
So, the problem could be solved with a similar structure in Matlab as this example:
[T,Y] = ode45(#(t,y) [y(2); 'the expression of the acceleration'], tspan, [x0 v0]);
where
T is the time vector, Y is the vector of position (column 1 as y(1)) and velocity (column 2 as y(2)).
ode45 is the ODE solver, but another one could be used.
tspan,x0,v0 are known.
the expression of the acceleration means an expression for d²x/dt², but here comes the problem, since it is inside the condition for i(t) and 'outside' at the same time multiplying (a + f(t))·(dx/dt). So, the acceleration cannot be written in matlab as d²x/dt² = something
Some issues that could help:
once the condition (d²x/dt² > b·(c-x)) and/or (t > d) is satisfied, the respective term i(t) and/or k(t) will be introduced until the end of the determined time in tspan.
for the condition (d²x/dt² > b·(c-x)), the term d²x/dt² could be written as the difference of velocities, like y(2) - y(2)', if y(2)' is the velocity of the previous instant, divided by the step-time defined in tspan. But I do not know how to access the previous value of the velocity during the solving of the ODE
Thank you in advanced !
First of all, you should reduce your problem to a first-order differential equation, by substituting dx/dt with a dynamical variable for the velocity.
This is something you have to do anyway for solving the ODE and this way you do not need to access the previous values of the velocity.
As for realising your conditions, just modify the function you pass to ode45 to account for this.
For this purpose you can use that d²x/dt² is in the right-hand side of your ODE.
Keep in mind though that ODE solvers do not like discontinuities, so you may want to smoothen the step or just restart the solver with a different function, once the condition is met (credit to Steve).
The second conditional term k(t)*(t>d) should be simple enough to implement, so I'll pass over that.
I would split up your equation into two part:
F1(t,x,x',x'') := (a+f(t))x'x'' + g(t) + (h(t)x'+j(t))x'' + k(t)(t>d),
F2(t,x,x',x'') := F1(t,x,x',x'') + i(t)x'x'',
where prime denote time derivatives. As suggested in this other answer
[...] or just restart the solver with a different function
you could solve the ODE F1 for t \in [t0, t1] =: tspan. Next, you'd find the first time tstar where x''> b(c-x) and the values x(tstar) and x'(tstar), and solve F2 for t \in [tstar,t1] with x(tstar), x'(tstar) as starting conditions.
Having said all that, the proper implementation of this should be using events, as suggested in LutzL's comment.
So, I should use something that looks like this:
function [value,isterminal,direction] = ODE_events(t,y,b,c)
value = d²x/dt² - b*(c-y(1)); % detect (d²x/dt² > b·(c-x)), HOW DO I WRITE d²x/dt² HERE?
isterminal = 0; % continue integration
direction = 0; % zero can be approached in either direction
and then include in the file (.m), where my ode is, this:
refine = 4; % I do not get exactly how this number would affect the results
options = odeset('Events',#ODE_events,'OutputFcn',#odeplot,'OutputSel',1, 'Refine',refine);
[T,Y] = ode45(#(t,y) [y(2); ( 1/(a + f(t))*(y(2)))*( - g(t) - ((h(t) + i(t))·(y(2)) - j(t)·(y(2))² - k(t)*(t > d)) ], tspan, [x0 v0], options);
How do I handle i(t)? because i(t)*(d²x/dt² > b*(c-y(1))))*(y(2)) has to be included somehow.
Thank you again

matlab optimization: objective function with dependent decision variable

I want to optimize an objective function with dependent decision variables as below.
Sum [I * (x(i) - x(i-1) + lo(i) - g(i)) * p(i)]
Please note that the decision variable is only x(i) and x(i-1) is a value came from previous step of optimization.
I have no idea how to write this objective function. Should I use function handler? Thanks
Perhaps this is what you're asking?
Imagine you have a 3 by 1 vector x.
[x_1
x = x_2
x_3]
and you want to compute:
[x_1 [0
y= x_2 - x_1
x_3 x_2]
You could do this in Matlab with the code:
y = x - [0;x(1:end-1)];
this works since x(1:end-1) will refer to [x_1; x_2]. You can use this snippet to write your overall objective function.

Solving an ODE when the function is given as discrete values -matlab-

I have the following ODE:
x_dot = 3*x.^0.5-2*x.^1.5 % (Equation 1)
I am using ode45 to solve it. My solution is given as a vector of dim(k x 1) (usually k = 41, which is given by the tspan).
On the other hand, I have made a model that approximates the model from (1), but in order to compare how accurate this second model is, I want to solve it (solve the second ODE) by means of ode45. My problem is that this second ode is given discrete:
x_dot = f(x) % (Equation 2)
f is discrete and not a continuous function like in (1). The values I have for f are:
0.5644
0.6473
0.7258
0.7999
0.8697
0.9353
0.9967
1.0540
1.1072
1.1564
1.2016
1.2429
1.2803
1.3138
1.3435
1.3695
1.3917
1.4102
1.4250
1.4362
1.4438
1.4477
1.4482
1.4450
1.4384
1.4283
1.4147
1.3977
1.3773
1.3535
1.3263
1.2957
1.2618
1.2246
1.1841
1.1403
1.0932
1.0429
0.9893
0.9325
0.8725
What I want now is to solve this second ode using ode45. Hopefully I will get a solution very similar that the one from (1). How can I solve a discrete ode applying ode45? Is it possible to use ode45? Otherwise I can use Runge-Kutta but I want to be fair comparing the two methods, which means that I have to solve them by the same way.
You can use interp1 to create an interpolated lookup table function:
fx = [0.5644 0.6473 0.7258 0.7999 0.8697 0.9353 0.9967 1.0540 1.1072 1.1564 ...
1.2016 1.2429 1.2803 1.3138 1.3435 1.3695 1.3917 1.4102 1.4250 1.4362 ...
1.4438 1.4477 1.4482 1.4450 1.4384 1.4283 1.4147 1.3977 1.3773 1.3535 ...
1.3263 1.2957 1.2618 1.2246 1.1841 1.1403 1.0932 1.0429 0.9893 0.9325 0.8725];
x = 0:0.25:10
f = #(xq)interp1(x,fx,xq);
Then you should be able to use ode45 as normal:
tspan = [0 1];
x0 = 2;
xout = ode45(#(t,x)f(x),tspan,x0);
Note that you did not specify what values of of x your function (fx here) is evaluated over so I chose zero to ten. You'll also not want to use the copy-and-pasted values from the command window of course because they only have four decimal places of accuracy. Also, note that because ode45 required the inputs t and then x, I created a separate anonymous function using f, but f can created with an unused t input if desired.

Implementing iterative solution of integral equation in Matlab

We have an equation similar to the Fredholm integral equation of second kind.
To solve this equation we have been given an iterative solution that is guaranteed to converge for our specific equation. Now our only problem consists in implementing this iterative prodedure in MATLAB.
For now, the problematic part of our code looks like this:
function delta = delta(x,a,P,H,E,c,c0,w)
delt = #(x)delta_a(x,a,P,H,E,c0,w);
for i=1:500
delt = #(x)delt(x) - 1/E.*integral(#(xi)((c(1)-c(2)*delt(xi))*ms(xi,x,a,P,H,w)),0,a-0.001);
end
delta=delt;
end
delta_a is a function of x, and represent the initial value of the iteration. ms is a function of x and xi.
As you might see we want delt to depend on both x (before the integral) and xi (inside of the integral) in the iteration. Unfortunately this way of writing the code (with the function handle) does not give us a numerical value, as we wish. We can't either write delt as two different functions, one of x and one of xi, since xi is not defined (until integral defines it). So, how can we make sure that delt depends on xi inside of the integral, and still get a numerical value out of the iteration?
Do any of you have any suggestions to how we might solve this?
Using numerical integration
Explanation of the input parameters: x is a vector of numerical values, all the rest are constants. A problem with my code is that the input parameter x is not being used (I guess this means that x is being treated as a symbol).
It looks like you can do a nesting of anonymous functions in MATLAB:
f =
#(x)2*x
>> ff = #(x) f(f(x))
ff =
#(x)f(f(x))
>> ff(2)
ans =
8
>> f = ff;
>> f(2)
ans =
8
Also it is possible to rebind the pointers to the functions.
Thus, you can set up your iteration like
delta_old = #(x) delta_a(x)
for i=1:500
delta_new = #(x) delta_old(x) - integral(#(xi),delta_old(xi))
delta_old = delta_new
end
plus the inclusion of your parameters...
You may want to consider to solve a discretized version of your problem.
Let K be the matrix which discretizes your Fredholm kernel k(t,s), e.g.
K(i,j) = int_a^b K(x_i, s) l_j(s) ds
where l_j(s) is, for instance, the j-th lagrange interpolant associated to the interpolation nodes (x_i) = x_1,x_2,...,x_n.
Then, solving your Picard iterations is as simple as doing
phi_n+1 = f + K*phi_n
i.e.
for i = 1:N
phi = f + K*phi
end
where phi_n and f are the nodal values of phi and f on the (x_i).

Cross characteristics of a non-linear equation in Matlab

I'd like to create a Matlab plot of propeller angular velocity in terms of applied current. The point is, this requires combining two interdependent sets of data.
Firstly, drag coefficient c_d depends on angular velocity omega (I have no formula, just data) as seen on the plot below - the characteristics c_d(omega) could be easily linearised as c_d(omega) = p*omega + p_0.
Secondly, omega depends not only on applied current i, but also on the drag coefficient c_d(omega).
A script that solves the case, where c_d is constant below. It must be somehow possible to join those two using Matlab commands. Thanks for any help.
%%Lookup table for drag coefficient c_d
c_d_lookup = [248.9188579 0.036688351; %[\omega c_d]
280.2300647 0.037199094;
308.6091183 0.037199094;
338.6636881 0.03779496;
365.8908244 0.038305703;
393.9557188 0.039156941;
421.9158934 0.039667683;
452.2846224 0.040348674;
480.663676 0.041199911;
511.032405 0.042051149;
538.9925796 0.042561892;
567.2669135 0.043242882;
598.4734005 0.043668501;
624.1297405 0.044264368;
651.9851954 0.044604863;
683.6105614 0.045200729];
subplot(2,1,1)
plot(c_d_lookup(:,1), c_d_lookup(:,2))
title('This is how c_d depends on \omega')
ylabel('c_d')
xlabel('\omega [rad/s]')
%%Calculate propeller angular speed in terms of applied current. omega
%%depends on c_d, which in turn depends on omega. The formula is:
% omega(i) = sqrt(a*i / (b * c_d(omega)))
% Where:
% i - applied current
% omega - propeller angular velocity
% a,b - coefficients
i = [1:15];
a = 0.0718;
b = 3.8589e-005;
%If c_d was constant, I'd do:
omega_i = sqrt(a .* i / (b * 0.042));
subplot(2,1,2)
plot(i, omega_i)
ylabel({'Propeller ang. vel.', '\omega [rad/s]'})
xlabel('Applied current i[A]')
title('Propeller angular velocity in terms of applied current')
EDIT:
Trying to follow bdecaf's solution. So I created a function c_d_find, like so:
function c_d = c_d_find(omega, c_d_lookup)
c_d = interp1(c_d_lookup(:,1), c_d_lookup(:,2), omega, 'linear', 'extrap');
end
I don't know anything about Matlab function handles, but seem to understand the idea... In Matlab command window I typed:
f = #(omega) omega - sqrt(a .* i / (b * c_d_find(omega, c_d_lookup)))
which I hope created the correct function handle. What do I do next? Executing the below doesn't work:
>> omega_consistent = fzero(f,0)
??? Operands to the || and && operators must be convertible to logical scalar
values.
Error in ==> fzero at 333
elseif ~isfinite(fx) || ~isreal(fx)
hmmm...
Wonder if I understand correctly - but looks like you are looking for a consistent solution.
Your equations don't look to complicated I would outline the solution like this:
Write a function function c_d = c_d_find(omega) that does some interpolation or so
make a function handle like f = #(omega) omega - sqrt(a .* i / (b * c_d_find(omega))) - this is zero for consistent omega
calculate a consistent omega with omega_consistent =fzero(f,omega_0)