multipoint boundary value ode with varying coefficients in matlab - matlab

I have a second order differential equation given as:
d²u/dz²=a+bu, where a and b are constants that vary in different intervals and z∈[0,Zn]
Intervals are given as I1:z∈[0,Z1), I2:z∈[Z1, Z2), ..., I(n):z∈[Z(n-1), Z(n)] and {a,b} constants varies as {a1,b1} in I1, {a2,b2} in I2,...,{an,bn} in I(n).
Boundary condition is given as u(z=0)=U0, u(z=Zn)=Umax.
A continuous graph of u vs z is required.
I thought of using bvp5c in matlab but bvp5c can solve multipoint boundary value problems where a = a0 < a1 < a2 < ... < an = b in the interval [a,b]. The points a1,a2, ... ,an–1 represent interfaces that divide [a,b] into regions. The problem is my constants(a,b in above ode) is also varying in different intervals.

You can do it. If you read the bvp5c docs, you will see that it takes a function handle (odefun) which takes the z, and u arguments. Simply return the correct value for the RHS based on value of the argument z. Note that you have to convert your 2nd order equation to a 1st order one.
du/dz = v
dv/dz = a(z) + b(z)u
You need to return the vector [v, a(z) + b(z)u] from the two arguments z and [u,v] that your odefun will be called with.

Related

Identify powers in an algebraic expression for a Buckingham Pi calculation in MatLab

This is a continuation of an earlier question I asked here.
If I create a symbolic expression in MatLab
syms L M T
F = M*L/T^2
I want to identify the powers of each dimension M, L, or T. In this case, the answer should be
for M, 1
for L, 1
for T, -2
There is a relatively easy way to do this if the expression F were a polynomial in MatLab employing the coeffs function. However, my expression is clearly not a polynomial as far as MatLab is concerned.
In the end, I will be working with at least two parameters so I will put them in a cell array since I anticipate cellfun will be useful.
V = L/T
param = {F,V};
The final output should be a table where the rows correspond to each dimension, L M and T and the columns are for each parameter F and V.
syms L M T
F = M*L/T^2
[C,T] = coeffs(expand(log(F),'IgnoreAnalyticConstraints',true))
[exp(T).' C.']
It returns the table:

how to define an array with fractional index number

Like suppose that I need to create a function named pressure denoted by p (a 2-D matrix) which depends on 2 variables r and z.
u, v, w are linear matrices which also depend on 2 variables r and z.
r and z are linear matrix defined below take i={1,2,3,4,5,6,7,8,9,10}
r(i)=i/10
z(i)=i/10
u(i) = 2*r(i) + 3*z(i)
v(i) = 8*r(i) + 4*z(i)
w(i) = 3*r(i) + 2*z(i)
p = p(r,z) %, which is given as,
p(r(i),z(j)) = 2*v(i) - 4*u(i) + w(j)
Now suppose the value of p at a given location (r,z) say (0.4,0.8) is needed, I want that if I give the input p(0.4,0.8), I get the result.
In your case the easiest way is to convert the fractional numbers to integers by multiplying by 10.
This way the location (r,z) = (0.4, 0.8) will become (4,8).
If you don't want to remember every time to provide the locations multiplied by 10, just create a function that will do it for you, so you can call the function with the fractional location.
If your matrices are linear, you will always find a multiplying factor to get rid of the fractional coordinates.
Not entirely sure what you mean here, but if your matrix is only defined in the indices you give (i.e. you only want to draw values from the fixed set of indices you defined), then this should do it:
% the query indices
r_i = 0.4;
z_i = 0.8;
value = p(r_i*10,z_i*10);
if you want to look at values between the ones you defined, you need to look at interpolation:
% the query indices
r_i = 0.46;
z_i = 0.84;
value = interp2(r,z, p, r_i, z_i);
(I may have gotten r and z in that last function in the wrong order, try it out).

calculating the function limit interatively

How to calculate the limit of a function interatively in Matlab, by closer to the given limit value? The accuracy of closing is 10^(-7)
I suppose that that the taylor formula should be used, but don't know how to apply it there.
The function itself is :
The limit is 88.
In other words, the assignment is to present limits as series with assigned variables, compute them step-by-step, approach the limits' value with 10^(-7) precision.
example code of task:
syms x;
F=log(1+sin(x))/(sin(4*x));
a=limit(F,x,0);
disp(a)
sum=taylor(F,x,0,'Order',7);
disp(sum)
disp (subs(sum,x,0))
Calculating it with MATLAB is quite easy, when using the Symbolic Toolbox. The limit function is what you need:
syms x
limit((x^2-9*x-10)/(sqrt(x+6)-4),x,10)
ans =
88
If you want to calculate it by hand, you don't need Taylor series, you'll need L'Hopital's rule, which states
(image: wikipedia)
This leads to
To calculate this in MATLAB, you could use the diff function to get the derivative and do something like
syms x
f(x) = x^2-9*x-10;
g(x) = sqrt(x+6)-4;
r(x) = diff(f(x)) / diff(g(x));
r(10)
ans =
88
Well, as we are using MATLAB, we can of course just use Taylor series expansion and let MATLAB do the job. MATLAB has a taylor function which creates the Taylor expansion. As the Taylor expansion is exact around the expansion point and the error increases, the further away you are from that point, it is best to use 10 as expansion point.
syms x
t(x) = taylor((x^2-9*x-10)/(sqrt(x+6)-4),x,10,'Order',6);
t(10)
ans =
88
OK, now that I know what you're after, what you could perhaps do is use that taylor command and expand about a point that is quite far off from where you want to compute the limit. If we set the expansion point to be where you want to evaluate the limit, no matter what order polynomial you choose, you will get the correct result which is what I'm assuming you're not after.
Start at an expansion point that is far away, then keep incrementally increasing the order of polynomial of the Taylor series until you get your desired accuracy. You don't want to choose an expansion point that is too far away, or you will never get the right answer. As such, I'm going to expand at x = 7.
Something like this:
true_val = 88; %// Define true value
syms x;
f = (x^2-9*x-10)/(sqrt(x+6)-4); %// Define function
order = 2; %// Start with second order
format long g; %// For better formatting
while true %// Keep iterating...
% // Get Taylor polynomial centered at x = 7 of the current order
pol = taylor(f, x, 7, 'Order', order);
%// Evaluate the Taylor series
val = double(subs(pol, x, 10));
%// Show the results
disp(['Order: ' num2str(order)]);
disp('Result');
disp(val);
%// Check to see if we have at least 1e-7 accuracy then break out if yes
if abs(true_val - val) < 1e-7
break;
end
%// Increment the order by 1
order = order + 1;
end
This is what I get:
Order: 2
Result
86.9892652074553
Order: 3
Result
88.0453290425764
Order: 4
Result
87.9954798755339
Order: 5
Result
88.0005926106152
Order: 6
Result
87.9999105029301
Order: 7
Result
88.0000147335223
Order: 8
Result
87.999997429935
Order: 9
Result
88.0000004672668
Order: 10
Result
87.9999999123696

Graphing Polynomials in MATLAB

I need to create a polynomial of the form:
P(x) = q(1,1) + q(2,2)(x-z(1)) + q(3,3)(x-z(1))(x-z(2)) + --- + q(2n, 2n)(x-z(1))(x-z(2))...(x-z(2n)) NOTE: The indices of the equation have been shifted to accomodate MATLAB.
in MATLAB. Consult this link here specifically slides 15 and 16.
I have the matrix Q filled, so I have the diagonal, and I also have z(1:2n) filled.
I'm having a hard time figuring out a way to create a polynomial that I can graph this polynomial. I've tried to use a for loop to append each term to P(x), but it doesn't operate the way I thought it would.
So far, my code will calculate the coefficients (presented as Q(0,0) -> Q(2n+1, 2n+1) in the problem above) without a problem.
I'm having an issue with the construction of a degree n polynomial of the form described above. Plotting makes more sense now, create a vector x with evaluative values, and then run them through the polynomial "function" and plot the x vector against the resulting vector.
So I just need to create this polynomial.
I would use diag and cumprod to help you accomplish this. First use diag to extract the diagonals of your matrix Q. After, use cumprod to generate a vector of cumulative products.
How cumprod works on a vector is that for each element in the vector, the i'th element collects products from 1 up to the i'th element. As an example, if we had a vector V = [1 2 3 4 5], cumprod(V) would produce [1 2 6 24 120]. The 4th element (as an example) would be 1*2*3*4, representing the products from the 1st to the 4th element.
As such, this is the code that I would do:
qdiag = diag(Q);
xMinusZ = x - z; % Takes z and does x - z for every element in z
cumProdRes = cumprod(xMinusZ);
P = sum(qdiag .* [1;cumProdRes(1:end-1)]);
P should give you P(x) that you desired. Make sure that z is a column vector to make it compatible with the diagonals extracted from Q.
NB: I believe there is a typo in your equation. The last term of your equation (going with your convention) should have (x-z(2n-1)) and not (x-z(2n)). This is because the first term in your equation does not have z.
Here's an example. Let's suppose Q is defined
Q = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16];
The vector z is:
z = [4;3;2;1];
Let's evaluate the function at x = 2
Extracting the diagonals of Q should give us Q = [1;6;11;16]. Subtract x from every element of z should give us:
xMinusZ = [-2;-1;0;1];
Using the equation that you have above, we have:
P = 1 + 6*(-2) + 11*(-2)*(-1) + 16*(-2)*(-1)*(0) = 11
This is what the code should give.
What if we want to do this for more than one value of x?
As you have stated in your post, you want to evaluate this for a series of x values. As such, you need to modify the code so that it looks like this (make sure that x is a column vector):
qdiag = diag(Q);
xMinusZ = repmat(x,1,length(z)) - repmat(z',length(z),1);
cumProdRes = cumprod(xMinusZ,2);
P = sum(repmat(qdiag',length(z),1).*[ones(length(z),1) cumProdRes(:,1:end-1)],2);
P should now give you a vector of outputs, and so if you want to plot this, simply do plot(x,P);

doing optimizations in matlab: figuring out constraint equation

I have N lines that are defined by a y-intercept and an angle, q. The constraint is that all N lines must intersect at one point. The equations I can come up with to eventually get the constraint are these:
Y = tan(q(1))X + y(1)
Y = tan(q(2))X + y(2)
...
I can, by hand, get the constraint if N = 3 or 4 but I am having trouble just getting one constraint if N is greater than 4. If N = 3 or 4, then when I solve the equations above for X, I get 2 equations and then can just set them equal to each other. If N > 4, I get more than 2 equations that equal X and I dont know how to condense them down into one constraint. If I cannot condense them down into one constraint and am able to solve the optimization problem with multiple constraints that are created dynamically (depending on the N that is passed in) that would be fine also.
To better understand what I am doing I will show how I get the constraints for N = 3. I start off with these three equations:
Y = tan(q(1))X + y(1)
Y = tan(q(2))X + y(2)
Y = tan(q(3))X + y(3)
I then set them equal to each other and get these equations:
tan(q(1))X + y(1) = tan(q(2))X + y(2)
tan(q(2))X + y(2) = tan(q(3))X + y(3)
I then solve for X and get this constraint:
(y(2) - y(1)) / (tan(q(1)) - tan(q(2))) = (y(3) - y(2)) / (tan(q(2)) - tan(q(3)))
Notice how I have 2 equations to solve for X. When N > 4 I end up with more than 2. This is OK if I am able to dynamically create the constraints and then call an optimization function in MATLAB that will handle multiple constraints but so far have not found one.
You say the optimization algorithm needs to adjust q such that the "real" problem is minimized while the above equations also hold.
Note that the fifth Euclid axoim ensures that all lines will always intersect with all other lines, unless two qs are equal but the corresponding y0s are not. This last case is so rare (in a floating point context) that I'm going to skip it here, but for added robustness, you should eventually include it.
Now, first, think in terms of matrices. Your constraints can be formulated by the matrix equation:
y = tan(q)*x + y0
where q, y and y0 are [Nx1] matrices, x an unknown scalar. Note that y = c*ones(N,1), e.g., a matrix containing only the same constant. This is actually a non-linear constraint -- that is, it cannot be expressed as
A*q <= b or A*q == b
with A some design matrix and b some solution vector. So, you'll have to write a function defining this non-linear constraint, which you can pass on to an optimizer like fmincon. From the documentation:
x = fmincon(fun,x0,A,b,Aeq,beq,lb,ub,nonlcon) subjects the
minimization to the nonlinear inequalities c(x) or equalities ceq(x)
defined in nonlcon. fmincon optimizes such that c(x) ≤ 0 and ceq(x) =
0. If no bounds exist, set lb = [] and/or ub = [].
Note that you were actually going in the right direction. You can solve for the x-location of the intersection for any pair of lines q(n),y0(n) and q(m),y0(m) with the equation:
x(n,m) = (y0(n)-y0(m)) / (q(m)-q(n))
Your nonlcon function should find x for all possible pairs n,m, and check if they are all equal. You can do this conveniently something like so:
function [c, ceq] = nonlcon(q, y0)
% not using inequalities
c = -1; % NOTE: setting it like this will always satisfy this constraint
% compute tangents
tanq = tan(q);
% compute solutions to x for all pairs
x = bsxfun(#minus, y0, y0.') ./ -bsxfun(#minus, tanq, tanq.');
% equality contraints: they all need to be equal
ceq = diff(x(~isnan(x))); % NOTE: if all(ceq==0), converged.
end
Note that you're not actually solving for q explicitly (or need the y-coordinate of the intersection at all) -- that is all fmincon's job.
You will need to do some experimenting, because sometimes it is sufficient to define
x = x(~isnan(x));
ceq = norm(x-x(1)); % e.g., only 1 equality constraint
which will be faster (less derivatives to compute), but other problems really need
x = x(~isnan(x));
ceq = x-x(1); % e.g., N constraints
or similar tricks. It really depends on the rest of the problem how difficult the optimizer will find each case.