Why is my third MATLAB function outputing only zeros when using ode45? - matlab

I need to model negative, positive and simple regulation of a gene for my systems biology class using MATLAB. The problem is that the functions for negative and simple regulation work but the positive regulation function is only outputting zeros.
My script is as follows:
% Simulation of simple regulation, negative autoregulation and positive
% autoregulation
% Define constants
global a b K n
a = 1;
b = 1;
K = 0.5;
n = 2; % Hill coefficient
% Simulation time
tspan = [0,10];
% Initial condition
X0 = 0;
% Run simulations
[t1,X1] = ode45(#autoregulation_f0,tspan,X0); % Simple regulation
[t2,X2] = ode45(#autoregulation_f1,tspan,X0); % Negative autoregulation
[t3,X3] = ode23(#autoregulation_f2,tspan,X0); % Positive autoregulation
% Plot results
figure;
plot(t1,X1,t2,X2,t3,X3);
legend('simple','negative','Location','southeast');
And my functions are:
function dxdt = autoregulation_f0(t,X)
global a b
dxdt = b - a*X;
end
function dxdt = autoregulation_f1(t,X)
global a b K n
dxdt = b/(1+(X^n)/(K^n)) - a*X;
end
function dxdt = autoregulation_f2(t,X)
global a b K n
dxdt = b*X.^n./(K.^n+X.^n) + a*X;
end
The third function "autoregulation_f2(t,X)" is the one that outputs zeros and therefore when plotting the graph I just get a straight line.
Does anyone know what could be causing this?
Thanks in advance!

It looks to be the correct result for the given function. Your provided dxdt has an X in every term. The initial X0=0 will result in dxdt=0, giving you no change in X. As a result you just end up with a flat line.

Related

Using arrayfun to solve a equation system (with vpasolve) MatLab

I am struggling with solving a problem as efficient as possible.
I have two equations and want to solve them together. Furthermore, I want to solve them for four different cases. I can solve them independently altering the code for each case. I can also solve them by accessing a vector that contains the desired value for one of them (e.g., the first value of A) by using arrayfun. However I can't manage to do all of them together.
My code:
clc
clear all
close all
% scalar parameters
g = 9.807; % Gravity constant, m/s2
d = 1.225; % Density of air, kg/m3
x = 1000; % Height, m
% vector parameters
%t = 0:2:10; % time, seconds
A = [1.2; 1.7; 1.8; 0.3]; % Area, m^2
m = [82; 84; 90; 25]; % Mass, kg
Cd = [0.3; 1.14; 0.29; 0.045]; % Drag coefficient, -
syms v t
eqn1 = 2*m./(A.*Cd*d).* log(abs(cosh(t.*sqrt(A.*Cd*d*g./(2*m))))) == x;
eqn2 = (2*g*m./(d*A.*Cd)).*tanh(t.* sqrt((g*d*Cd.*A)./(2*m))) - v == 0;
eqns=[eqn1 eqn2];
variables = [v t];
result = arrayfun(#vpasolve, eqns, 'uniform', 0)
%disp('v='),disp(eval(v));
%disp('t='),disp(eval(t));
I get a result for t (which is weirdly negative and I don't know why), but I only get a {1×1 struct} for v, which I don't want. I know I can solve this also by using a for loop, but I wanted to make it more efficient.
I tried the code written above and solved it in various forms, however not as desired.
The way you have it implemented you're effectively trying to solve four equations with two unknowns, which isn't supported by vpasolve except in the case of polynomial systems.
It looks like you're trying to solve the same system for four different combinations of values for the parameters A, m, and Cd. The easiest way to do that is to just break this out as a for loop (there is simply no benefit to using arrayfun here – speed or otherwise). You'll need to create some temporary symbolic variable for the parameter (there are a few ways this could be done). Here is example code to do just that:
% scalar parameters
g = 9.807; % Gravity constant, m/s2
d = 1.225; % Density of air, kg/m3
x = 1000; % Height, m
% vector parameters
%t = 0:2:10; % time, seconds
A = [1.2; 1.7; 1.8; 0.3]; % Area, m^2
m = [82; 84; 90; 25]; % Mass, kg
Cd = [0.3; 1.14; 0.29; 0.045]; % Drag coefficient, -
syms v t real
syms A_sym m_sym Cd_sym real % Temporary symbolic variables
eqn1 = 2*m_sym./(A_sym.*Cd_sym*d).* log(abs(cosh(t.*sqrt(A_sym.*Cd_sym*d*g./(2*m_sym))))) == x;
eqn2 = (2*g*m_sym./(d*A_sym.*Cd_sym)).*tanh(t.* sqrt((g*d*Cd_sym.*A_sym)./(2*m_sym))) - v == 0;
eqns=[eqn1 eqn2];
variables = [v t];
n = length(A); % Number of prameter sets
result = cell(n,1); % Preallocate resultant cell array
for i = 1:n
% Substitute in numeric values for i-th parameter set
eqns_sub = subs(eqns,{A_sym,m_sym,Cd_sym},{A(i),m(i),Cd(i)});
% Solve and store in cell array
result{i} = vpasolve(eqns_sub,variables);
end
The output, result, is a 4-by-1 cell array of structs with your two variables, v and t, as VPA-valued fields for each.
You could replace the last few lines with the following if what you want is a numeric array as the output (this assumes that only one solution is found for each parameter set):
n = length(A); % Number of prameter sets
result = zeros(n,length(variables)); % Preallocate resultant array
for i = 1:n
% Substitute in numeric values for i-th parameter set
eqns_sub = subs(eqns,{A_sym,m_sym,Cd_sym},{A(i),m(i),Cd(i)});
% Solve, convert to double precision, and store in array
out = vpasolve(eqns_sub,variables);
result(i,:) = double([out.v out.t]);
end

Interpolation through Newton polynomials

I attempted to solve the problem, and would like a solution to compare to.
The question is:
Write a function that determines the (n-1)th order Newton polynomial and interpolates for a
set of values. The inputs of your function should be: a vector of x values, a corresponding
vector of y values, and a vector of values to interpolate. Your outputs should be the
coefficients of the polynomial (as a vector, [a1 a2 ···an]) and the corresponding function
values for the interpolation. Thoroughly comment your code to show that you
know what you are doing.
My attempt is:
function yint = Newtint(x,y,xx)
n = length(x);
if length(y)~=n, error('x and y must be same length'); end
b = zeros(n,n);
b(:,1) = y(:); % the (:) ensures that y is a column vector.
for j = 2:n
for i = 1:n-j+1
b(i,j) = (b(i+1,j-1)-b(i,j-1))/(x(i+j-1)-x(i));
end
end
xt = 1;
yint = b(1,1);
for j = 1:n-1
xt = xt*(xx-x(j));
yint = yint+b(1,j+1)*xt;
end
% input:
% x = independent variable
% y = dependent variable
% xx = value of independent variable at which
% interpolation is calculated
% output:
% yint = interpolated value of dependent variable
% compute the finite divided differences in the form of a
% difference table

Solve a nonlinear equation using ODE45 function in matlab for different values of initial conditions

I have written a script to compute and solve a simple inverted pendalum system.Now suppose that I want to solve the nonlinear dynamic equation of the system with ODE45 function with different values of initial conditions.How could I use a for loop to solve for state vector of X for different values of initial conditions?I wrote a for loop to do that but I could not get the answer I wanted.Help me please.Here are my function and mfile as follows:
function xDot = of(x,g,L,u)
xDot = zeros(2,1);
xDot(1) = x(2);
xDot(2) = ((g./L)*sin(x(1)))+u;
end
And this is my main code:
clc;
clear;close all;
%% Solve The Nonlinear Equation
L = 1;
g = 9.81;
h = 0.25;
t = [0:h:5];
A = [0 1;(g/L) 0];
B =[0 1]';
Ics = [pi,0;pi/2 0;pi/5 0;0.001 0;pi 0.5;pi/2 0.5;pi/5 0.5;0.001 0.5];
[Poles,~] = eig(A); %Poles Of Closed LOop System
R = 0.01;
Q = eye(2);
K = lqr(A,B,Q,R);
u = #(x)-K*(x);
for i=1:size(Ics,1)
[~,X] = ode45(#(t,x)of(x,g,L,u(x)),t,Ics(i,:));
end
Also note that I want the first column of X vector which is the angular displacements of the pendulum in each iteration because the second column of X vector in ODE45 is always the Derivative of the main state vector.
You can store all the integration outputs for the different initial conditions in a 3D array.
The number of rows of Xout will equal the number of time steps at which you want to evaluate your solution, so numel(t). The number of columns is the number of states, and then the third dimension will be the number of initial conditions you want to test.
Xout = zeros(numel(t), size(Ics, 2), size(Ics, 1)); % initialize the 3D array
for k = 1:size(Ics, 1)
[~, Xout(:, :, k)] = ode45(#(t, x)of(x, g, L, u(x)), t, Ics(k, :));
end

Solving ODEs with Matlab, with varying Parameters

Lets say I have a simple logistic equation
dx/dt = 2ax(1 - x/N)
where N is the carrying capacity, a is some growth rate, and both a and N are parameters I'd like to vary.
So what I want to do is to plot a 3D graph of my fixed point and the two parameters.
I understand how to find a fixed point of a single parameter.
Here is my sample code
function xprime = MyLogisticFunction(t,X) %% The ODE
% Parameters
N = 10 % Carrying Capacity
a = 0.5 % Growth Rate
x1prime = 2*a*X(1)*(1 - X(1)/N );
xprime = [x1prime ]';
end
Next my solver
% Initial Number
x0 = 0.4;
%Time Window
tspan=[0 100];
[t,x]=ode45(#MyLogisticFunction,tspan,x0);
clf
x(end,1) % This gives me the fixed point for the parameters above.
So my real question is, how do I put a for loop across two functions, that allows me to vary a and N, so that I can plot out a 3D graph of a and N and my fixed point x*.
I've tried combining both functions into one .m file but it does not seem to work
You need to pass the parameters to your function:
function xprime = MyLogisticFunction(t,X,a,N) %% The ODE
% Parameters (passed as function arguments)
% N = 10 % Carrying Capacity
% a = 0.5 % Growth Rate
x1prime = 2*a*X(1)*(1 - X(1)/N );
xprime = [x1prime ]';
end
and then when you call the ode solver:
% Initial Number
x0 = 0.4;
%Time Window
tspan=[0 100];
a = 0.1:0.1:1; % or whatever
N = 1:10; % or whatever
x_end = zeros(length(a),length(N));
for ii = 1:length(a)
for jj = 1:length(N)
[t,x]=ode45(#(t,X)MyLogisticFunction(t,X,a(ii),N(jj)),tspan,x0);
x_end(ii,jj) = x(end,1);
end
end

Using MATLAB to write a function that implements Newton's method in two dimensions

I am trying to write a function that implements Newton's method in two dimensions and whilst I have done this, I have to now adjust my script so that the input parameters of my function must be f(x) in a column vector, the Jacobian matrix of f(x), the initial guess x0 and the tolerance where the function f(x) and its Jacobian matrix are in separate .m files.
As an example of a script I wrote that implements Newton's method, I have:
n=0; %initialize iteration counter
eps=1; %initialize error
x=[1;1]; %set starting value
%Computation loop
while eps>1e-10&n<100
g=[x(1)^2+x(2)^3-1;x(1)^4-x(2)^4+x(1)*x(2)]; %g(x)
eps=abs(g(1))+abs(g(2)); %error
Jg=[2*x(1),3*x(2)^2;4*x(1)^3+x(2),-4*x(2)^3+x(1)]; %Jacobian
y=x-Jg\g; %iterate
x=y; %update x
n=n+1; %counter+1
end
n,x,eps %display end values
So with this script, I had implemented the function and the Jacobian matrix into the actual script and I am struggling to work out how I can actually create a script with the input parameters required.
Thanks!
If you don't mind, I'd like to restructure your code so that it is more dynamic and more user friendly to read.
Let's start with some preliminaries. If you want to make your script truly dynamic, then I would recommend that you use the Symbolic Math Toolbox. This way, you can use MATLAB to tackle derivatives of functions for you. You first need to use the syms command, followed by any variable you want. This tells MATLAB that you are now going to treat this variable as "symbolic" (i.e. not a constant). Let's start with some basics:
syms x;
y = 2*x^2 + 6*x + 3;
dy = diff(y); % Derivative with respect to x. Should give 4*x + 6;
out = subs(y, 3); % The subs command will substitute all x's in y with the value 3
% This should give 2*(3^2) + 6*3 + 3 = 39
Because this is 2D, we're going to need 2D functions... so let's define x and y as variables. The way you call the subs command will be slightly different:
syms x, y; % Two variables now
z = 2*x*y^2 + 6*y + x;
dzx = diff(z, 'x'); % Differentiate with respect to x - Should give 2*y^2 + 1
dzy = diff(z, 'y'); % Differentiate with respect to y - Should give 4*x*y + 6
out = subs(z, {x, y}, [2, 3]); % For z, with variables x,y, substitute x = 2, y = 3
% Should give 56
One more thing... we can place equations into vectors or matrices and use subs to simultaneously substitute all values of x and y into each equation.
syms x, y;
z1 = 3*x + 6*y + 3;
z2 = 3*y + 4*y + 4;
f = [z1; z2];
out = subs(f, {x,y}, [2, 3]); % Produces a 2 x 1 vector with [27; 25]
We can do the same thing for matrices, but for brevity I won't show you how to do that. I will defer to the code and you can see it then.
Now that we have that established, let's tackle your code one piece at a time to truly make this dynamic. Your function requires the initial guess x0, the function f(x) as a column vector, the Jacobian matrix as a 2 x 2 matrix and the tolerance tol.
Before you run your script, you will need to generate your parameters:
syms x y; % Make x,y symbolic
f1 = x^2 + y^3 - 1; % Make your two equations (from your example)
f2 = x^4 - y^4 + x*y;
f = [f1; f2]; % f(x) vector
% Jacobian matrix
J = [diff(f1, 'x') diff(f1, 'y'); diff(f2, 'x') diff(f2, 'y')];
% Initial vector
x0 = [1; 1];
% Tolerance:
tol = 1e-10;
Now, make your script into a function:
% To run in MATLAB, do:
% [n, xout, tol] = Jacobian2D(f, J, x0, tol);
% disp('n = '); disp(n); disp('x = '); disp(xout); disp('tol = '); disp(tol);
function [n, xout, tol] = Jacobian2D(f, J, x0, tol)
% Just to be sure...
syms x, y;
% Initialize error
ep = 1; % Note: eps is a reserved keyword in MATLAB
% Initialize counter
n = 0;
% For the beginning of the loop
% Must transpose into a row vector as this is required by subs
xout = x0';
% Computation loop
while ep > tol && n < 100
g = subs(f, {x,y}, xout); %g(x)
ep = abs(g(1)) + abs(g(2)); %error
Jg = subs(J, {x,y}, xout); %Jacobian
yout = xout - Jg\g; %iterate
xout = yout; %update x
n = n + 1; %counter+1
end
% Transpose and convert back to number representation
xout = double(xout');
I should probably tell you that when you're doing computation using the Symbolic Math Toolbox, the data type of the numbers as you're calculating them are a sym object. You probably want to convert these back into real numbers and so you can use double to cast them back. However, if you leave them in the sym format, it displays your numbers as neat fractions if that's what you're looking for. Cast to double if you want the decimal point representation.
Now when you run this function, it should give you what you're looking for. I have not tested this code, but I'm pretty sure this will work.
Happy to answer any more questions you may have. Hope this helps.
Cheers!