Vertcat error using ODE45 - matlab

I am trying to numerically simulate a system using ODE45. I cannot seem to figure out why i'm getting the following error:
Error using vertcat
Dimensions of matrices being concatenated are not consistent.
[t,x] = ode45(#NL_hw3c, [0,20], [1, 2, 3]);
function sys = NL_hw3c(t,x)
sys = [x(2)+ x(1)^2;
x(3)+log10(x(2)^2 + 1);
-3*x(1)-5*x(2)-3*x(3)+4*cos(t)-5*x(1)^2 -3*log10(x(2)^2 + 1) -6*x(1)*x(2) -6*x(1)^3 -(2*x(2)*(x(3)+ log10(x(2)^2 + 1)))/((x(2)^2 + 1)*log(10)) -2*x(1)*x(3) -2*x(1)*log10(x(2)^2 + 1) -2*x(2)^2 -8*x(1)^2*x(2) -6*x(1)^4];
end
Googled and couldn't find a similar solution. Any help would be appreciated.
Thanks

I had to separate each of the variables in your array for it to work:
function s = NL_hw3c(t,x)
s1 = x(2)+ x(1)^2;
s2 = x(3)+log10(x(2)^2 + 1);
s3 = -3*x(1)-5*x(2)-3*x(3)+4*cos(t)-5*x(1)^2 -3*log10(x(2)^2 + 1) -6*x(1)*x(2) -6*x(1)^3 -(2*x(2)*(x(3)+ log10(x(2)^2 + 1)))/((x(2)^2 + 1)*log(10)) -2*x(1)*x(3) -2*x(1)*log10(x(2)^2 + 1) -2*x(2)^2 -8*x(1)^2*x(2) -6*x(1)^4;
s = [s1;s2;s3];
end
I got the following output:
t =
0
0.0018
0.0037
0.0055
0.0074
0.0166
...
...
19.7647
19.8431
19.9216
20.0000
x =
1.0000 2.0000 3.0000
1.0055 2.0067 2.8493
1.0111 2.0131 2.6987
1.0167 2.0192 2.5481
1.0224 2.0251 2.3975
...
...
0.7926 -0.0187 -1.7587
0.8380 -0.1567 -1.7624
0.8781 -0.2928 -1.7534
0.9129 -0.4253 -1.7299
The reason why your function didn't work was because in the last value of your array, the spaces between each part of the expression are interpreted as going into a separate column. Essentially, the first two rows of your matrix consist of 1 element and if you use the last expression exactly as it is, you would be trying to place 9 elements in the last row. I'm assuming you want a 3 x 1 matrix and the last element would thus violate the size of this matrix that you want to create and this is why it's giving you an error.
I'm assuming you want the last value as an entire expression, so to do this you will need to place this as a separate expression then place it into your array.
To make the code more readable, I've placed all of the entries as separate variables before making the array.

Related

mle memory error with custom negative log-likelihood function

I am trying to use 'mle' with a custom negative log-likelihood function, but I get the following error:
Requested 1200000x1200000 (10728.8GB) array exceeds maximum array size preference (15.6GB). This might cause MATLAB to become unresponsive.
The data I am using is a 1x1200000 binary array (which I had to convert to double), and the function has 10 arguments: one for the data, 3 known paramenters, and 6 to be optimized. I tried setting 'OptimFun' to both 'fminsearch' and 'fmincon'. Also, optimizing the parameters using 'fminsearch' and 'fminunc' instead of 'mle' works fine.
The problem happens in the 'checkFunErrs' functions, inside the 'mlecustom.m' file (call at line 173, actuall error at line 705).
With 'fminunc' I could calculate the optimal parameters, but it does not give me confidence intervals. Is there a way to circumvent this? Or am I doing something wrong?
Thanks for the help.
T_1 = 50000;
T_2 = 100000;
npast = 10000;
start = [0 0 0 0 0 0];
func = #(x, data, cens, freq)loglike(data, [x(1) x(2) x(3) x(4) x(5) x(6)],...
T_1, T_2, npast);
params = mle(data, 'nloglf', func, 'Start', start, 'OptimFun', 'fmincon');
% Computes the negative log likehood
function out = loglike(data, params, T_1, T_2, npast)
size = length(data);
if npast == 0
past = 0;
else
past = zeros(1, size);
past(npast+1:end) = movmean(data(npast:end-1),[npast-1, 0]); % Average number of events in the previous n years
end
lambda = params(1) + ...
(params(2)*cos(2*pi*(1:size)/T_1)) + ...
(params(3)*sin(2*pi*(1:size)/T_1)) + ...
(params(4)*cos(2*pi*(1:size)/T_2)) + ...
(params(5)*sin(2*pi*(1:size)/T_2)) + ...
params(6)*past;
out = sum(log(1+exp(lambda))-data.*lambda);
end
Your issue is line 228 (as of MATLAB R2017b) of the in-built mle function, which happens just before the custom function is called:
data = data(:);
The input variable data is converted to a column array without warning. This is typically done to ensure that all further calculations are robust to the orientation of the input vector.
However, this is causing you issues, because your custom function assumes data is a row vector, specifically this line:
out = sum(log(1+exp(lambda))-data.*lambda);
Due to implicit expansion, when the row vector lambda and the column vector data interact, you get a huge square matrix per your error message.
Adding these two lines to make it explicit that both are column vectors resolves the issue, avoids implicit expansion, and applies the calculation element-wise as you intended.
lambda = lambda(:);
data = data(:);
So your function becomes
function out = loglike(data, params, T_1, T_2, npast)
N = length(data);
if npast == 0
past = 0;
else
past = zeros(1,N);
past(npast+1:end) = movmean(data(npast:end-1),[npast-1, 0]); % Average number of events in the previous n years
end
lambda = params(1) + ...
(params(2)*cos(2*pi*(1:N)/T_1)) + ...
(params(3)*sin(2*pi*(1:N)/T_1)) + ...
(params(4)*cos(2*pi*(1:N)/T_2)) + ...
(params(5)*sin(2*pi*(1:N)/T_2)) + ...
params(6)*past;
lambda = lambda(:);
data = data(:);
out = sum(log(1+exp(lambda))-data.*lambda);
end
An alternative would be to re-write your function so that it uses column vectors, but you create new row vectors with the (1:N) steps and the concatenation within the movmean. The suggested approach is arguably "lazier", but also robust to row or column inputs.
Note also I've changed your variable name from size to N, since size is an in-built function which you should avoid shadowing.

Euler's method in MATLAB: code doesn't work

For my computing course, I am given the following function:
y'(x) = -8y(x) + 0.5x + 1/16 and an initial value of y(0)=2.
Now, I am asked to solve this equation by using Euler's method, in MATLAB.
My code should give an output of 2 arrays: xar and yar, in which I see the x-values vs. the y-values, however, if I run my code, it says: "undefined variable x". Here's my code:
function [xar,yar] = Euler(a,b,ybouco,N)
% a is the lower limit
% b is the upper limit
% ybouco is the initial value
% N is the number of intervals
a=0;
b=3;
ybouco=2;
N=10;
h=(b-a)/N;
T=a:h:b;
y(1)=ybouco;
f = #(x) -8*y(x) + 0.5x + (1/16);
y(x) = 2*exp(-8*x)+(1/16)*x;
for i = 1:N
y (i+1) = y(i)+h*f(T(i));
end
end
Can someone explain what is wrong with my code??
First of all, note that assigning argument parameters in the function block is wrong! (i.e. a,b,ybouco and N) should be passed through argument by calling the function. There is no use in writing arguments to be assigned by user beside assigning them in the script manually.
One way is to call the function and assign the value in the command window like below:
[x,y]=Euler(0,3,2,10)
where a=0, b=3, ybouco=2 and N=10 was passed to the function as an input and x and y returned by the function as output.
Plus, when you are solving an ODE numerically it means you do not know y analytically.
So you should omit the assigning part of the code and do a little change like below:
function [xar,yar] = Euler(a,b,ybouco,N)
h=(b-a)/N;
T=a:h:b;
y(1)=ybouco;
for i = 1:N
f(i) = -8*y(i) + 0.5*T(i) + (1/16);
y(i+1) = y(i)+h*f(i);
end
xar=T;
yar=y;
end
Then by calling the function in the command window, you will get the following results:
x =
Columns 1 through 8
0 0.3000 0.6000 0.9000 1.2000 1.5000 1.8000 2.1000
Columns 9 through 11
2.4000 2.7000 3.0000
y =
Columns 1 through 8
2.0000 -2.7813 3.9575 -5.4317 7.7582 -10.6627 15.1716 -20.9515
Columns 9 through 11
29.6658 -41.1533 58.0384
You can also plot the result and get the following graph:
If you increase N from 10 to 100 you will have more accurate results and a smooth graph like below:
The error message is because you have an assignment
y(x) = 2*exp(-8*x)+(1/16)*x;
where x is not defined. The x in y(x) indexes into the array y.
Maybe you intended to write
y = #(x) 2*exp(-8*x)+(1/16)*x;
to define an anonymous function. But that would clash with the array y you have already defined. Maybe just delete this line?
Also,
h=(b-a)/N;
T=a:h:b;
can be better written as
T = linspace(a,b,N);

Matlab AR digital fiter computation w/o loops

I'm given the a(k) matrix and e(n) and I need to compute y(n) from the following eq:
y(n) = sum(k = 1 to 10 )( a(k)*y(n-k) ) + e(n).
I have the a matrix(filter coefficients) and the e matrix (the residual), therefore there is only 1 unknown: y, which is built by the previous 10 samples of y.
An example to this equation:
say e(0) (my first residual sample) = 3
and y(-10) to y(-1) = 0
then y(0), my first sample in the signal y, would just be e(0) = 3:
y(0) = a(1)*y(-1) + a(2)*y(-2) + .... + a(10)*y(-10) + e(0) = e(0) = 3
and if e(1) = 4, and a(1) = 5, then
y(1) = a(1)*y(0) + a(2)*y(-1) + a(3)&y(-2) + ... + a(10)*y(-9) + e(1) = 19
The problem is
I don't know how to do this without loops because, say, y(n) needs y(n-1), so I need to immediately append y(n-1) into my matrix in order to get y(n).
If n (the number of samples) = say, 10,000,000, then using a loop is not ideal.
What I've done so far
I have not implemented anything. The only thing I've done for this particular problem is research on what kind of Matlab functions I could use.
What I need
A Matlab function that, given an equation and or input matrix, computes the next y(n) and automatically appends that to the input matrix, and then computes the next y(n+1), and automatically append that to the input matrix and so on.
If there is anything regarding my approach
That seems like it's on the wrong track, or my question isn't clear enough, of if there is no such matlab function that exists, then I apologize in advance. Thank you for your time.

Calculate roots of characteristic equation of symbolic matrix

I have 3 data matrices A,B,C (all 3x3), with which I use the following code to calculate roots of D(p)X = 0
syms p
D = A + B*p + C*(p^2)
solP = double(solve(det(D)))
From this, I get 6 values for solP. But when I try substituting it back into the symbolic matrix D, as follows, I get non-zero values of det(D) sometimes
for i = 1:6
p = solP(i)
det(double(subs(D)) % Should be zero always as we are substituting roots
end
Please help me understand this behaviour.
EDIT ::
Example :
A =
1.0e+11 *
4.8976 7.0936 6.7970
4.4559 7.5469 6.5510
6.4631 2.7603 1.6261
B =
1.0e+11 *
3.9223 7.0605 0.4617
6.5548 0.3183 0.9713
1.7119 2.7692 8.2346
C =
1.0e+11 *
6.9483 0.3445 7.6552
3.1710 4.3874 7.9520
9.5022 3.8156 1.8687
solP =
0.1061 + 0.0000i
1.5311 + 0.0000i
-0.3432 + 0.9356i
-0.3432 - 0.9356i
0.4228 - 0.5465i
0.4228 + 0.5465i
det(D) =
2.2143e+19
-5.4911e+20
-8.6415e+19 + 4.5024e+19i
-8.6415e+19 - 4.5024e+19i
-1.4547e+19 + 9.1135e+19i
-1.4547e+19 - 9.1135e+19i
The problem is related to the relative accuracy of floating point values, typically 1e-16.
The input matrices are of the order 1e+11 - 1e+12, the solution is of the order 1e+0, so the elements of D are also of the order 1e+11 - 1e+12. To calculate a determinant of a 3x3 matrix, one should take products of three matrix elements and add/subtract them. So, each term is of the order of 1e+33 - 1e+36. If you subtract such a values to obtain the determinant, the expected accuracy is in the order of 1e+17 - 1e+20. Indeed, this corresponds with the values you get. Given the relative accuracy, you are not able to reach further to zero.
Note that if you scale your input matrices, i.e. divide it by 1e+11, the solutions are indeed the same, but the determinants are probably more what you would expect.

How to put limit in Matlab programming

so i want to generate an eqution like theta= asind(x), then i make a program like this:
x=0.5:5
theta=asind(x)
if x>1
theta = out of range
otherwise x=<1
end
fprintf('theta')
but it gives an error:
xrdError: File: xrd.m Line: 4 Column: 17
Unexpected MATLAB expression.
please help me
A sensible thing to do is to set values which are invalid or missing to NaN (not a number). This can easily be done without a loop:
x=0.5:0.1:5; % changed spacing so there is more than one valid x
theta=asind(x);
theta(x>1)=NaN;
plot(x,theta); % will plot only the valid values
You said that you wanted the elements of theta to say "out of range" when the corresponding value of x is out of range, and otherwise to display the inverse sine of x.
This is a little odd in Matlab, because data in Matlab tends to be either arrays of numbers, or arrays of characters, but not a mixture of numbers and characters.
There is a way to mix numbers and characters by using what is called a cell array. A cell array can be created like this
cell1 = {};
cell2 = cell(5, 1);
and you assign and access the elements like this
cell1{1} = 'Hello';
cell1{2} = 7;
disp(cell{1})
So the program that (I think) you want to write would look something like
x = (0.5 : 5)';
theta = cell(size(x));
for i = 1:length(x)
if x(i) < -1 || x(i) > 1
theta{i} = 'Out of range';
else
theta{i} = asind(x(i));
end
end
x, theta
which outputs
x =
0.5000
1.5000
2.5000
3.5000
4.5000
theta =
[30.0000]
'Out of range'
'Out of range'
'Out of range'
'Out of range'
However, you should probably reconsider what it is you want your program to do, because a cell array is not a particularly easy data type to work with in Matlab.