Matlab: Using interp2 in ode45 - matlab

I have a 2-dimensional matrix with discrete values and I want to use the ode45 command.
To do this I used interp2 to create a function ode45 can use.
The problem is, it looks like ode45 is moving out of my defined area and so interp2 returns NaN-values. To get rid of the NaN I used an extrapolation value but now it seems that ode45 integrates from my initial values to this extrapolation value, disregarding any of my given values in the matrix.
Here is a little example with a 2x2 matrix:
clear all;
close all;
clc;
A = rand(2, 2); % the matrix with my values
x = 1:2;
y = x;
[X, Y] = meshgrid(x, y); % grid on which my values are defined
xi = 1:0.5:2;
yi = xi;
[Xi, Yi] = meshgrid(xi, yi); % interpolation grid
tspan = 0:0.2:1;
B = #(xq,yq)interp2(X, Y, A, xq, yq, 'linear', 10); % interpolation function with extrapval of 10
[T,C] = ode45(#(Xi,Yi)B(Xi,Yi), tspan, [Xi,Yi]); % ode45 function using interp-function and intital values [Xi,Yi]
What am I doing wrong?
Thanks for any help in advance!

I don't think this will work as you have set it up. Your ODE function B should take inputs of time, and a single input (column) vector of state variables and return a column vector of rates of change for the state variables. Please look at the help documentation for ode45.
If your state variables are coordinate pairs (x,y), you need to return dx/dt and dy/dt for each pair. I'm not sure how this could come from interpolating on a single array. I think you need something like the following:
clear
%// Define the right hand side of your ODE such that
%// dx/dt = Ax(x,y)
%// dy/dt = Ay(x,y)
%// For demonstration I'm using a circular velocity field.
xref = linspace(-pi,pi);
yref = linspace(-pi,pi);
[xref yref] = meshgrid(xref,yref);
r=sqrt(xref.^2+yref.^2);
Ax = [-yref./r];
Ay = [xref./r];
%// Initial states:
xi = 1:0.05:2;
yi = xi;
[Xi, Yi] = meshgrid(xi, yi); % interpolation grid
%// state array = [x1; y1; x2; y2; ... ]
states = [Xi(:)'; Yi(:)'];
states = states(:);
B = #(t,states) reshape([ interp2(xref,yref,Ax,states(1:2:end),states(2:2:end)) ...
interp2(xref,yref,Ay,states(1:2:end),states(2:2:end))]',size(states));
tspan=0:.02:10;
[T,C] = ode45(B, tspan, states);
for i=1:size(C,1)
figure(1)
clf
plot(C(i,1:2:end),C(i,2:2:end),'k.')
axis(pi*[-1 1 -1 1])
drawnow
end
Obviously this code relies heavily on managing array shapes to maintain the correct ordering for x, y, dx/dt, and dy/dt. There may be a simpler way to write it.
EDIT
The key here is to clearly define a state vector and define your ODE function to match that state vector. The state vector must be a column vector and your ODE function must return a column vector. In the code above I have chosen to represent the state of the system as a vector formated as states(:,1) = [x1 y1 x2 y2 x3 y3 ... ]. That means your ODE must return a column vector of the form
[ d/dt(x1) ]
[ d/dt(y1) ]
[ d/dt(x2) ]
[ d/dt(y2) ]
[ d/dt(x2) ]
[ d/dt(y2) ]
[ ... ]
[ ... ]
You will also require 2 interpolations, 1 for the x components and 1 for the y, to get the rates of change based on Ax and Ay. The way I chose to do this was with the line
B = #(t,states) reshape([ interp2(xref,yref,Ax,states(1:2:end),states(2:2:end)) ...
interp2(xref,yref,Ay,states(1:2:end),states(2:2:end))]',size(states));
This line is a bit complex and difficult to understand because it is written as an anonymous function. If you define a stand-alone function for this it will be much more clear and could be written as
function ODEvals = B(t,states,xref,yref,Ax,Ay)
x(:,1) = states(1:2:end); %// extract x values from states as a column vector
y(:,1) = states(2:2:end); %// extract y values
dxdt(:,1) = interp2(xref,yref,Ax,x,y); %// interpolate Ax
dydt(:,1) = interp2(xref,yref,Ay,x,y); %// interpolate Ay
%// concatenate the results, dxdt and dydt are column vectors
%// 1) put the as column 1 and 2
%// 2) take the transpose so they become rows one and two:
%// [d/dt(x1) d/dt(x2) ... ]
%// [d/dt(y1) d/dt(y2) ... ]
%// 3) reshape into a single column, the ordering will be:
%// [ d/dt(x1) ]
%// [ d/dt(y1) ]
%// [ d/dt(x2) ]
%// [ d/dt(y2) ]
%// [ d/dt(x2) ]
%// [ d/dt(y2) ]
%// [ ... ]
%// [ ... ]
ODEvals = reshape([dxdt dydt]',[],1);
One last note:
To use ode45, your ODE function must take inputs of a time (t above) and a state vector, even if you don't use the time. Additional arguments are optional, see the documentation on ode45 for more details.

Related

Constrained linear least squares not fitting data

I am trying to fit a 3D surface polynomial of n-degrees to some data points in 3D space. My system requires the surface to be monotonically increasing in the area of interest, that is the partial derivatives must be non-negative. This can be achieved using Matlab's built in lsqlin function.
So here's what I've done to try and achieve this:
I have a function that takes in four parameters;
x1 and x2 are my explanatory variables and y is my dependent variable. Finally, I can specify order of polynomial fit. First I build the design matrix A using data from x1 and x2 and the degree of fit I want. Next I build the matrix D that is my container for the partial derivatives of my datapoints. NOTE: the matrix D is double the length of matrix A since all datapoints must be differentiated with respect to both x1 and x2. I specify that Dx >= 0 by setting b to be zeroes.
Finally, I call lsqlin. I use "-D" since Matlab defines the function as Dx <= b.
function w_mono = monotone_surface_fit(x1, x2, y, order_fit)
% Initialize design matrix
A = zeros(length(x1), 2*order_fit+2);
% Adjusting for bias term
A(:,1) = ones(length(x1),1);
% Building design matrix
for i = 2:order_fit+1
A(:,(i-1)*2:(i-1)*2+1) = [x1.^(i-1), x2.^(i-1)];
end
% Initialize matrix containing derivative constraint.
% NOTE: Partial derivatives must be non-negative
D = zeros(2*length(y), 2*order_fit+1);
% Filling matrix that holds constraints for partial derivatives
% NOTE: Matrix D will be double length of A since all data points will have a partial derivative constraint in both x1 and x2 directions.
for i = 2:order_fit+1
D(:,(i-1)*2:(i-1)*2+1) = [(i-1)*x1.^(i-2), zeros(length(x2),1); ...
zeros(length(x1),1), (i-1)*x2.^(i-2)];
end
% Limit of derivatives
b = zeros(2*length(y), 1);
% Constrained LSQ fit
options = optimoptions('lsqlin','Algorithm','interior-point');
% Final weights of polynomial
w_mono = lsqlin(A,y,-D,b,[],[],[],[],[], options);
end
So now I get some weights out, but unfortunately they do not at all capture the structure of the data. I've attached an image so you can just how bad it looks. .
I'll give you my plotting script with some dummy data, so you can try it.
%% Plot different order polynomials to data with constraints
x1 = [-5;12;4;9;18;-1;-8;13;0;7;-5;-8;-6;14;-1;1;9;14;12;1;-5;9;-10;-2;9;7;-1;19;-7;12;-6;3;14;0;-8;6;-2;-7;10;4;-5;-7;-4;-6;-1;18;5;-3;3;10];
x2 = [81.25;61;73;61.75;54.5;72.25;80;56.75;78;64.25;85.25;86;80.5;61.5;79.25;76.75;60.75;54.5;62;75.75;80.25;67.75;86.5;81.5;62.75;66.25;78.25;49.25;82.75;56;84.5;71.25;58.5;77;82;70.5;81.5;80.75;64.5;68;78.25;79.75;81;82.5;79.25;49.5;64.75;77.75;70.25;64.5];
y = [-6.52857142857143;-1.04736842105263;-5.18750000000000;-3.33157894736842;-0.117894736842105;-3.58571428571429;-5.61428571428572;0;-4.47142857142857;-1.75438596491228;-7.30555555555556;-8.82222222222222;-5.50000000000000;-2.95438596491228;-5.78571428571429;-5.15714285714286;-1.22631578947368;-0.340350877192983;-0.142105263157895;-2.98571428571429;-4.35714285714286;-0.963157894736842;-9.06666666666667;-4.27142857142857;-3.43684210526316;-3.97894736842105;-6.61428571428572;0;-4.98571428571429;-0.573684210526316;-8.22500000000000;-3.01428571428571;-0.691228070175439;-6.30000000000000;-6.95714285714286;-2.57232142857143;-5.27142857142857;-7.64285714285714;-2.54035087719298;-3.45438596491228;-5.01428571428571;-7.47142857142857;-5.38571428571429;-4.84285714285714;-6.78571428571429;0;-0.973684210526316;-4.72857142857143;-2.84285714285714;-2.54035087719298];
% Used to plot the surface in all points in the grid
X1 = meshgrid(-10:1:20);
X2 = flipud(meshgrid(30:2:90).');
figure;
for i = 1:4
w_mono = monotone_surface_fit(x1, x2, y, i);
y_nr = w_mono(1)*ones(size(X1)) + w_mono(2)*ones(size(X2));
for j = 1:i
y_nr = w_mono(j*2)*X1.^j + w_mono(j*2+1)*X2.^j;
end
subplot(2,2,i);
scatter3(x1, x2, y); hold on;
axis tight;
mesh(X1, X2, y_nr);
set(gca, 'ZDir','reverse');
xlabel('x1'); ylabel('x2');
zlabel('y');
% zlim([-10 0])
end
I think it may have something to do with the fact that I haven't specified anything about the region of interest, but really I don't know. Thanks in advance for any help.
Alright I figured it out.
The main problem was simply an error in the plotting script. The value of y_nr should be updated and not overwritten in the loop.
Also I figured out that the second derivative should be monotonically decreasing. Here's the updated code if anybody is interested.
%% Plot different order polynomials to data with constraints
x1 = [-5;12;4;9;18;-1;-8;13;0;7;-5;-8;-6;14;-1;1;9;14;12;1;-5;9;-10;-2;9;7;-1;19;-7;12;-6;3;14;0;-8;6;-2;-7;10;4;-5;-7;-4;-6;-1;18;5;-3;3;10];
x2 = [81.25;61;73;61.75;54.5;72.25;80;56.75;78;64.25;85.25;86;80.5;61.5;79.25;76.75;60.75;54.5;62;75.75;80.25;67.75;86.5;81.5;62.75;66.25;78.25;49.25;82.75;56;84.5;71.25;58.5;77;82;70.5;81.5;80.75;64.5;68;78.25;79.75;81;82.5;79.25;49.5;64.75;77.75;70.25;64.5];
y = [-6.52857142857143;-1.04736842105263;-5.18750000000000;-3.33157894736842;-0.117894736842105;-3.58571428571429;-5.61428571428572;0;-4.47142857142857;-1.75438596491228;-7.30555555555556;-8.82222222222222;-5.50000000000000;-2.95438596491228;-5.78571428571429;-5.15714285714286;-1.22631578947368;-0.340350877192983;-0.142105263157895;-2.98571428571429;-4.35714285714286;-0.963157894736842;-9.06666666666667;-4.27142857142857;-3.43684210526316;-3.97894736842105;-6.61428571428572;0;-4.98571428571429;-0.573684210526316;-8.22500000000000;-3.01428571428571;-0.691228070175439;-6.30000000000000;-6.95714285714286;-2.57232142857143;-5.27142857142857;-7.64285714285714;-2.54035087719298;-3.45438596491228;-5.01428571428571;-7.47142857142857;-5.38571428571429;-4.84285714285714;-6.78571428571429;0;-0.973684210526316;-4.72857142857143;-2.84285714285714;-2.54035087719298];
% Used to plot the surface in all points in the grid
X1 = meshgrid(-10:1:20);
X2 = flipud(meshgrid(30:2:90).');
figure;
for i = 1:4
w_mono = monotone_surface_fit(x1, x2, y, i);
% NOTE: Should only have 1 bias term
y_nr = w_mono(1)*ones(size(X1));
for j = 1:i
y_nr = y_nr + w_mono(j*2)*X1.^j + w_mono(j*2+1)*X2.^j;
end
subplot(2,2,i);
scatter3(x1, x2, y); hold on;
axis tight;
mesh(X1, X2, y_nr);
set(gca, 'ZDir','reverse');
xlabel('x1'); ylabel('x2');
zlabel('y');
% zlim([-10 0])
end
And here's the updated function
function [w_mono, w] = monotone_surface_fit(x1, x2, y, order_fit)
% Initialize design matrix
A = zeros(length(x1), 2*order_fit+1);
% Adjusting for bias term
A(:,1) = ones(length(x1),1);
% Building design matrix
for i = 2:order_fit+1
A(:,(i-1)*2:(i-1)*2+1) = [x1.^(i-1), x2.^(i-1)];
end
% Initialize matrix containing derivative constraint.
% NOTE: Partial derivatives must be non-negative
D = zeros(2*length(y), 2*order_fit+1);
for i = 2:order_fit+1
D(:,(i-1)*2:(i-1)*2+1) = [(i-1)*x1.^(i-2), zeros(length(x2),1); ...
zeros(length(x1),1), -(i-1)*x2.^(i-2)];
end
% Limit of derivatives
b = zeros(2*length(y), 1);
% Constrained LSQ fit
options = optimoptions('lsqlin','Algorithm','active-set');
w_mono = lsqlin(A,y,-D,b,[],[],[],[],[], options);
w = lsqlin(A,y);
end
Finally a plot of the fitting (Have used a new simulation, but fit also works on given dummy data).

A density plot using 2 coordinates columns and a weight column

I have a matrix with 3 columns. The first two columns are coordinates and the third is weight or intensity.
newmat = [ 27.37 -45.69 14.47
27.37 -45.68 18.58
27.37 -45.67 29.05
27.37 -45.66 51.7
... ... ... ]
I have already created a scatter plot:
However, I'd like to have something like a density plot (as the second plot here). I have tried to use hist3 function as in here, but I didn't figure out how to take into account the third column - weight.
You could create a matrix from the data in newmat (using the functions sortrows, unique, and accumarray) and plot it as an image:
newmat = sortrows(newmat, [1 2]); % Sort the first two columns in ascending order
[x, ~, newmat(:, 1)] = unique(newmat(:, 1)); % Make numeric indices for column 1
[y, ~, newmat(:, 2)] = unique(newmat(:, 2)); % Make numeric indices for column 2
M = accumarray(newmat(:, 1:2), newmat(:, 3)).'; % Build the matrix
imagesc(x, y, M);
Here's some sample data similar to your format:
[X, Y] = meshgrid(0:0.1:2, 3:0.1:5);
Z = peaks(21);
newmat = [X(:) Y(:) Z(:)];
And here's the plot the above code produces from that data:

How to plot histogram of columns of a matrix in MATLAB?

I have to plot a histogram of each column of MatrixE1. How can I go about doing this? This is what I have written so far.
% Create a random 5 x 3 matrix filled with random values between 0 and 10
a0 = 0;
b0 = 10;
r = a0 + (b0-a0).*rand(1,1);
matrixA = [randi([0 10]) randi([0 10]) randi([0 10]); randi([0 10]) randi([0 10]) randi([0 10]); randi([0 10]) randi([0 10]) randi([0 10]); randi([0 10]) randi([0 10]) randi([0 10]); randi([0 10]) randi([0 10]) randi([0 10])]
% Create identity matrix 3 x 3
matrixB = eye(3,3)
% Create new submatrix of A with the last 3 rows
matrixC = matrixA(end-2 : end, :)
% Pair wise multiplication of C and B
matrixD = times(matrixC, matrixB)
% Concatenate Matrix A and D
matrixE1 = [matrixA ; matrixD]
% Plot histogram of columns.
matrixColumn1 = matrixE1(1 : end , end-2: end-2);
matrixFColumn2 = matrixE1(1 : end, end -1 : end-1);
matrixFColumn3 = matrixE1(1 : end, end : end);
You can access each of your coloumns in matrixE1 like this:
firstCol = matrixE1(:,1);
secondCol = matrixE1(:,2);
thirdCol = matrixE1(:,3);
...and then you can simply use comand hist() to plot histograms. You would plot histogram of first coloumn in matrixE1 as:
hist(firstCol);
And if I understand your second question:
''What would I do? hist(??). How can I get one histogram of all the columns of matrixE1? Should I do hist(matrixE1)?''
You can simply use command hold on after ploting histogram of one coloumn. Then plot another histogram on the same plot. For example if you want to plot histogram of first and second coloumn from matrixE1 to the same plot, you would type:
hist(firstCol);
hold on;
hist(secondCol);
>> v1=randn(1000,1); % zero mean, unity stdev
>> v2=randn(1000,1)+1; % mean at one, unity stdev
>> V=[v1 v2]; % 1000 x 2 matrix
>> hist(V,100); % 100 bins
>> legend('v1', 'v2');
There is another, simpler but computationally more expensive way:
plotmatrix(A)
For any matrix A this will produce a m-by-n plot of scatterplots of all pairwise combinations of your input matrix (do not do this for large matrices, larger than you could fit on your screen).
What you gain on top are histograms along the main diagonal of the plotmatrix.
Adding this answer due to other answers (1, 2) using outdated function hist.
MATLAB recommends avoiding the use of hist and now favors histogram (source). The changeover is straightforward.
% MATLAB R2019a
% Sample Data
NumPoints = 2000;
a1 = 10*rand(NumPoints,1);
a2 = wblrnd(3,7,NumPoints,1);
a3 = 7 + 0.75*randn(NumPoints,1);
A = [a1 a2 a3]; % Data Matrix
% Implement Sturges Rule for n<=500, Scott's Rule for n>500
nbinsh =#(n) ceil((1 + 3.3*log10(n))*(n<=500) + ((5/3)*(n^(1/3)))*(n>500));
NumBins = nbinsh(NumPoints);
numCols = size(A,2);
% Plot
figure, hold on
for k = 1:numCols
histogram(A(:,k),'NumBins',NumBins,'DisplayName',['Col ' num2str(k)]);
end
legend('show')
You can adjust from frequency (counts) to probability or probability density function depending on the application needs with the Normalization property (see documentation here).

Plotting response of a system with polynomial matrices

How can I plot the time response of a system when the system, input, output matrices are polynomials? For example
A(x) = [0.59*x 1.67*x; 0.1 0.2]
B(x) = [2.3*x; 0.3]
C = [1 0]
Operating region of x = [-2, 2]
Initial condition x(0) = [2 0]
If the matrices were constant, I could use ss and lsim to plot it. But, how do I do it in this case? I am new to Matlab and control systems.
Using your example, I will run you through the basic idea of general ODE simulation in MatLab (which is very similar across programming languages).
(First though, I am assuming that the x you have written in your A and B matrices is actually x1 since you did not specify. I am also assuming from context that your state vector is [x1 x2]).
Create a function that takes in the
current time, t_now
current state vector, x_now
full input array, u
full time array, t
and uses them to compute the state derivative (xdot). The full time array (t) will only be needed for indexing the control input (u), as you will see. Basically, it will be a coded function for
xdot = f(t, x, u)
which is the general form of an ODE.
function xdot = myODE(t_now, x_now, u, t)
A = [ 0.59*x_now(1), 1.67*x_now(1);
0.1, 0.2 ] ;
B = [ 2.3*x_now(1);
0.3 ] ;
u_now = interp1(t, u, t_now) ; % get u(t=t_now)
xdot = A*x_now + B*u_now ;
end
Next, create a script that runs the simulation using an ODE solver like MatLab's ode45. If you want to know how these solvers work, read up on numerical integration. MatLab's ode45 uses a Runge-Kutta method.
%// time range over which to compute simulation
t = [0 : 0.01 : 5] ;
%// define the input signal
%// why not make it zero to look at the natural response
u = zeros(1, length(t)) ;
%// initial condition
x0 = [2, -5] ;
%// call ode45
%// first argument: anonymous call to myODE that tells it which inputs to use
%// second argument: the time range for the simulation
%// third argument: the initial condition
%// first output: the sim time, may be more detailed than the original t
%// second output: the full output including all states
[t_out, response] = ode45(#(t_now, x_now) myODE(t_now, x_now, u, t), t, x0) ;
%// The response contains two column vectors: one for x1 and one for x2 at
%// every time in t. You can extract "the true output" which based on
%// your C matrix is x1.
y = response(:,1) ;
%// Plot results
plot(t, u, 'r--', t_out, y, 'k') ;
grid on ;
legend('input', 'output')
xlabel('time')
ylabel('value')
Suppose you don't have u as a predefined input signal, but rather as a function of the current state. Then simply modify the computation of u_now in the myODE function. In the simplest case, u is not a function of time at all, in which case you don't even need to pass u or the full time array into myODE at all! For example, if
u := -k*x1
then your ODE function can be
function xdot = myODE(t_now, x_now)
A = [ 0.59*x_now(1), 1.67*x_now(1);
0.1, 0.2 ] ;
B = [ 2.3*x_now(1);
0.3 ] ;
k = 5 ;
u_now = -k*x_now(1) ;
xdot = A*x_now + B*u_now ;
end
with the call to ode45 being
[t_out, response] = ode45(myODE(t_now, x_now), t, x0) ;
and no need to define u in the script.
Hope that helps!

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!