I'm trying to calculate Euler-Lagrange equations for a robotic structure.
I'll use q to indicate the vector of the joint variables.
In my code, I use
syms t;
q1 = sym('q1(t)');
q2 = sym('q2(t)');
q = [q1, q2];
to declare that q1 and q2 depend on time t.
After I calculate the Lagrangian L (in this case it is a simple link with a rotoidal joint)
L = (I1z*diff(q1(t), t)^2)/2 + (L1^2*M1*diff(q1(t), t)^2)/8
The problem is that when I try to differentiate L respect to q using diff(L, q), I get this error
Error using sym/diff (line 69)
The second argument must be a variable or a nonnegative integer specifying the number of differentiations.
How can I differentiate L respect to q to have the first term of the Euler-Lagrange equation?
I also tried to write q simply as
syms q1 q2
q = [q1 q2]
without the time dependency but differentiation will not work, i.e. will obviously give me [0, 0]
That's what I've got in the workspace (I1z is the inertia of the link respect to z-axis, M1 is the mass of the link, L1 is the length of the link)
q = [q1(t), q2(t)]
diff(q, t) = [diff(q1(t), t), diff(q2(t), t)]
L = (I1z*diff(q1(t), t)^2)/2 + (L1^2*M1*diff(q1(t), t)^2)/8
If you want to run the full code, you have to download all the .m files from here and then use
[t, q, L, M, I] = initiate();
L = lagrangian(odof(q, L), q, M, I, t, 1)
otherwise the following code should be the same.
syms t I1z L1 M1
q1 = sym('q1(t)');
q2 = sym('q2(t)');
q = [q1, q2];
qp = diff(q, t);
L = (I1z*qp(1)^2)/2 + (L1^2*M1*qp(1)^2)/8;
EDIT
Thanks to AVK's answer I realized the problem.
Example 1 (AVK's code)
syms t q1 q2 q1t q2t I1z L1 M1 % variables
L = (I1z*q1t^2)/2 + (L1^2*M1*q1t^2)/8
dLdqt = [diff(L,q1t), diff(L,q2t)]
This will work and its result will be
dLdqt = [(M1*q1t*L1^2)/4 + I1z*q1t, 0]
Example 2 (wrong)
syms t q1 q2 q1t q2t I1z L1 M1
L = (I1z*q1t^2)/2 + (L1^2*M1*q1t^2)/8;
qt = [q1t q2t];
dLdqt = diff(L, qt)
This will not work, because diff expects a single variable of differentiation
Example 3 (right)
syms t q1 q2 q1t q2t I1z L1 M1
L = (I1z*q1t^2)/2 + (L1^2*M1*q1t^2)/8;
qt = [q1t q2t];
dLdqt = jacobian(L, qt)
This will work, because jacobian expects at least a variable of differentiation
EDIT 2
Seems that MATLAB's Symbolit Toolbox can't handle differentiation with respect to q(t), so you have to use the variable q.
So using these as functions
q = [q1(t), q2(t), q3(t), q4(t), q5(t), q6(t)]
qp = [diff(q1(t), t), diff(q2(t), t), diff(q3(t), t), diff(q4(t), t), diff(q5(t), t), diff(q6(t), t)]
and these as variables
qv = [q1, q2, q3, q4, q5, q6];
qvp = [q1p, q2p, q3p, q4p, q5p, q6p];
solved the problem.
The whole code will looks like this
syms q1 q2 q3 q4 q5 q6;
syms q1p q2p q3p q4p q5p q6p;
qv = [q1, q2, q3, q4, q5, q6];
qvp = [q1p, q2p, q3p, q4p, q5p, q6p];
Lagv = subs(Lag, [q, qp], [qv, qvp]);
dLdq = jacobian(Lagv, qv);
dLdqp = jacobian(Lagv, qvp);
dLdq = subs(dLdq, [qv, qvp], [q, qp]);
dLdqp = subs(dLdqp, [qv, qvp], [q, qp]);
m_eq = diff(dLdqp, t) - dLdq;
If you want to differentiate L with respect to q, q must be a variable. You can use subs to replace it with a function and calculate
later:
syms t q1 q2 q1t q2t I1z L1 M1 % variables
L = (I1z*q1t^2)/2 + (L1^2*M1*q1t^2)/8
dLdqt= [diff(L,q1t), diff(L,q2t)]
dLdq = [diff(L,q1), diff(L,q2)]
syms q1_f(t) q2_f(t) % functions
q1t_f(t)= diff(q1_f,t)
q2t_f(t)= diff(q2_f,t)
% replace the variables with the functions
dLdq_f= subs(dLdq,{q1 q2 q1t q2t},{q1_f q2_f q1t_f q2t_f})
dLdqt_f= subs(dLdqt,{q1 q2 q1t q2t},{q1_f q2_f q1t_f q2t_f})
% now we can solve the equation
dsolve(diff(dLdqt_f,t)-dLdq_f==0)
I developed the Euler-Lagrange Library in MATLAB, with a list of illustrative examples. you can download it using the following link:
https://www.mathworks.com/matlabcentral/fileexchange/86563-matlab-euler-lagrange-library
Related
This is a follow-up on a previous question by myself: Laplace transform of numerical data in MATLAB
I have experimentally collected data, and want to take a Laplace transformation of that. However, laplace() needs a model/equation. I find a fit equation to model my data from:
[up,lo] = envelope(dat);
x = 1:length(up);
x = x';
f = fit(x,up,'poly3');
Then for my Laplace transform I need to I pass the output of
f = fit(x,up,'poly3');
into
syms f
laplace(f)
However at the moment this spits out the transform of f:
laplace(f)
ans =
1/s^2
If this is f
f =
Linear model Poly3:
f(x) = p1*x^3 + p2*x^2 + p3*x + p4
Coefficients (with 95% confidence bounds):
p1 = 1.772e-12 (1.593e-12, 1.951e-12)
p2 = -2.211e-08 (-2.483e-08, -1.939e-08)
p3 = 2.847e-05 (1.676e-05, 4.017e-05)
p4 = 0.2762 (0.2627, 0.2897)
How do I find the Laplace transform of f?
I'm not familiar with the output of fit, but your symbolic variable at least should be x, as that's your dependent variable. You can then build up the f yourself:
p1 = 1.772e-12;
p2 = -2.211e-08;
p3 = 2.847e-05;
p4 = 0.2762;
syms x
f = p1*x.^3 + p2*x.^2 + p3*x + p4;
laplace(f)
ans =
(8402860860456175*((50949907131585781563392*s)/5251788037785109375 + 1))/(295147905179352825856*s^2) - 6682337467919863/(151115727451828646838272*s^3) + 26323556995364325/(2475880078570760549798248448*s^4)
fit() gives you a fitobject type variable, which, if I understand its documentation correctly, can be accessed as a structure. This means that you should be able to programmatically use the fitted parameters to build your function of symbolic x.
I'm trying to write a function in Matlab that calculates the Call price using the Black Scholes formula with vector inputs. I have so far:
function [C] = BlackScholesCall(S,K,t,r,sigma)
%This function calculates the call price per Black-Scholes equation
%INPUT S ... stock price at time 0
% K ... strike price
% r ... interest rate
% sigma ... volatility of the stock price measured as annual standard deviation
% t ... duration in years
%OUTPUT C ... call price
%USAGE BlackScholesCall(S,K,t,r,sigma)
for l = 1:length(K)
for z = 1:length(t)
d1 = (log(S/K(l)) + (r + 0.5*sigma^2)*t(z))/(sigma*sqrt(t(z)));
d2 = d1 - sigma*sqrt(t(z));
N1 = 0.5*(1+erf(d1/sqrt(2)));
N2 = 0.5*(1+erf(d2/sqrt(2)));
C(l) = S*N1-K(l)*exp(-r*t(z))*N2;
end
end
end
F.e. the code to call my function would be
S = 20
K = 16:21
t = 1:1:5
r = 0.02
sigma = 0.25
C = BlackScholesCall(S, K, t, r, sigma)
But when I compare this with the results of the blsprice function in Matlab, I get different results. I suspect there might be something wrong with the way I did the loop?
You are getting the same results as,
>> blsprice(S,K,r,t(end),sigma)
ans =
7.1509 6.6114 6.1092 5.6427 5.2102 4.8097
This is because by using C(l) = ... you are overwriting each element of C numel(t) times, and hence only storing/returning the last calculated values for each value of z.
At a minimum you need to use,
%C(l) = S*N1-K(l)*exp(-r*t(z))*N2;
C(z,l) = S*N1-K(l)*exp(-r*t(z))*N2;
But you should also pre-allocate your output matrix. That is, before either of the loops, you should add
C = nan(numel(K),numel(t));
Finally, you should note that you don't need to use any loops at all,
[Kmat,tmat] = meshgrid(K,t);
d1 = (log(S./Kmat) + (r + 0.5*sigma^2)*tmat)./(sigma*sqrt(tmat));
d2 = d1 - sigma*sqrt(tmat);
N1 = 0.5*(1+erf(d1/sqrt(2)));
N2 = 0.5*(1+erf(d2/sqrt(2)));
C = S*N1-Kmat.*exp(-r*tmat).*N2;
An R version could be the following.
BlackScholesCall <- function(S, K, tt, r, sigma){
f <- function(.K, .tt){
d1 <- (log(S/.K) + (r + 0.5*sigma^2)*.tt)/(sigma*sqrt(.tt))
d2 <- d1 - sigma*sqrt(.tt)
S*pnorm(d1) - .K*exp(-r*.tt)*pnorm(d2)
}
m <- length(K)
n <- length(tt)
o <- outer(K, tt, f)
last <- if(m > n) o[n:m, n] else o[m, m:n]
c(diag(o), last)
}
BlackScholesCall(S, K, tt, r, sigma)
#[1] 4.703480 4.783563 4.914990 5.059922 5.210161 5.210161 4.809748
I've noticed some weird facts about integral2. These are probably due to my limitations in understanding how it works. I have some difficulties in integrating out variables when I have particular functions. For instance, look at the following Code:
function Output = prova(p,Y)
x = p(1);
y = p(2);
w = p(3);
z = p(4);
F1 = #(Data,eta_1,eta_2,x,y,w,z) F2(eta_1,eta_2,Data) .* normpdf(eta_1,x,y) .* normpdf(eta_2,w,z);
Output = integral2(#(eta_1,eta_2)F1(Y,eta_1,eta_2,0,1,10,2),-5,5,-5,5);
end
function O = F2(pp1,pp2,D)
O = pp1 + pp2 + sum(D);
end
In this case the are no problems in evaluating the integral. But if I change the code in this way I obtain some errors, although the output of F2 is exactly the same:
function Output = prova(p,Y)
x = p(1);
y = p(2);
w = p(3);
z = p(4);
F1 = #(Data,eta_1,eta_2,x,y,w,z) F2(eta_1,eta_2,Data) .* normpdf(eta_1,x,y) .* normpdf(eta_2,w,z);
Output = integral2(#(eta_1,eta_2)F1(Y,eta_1,eta_2,0,1,10,2),-5,5,-5,5);
end
function O = F2(pp1,pp2,D)
o = sum([pp1 pp2]);
O = o + sum(D);
end
The problems increase if F2 for example have some matrix multiplication in which "eta_1" and "eta_2", which I want to integrate out, are involved. This problems makes practically impossible to solve computations in which, for instance, we have to integrate out a variable X which is inside a Likelihood Function (whose calculation could require some internal Loop, or Sum, or Prod involving our variable X). What is the solution?
I am trying to solve a RLC circuit as a symbolic differential equation in MATLAB using dsolve, the equation being
U(t) = L*Q''(t) + R*Q'(t) + (1/C)*Q(t)
with the initial conditions
Q(0) = 0
Q'(0) = 0
and
U(t) = 10*sin(2*t)
L = 1
R = 0
C = 1/4
While this works ...
When I implement it explicitly (and using strings) as
Q = dsolve('D2Q(t) + 4*Q(t) = 10*sin(2*t)', 'DQ(0)=0, Q(0)=0');
Q = simplify(Q);
I'll get
Q =
5 sin(2 t) 5 t cos(2 t)
---------- - ------------
4 2
which is correct.
... this does not.
For purely esoteric reasons I tried computing it directly using symbolic equations, as the documentation on dsolve stated it could be done.
So starting with
syms L R C t Q(t)
U = sym('10')*sin(sym('2')*t)
DEQ = L*diff(Q(t),t,2) + R*diff(Q(t),t) + (1/C)*Q(t)
DEQ = subs(DEQ, [L R C], [sym('1'), sym('0'), sym('1/4')])
eqn = (U == DEQ)
I receive
eqn =
10*sin(2*t) == 4*Q(t) + diff(Q(t), t, t)
Which is correct. If I now feed it into dsolve though, using
Q = dsolve(eqn, ...
Q(t) == 0, ...
diff(Q(t),t) == 0);
Matlab throws the error
Error using symengine (line 58)
Could not extract differential variables to solve for. Use 'solve' or 'vpasolve'
to compute the solutions of non-differential equations.
Why is that?
It looks like you're using sym/diff and symfuns incorrectly. Q(t) is what is referred to as an arbitrary (help sym/diff uses the term "abstract" instead) symbolic function, i.e., a function with no definition. Your function's name is Q (think of it as a function handle) and it is represented by the abstract formula Q(t), which just means that it's a function of t. When you want to take the derivative of an abstract function, pass in the name of the function - in your case, Q (the online documentation makes this slightly clearer, but not really). When you want evaluate the function use the formula, e.g., Q(0), the output of which is a sym rather than a symfun.
Here is how I might write the code for your second case:
syms L R C t Q(t)
U = 10*sin(2*t); % No need to wrap integer or exactly-represenable values in sym
dQ = diff(Q,t);
d2Q = diff(dQ,t);
DEQ = L*d2Q + R*dQ + Q/C;
DEQ = subs(DEQ, {L, R, C}, {1, 0, 1/4});
eqn = (U == DEQ);
Q = dsolve(eqn, Q(0) == 0, dQ(0) == 0);
Q = simplify(Q)
which returns
Q =
(5*sin(2*t))/4 - (5*t*cos(2*t))/2
You also forgot to evaluate your initial conditions at zero in the second case so I fixed that too. By the way, in current versions of Matlab you should be using the pure symbolic form for symbolic math (as opposed to strings).
Suppose we are given a training dataset {yᵢ, xᵢ}, for i = 1, ..., n, where yᵢ can either be -1 or 1 and xᵢ can be e.g. a 2D or 3D point.
In general, when the input points are linearly separable, the SVM model can be defined as follows
min 1/2*||w||²
w,b
subject to the constraints (for i = 1, ..., n)
yᵢ*(w*xᵢ - b) >= 1
This is often called the hard-margin SVM model, which is thus a constrained minimization problem, where the unknowns are w and b. We can also omit 1/2 in the function to be minimized, given it's just a constant.
Now, the documentation about Matlab's quadprog states
x = quadprog(H, f, A, b) minimizes 1/2*x'*H*x + f'*x subject to the restrictions A*x ≤ b. A is a matrix of doubles, and b is a vector of doubles.
We can implement the hard-margin SVM model using quadprog function, to get the weight vector w, as follows
H becomes an identity matrix.
f' becomes a zeros matrix.
A is the left-hand side of the constraints
b is equal to -1 because the original constraint had >= 1, it becomes <= -1 when we multiply with -1 on both sides.
Now, I am trying to implement a soft-margin SVM model. The minimization equation here is
min (1/2)*||w||² + C*(∑ ζᵢ)
w,b
subject to the constraints (for i = 1, ..., n)
yᵢ*(w*xᵢ - b) >= 1 - ζᵢ
such that ζᵢ >= 0, where ∑ is the summation symbol, ζᵢ = max(0, 1 - yᵢ*(w*xᵢ - b)) and C is a hyper-parameter.
How can this optimization problem be solved using the Matlab's quadprog function? It's not clear to me how the equation should be mapped to the parameters of the quadprog function.
The "primal" form of the soft-margin SVM model (i.e. the definition above) can be converted to a "dual" form. I did that, and I am able to get the Lagrange variable values (in the dual form). However, I would like to know if I can use quadprog to solve directly the primal form without needing to convert it to the dual form.
I don't see how it can be a problem. Let z be our vector of (2n + 1) variables:
z = (w, eps, b)
Then, H becomes diagonal matrix with first n values on the diagonal equal to 1 and the last n + 1 set to zero:
H = diag([ones(1, n), zeros(1, n + 1)])
Vector f can be expressed as:
f = [zeros(1, n), C * ones(1, n), 0]'
First set of constrains becomes:
Aineq = [A1, eye(n), zeros(n, 1)]
bineq = ones(n, 1)
where A1 is a the same matrix as in primal form.
Second set of constraints becomes lower bounds:
lb = (inf(n, 1), zeros(n, 1), inf(n, 1))
Then you can call MATLAB:
z = quadprog(H, f, Aineq, bineq, [], [], lb);
P.S. I can be mistaken in some small details, but the general idea is right.
I wanted to clarify #vharavy answer because you could get lost while trying to deduce what 'n' means in his code. Here is my version according to his answer and SVM wikipedia article. I assume we have a file named "test.dat" which holds coordinates of test points and their class membership in the last column.
Example content of "test.dat" with 3D points:
-3,-3,-2,-1
-1,3,2,1
5,4,1,1
1,1,1,1
-2,5,4,1
6,0,1,1
-5,-5,-3,-1
0,-6,1,-1
-7,-2,-2,-1
Here is the code:
data = readtable("test.dat");
tableSize = size(data);
numOfPoints = tableSize(1);
dimension = tableSize(2) - 1;
PointsCoords = data(:, 1:dimension);
PointsSide = data.(dimension+1);
C = 0.5; %can be changed
n = dimension;
m = numOfPoints; %can be also interpretet as number of constraints
%z = [w, eps, b]; number of variables in 'z' is equal to n + m + 1
H = diag([ones(1, n), zeros(1, m + 1)]);
f = [zeros(1, n), C * ones(1, m), 0];
Aineq = [-diag(PointsSide)*table2array(PointsCoords), -eye(m), PointsSide];
bineq = -ones(m, 1);
lb = [-inf(1, n), zeros(1, m), -inf];
z = quadprog(H, f, Aineq, bineq, [], [], lb);
If let z = (w; w0; eps)T be a the long vector with n+1+m elements.(m the number of points)
Then,
H= diag([ones(1,n),zeros(1,m+1)]).
f = [zeros(1; n + 1); ones(1;m)]
The inequality constraints can be specified as :
A = -diag(y)[X; ones(m; 1); zeroes(m;m)] -[zeros(m,n+1),eye(m)],
where X is the n x m input matrix in the primal form.Out of the 2 parts for A, the first part is for w0 and the second part is for eps.
b = ones(m,1)
The equality constraints :
Aeq = zeros(1,n+1 +m)
beq = 0
Bounds:
lb = [-inf*ones(n+1,1); zeros(m,1)]
ub = [inf*ones(n+1+m,1)]
Now, z=quadprog(H,f,A,b,Aeq,beq,lb,ub)
Complete code. The idea is the same as above.
n = size(X,1);
m = size(X,2);
H = diag([ones(1, m), zeros(1, n + 1)]);
f = [zeros(1,m+1) c*ones(1,n)]';
p = diag(Y) * X;
A = -[p Y eye(n)];
B = -ones(n,1);
lb = [-inf * ones(m+1,1) ;zeros(n,1)];
z = quadprog(H,f,A,B,[],[],lb);
w = z(1:m,:);
b = z(m+1:m+1,:);
eps = z(m+2:m+n+1,:);