MATLAB using ode45 to animate wave function throws tolerance error - matlab

I am working on animating a wave function in MATLAB. So far, I have not reached to part of the animation yet since my ode45 throws an error. I am using de Korteweg-de Vries equations for this
(which can be found here: https://en.wikipedia.org/wiki/Korteweg%E2%80%93de_Vries_equation).
Now my code is as follows:
function[t, N, u] = wave(u0, L, T, S, N)
%First we create a vector t which stores the time entries, a vector x which
%stores the location entries and an h which is the location step size for
%the Korteweg-De Vries function.
time = linspace(0,T,S);
x = linspace(-L,L,N);
h = x(2)-x(1);
U0=u0(x);
options=odeset('RelTol',1e-13,'AbsTol',1e-13);
[t,u] = ode45(#kdv,time,U0,options);
function dudt = kdv(t,u)
d2udx2 = ([u(N)-2*u(1)+u(2); diff(u,2); u(N-1)-2*u(N)+u(1)] ./ h^2);
total = d2udx2 + 3.*u.^2;
diff_total = diff(total);
diff_total = [diff_total(end); diff_total(1:end)];
dudt = -[diff_total(2)-diff_total(N-1); diff(diff_total,2); diff_total(N-1)+diff_total(2)] ./ (2*h);
end
end
Now when I set f=#(x)(2/2).*(1./cosh(sqrt(2).*x./2).^2) and then call the function with [t,N,u]=wave(f, 20, 10, 200, 200); I get the following error:
Warning: Failure at t=6.520003e-02. Unable to meet integration tolerances without reducing the step size below the
smallest value allowed (2.220446e-16) at time t.
In ode45 (line 360)
In wave (line 23)
Also the returned t and u have a size of 16x1 and 16x200 respectively, but I think they would expand to 200x1 and 200x200 if the warning did not occur.
Any hints on how to solve this would be much appreciated.

You did too much differences, the middle step of constructing diff_total is redundant.
d2udx2 and thus total are constructed correctly. You could shorten the first construction as
d2udx2 = diff([u(N); u; u(1) ], 2)./h^2`;
The next step constructing diff_total is redundant with the difference construction in dudt. The diff_total construction is lacking a division by h, for some unknown reason you have difference order 2 in the middle of dudt.
The outer x differentiation would be best done via convolution to get a central difference quotient as you have in the outer elements,
dudt = -conv([ total(N); total; total(1)], [1; 0; -1], 'valid')/(2*h)
All together this gives the derivatives procedure
function dudt = kdv(t,u,h)
d2udx2 = diff([u(end); u; u(1) ], 2)./h^2;
total = d2udx2 + 3*u.^2;
dudt = -conv( [ total(end); total; total(1)], [1; 0; -1], 'valid')./(2*h);
end
which (with N=80) produces the solution
which as intended is a soliton wave traveling with speed c=2.

Related

Having difficulties in finding error: Matrix dimensions must agree

My aim is to call this function into the pso code for minimization.
actually im calling this code into another program(mfile),here
v=0.1*x0; % initial velocity
for i=1:n
f0(i,1)=ofun(x0(i,:));
end
so what should i do, could anyone plz write me a code, so i can remove this problem. my aim is to minimize error using ITEA code, which im trying to do, im trying to find a that every time code runs, e_t have last updated value, not e_t=0.001 .
I don't have e_t. If I'm going to initialize it, it will remain constant, but I need to change its value in the code.
Second, I'm getting this error
Error using .* Matrix dimensions must agree.
Error in ofun (line 10), f = sum(t'.*abs(e_t)*dt);
function f=ofun(x)
Kp= x(1);
Ki= x(2);
e_t;
d=0.001;
I_ref=-1.1:d:1;
dt = 0.01;
t = 0:dt:1;
e_t= I_ref - (Kp.*e_t +Ki.*sum(t'.*abs(e_t)*dt));
f = sum(t'.*abs(e_t)*dt); % line 10
I want to write code for following equations
error= I_ref - (kp * error + ki*(integration of error));
I want to set I-ref=-1.1-1.1;
Here e_t get's the same size as I_ref
e_t= I_ref - (Kp.*e_t +Ki.*sum(t'.*abs(e_t)*dt));
Then you want to multiply it with t
f = sum(t'.*abs(e_t)*dt);
But t is of a different size as I_ref. t has length 101, I_ref has length 2101.
"Matrix dimensions must agree" is an error message that appears in this case in line 10 because matrix t cannot be multiplied elementwise with the e_t. Whichever matrix is smaller, I would probably add ones to the rest of it so that the result matrix is still able tone populated. Why are you transposing matrix t though? Good luck with your project!
function f=ofun(x)
%Define variables and constants- when you define e_t, why are you not multiplying dt elementwise? Also why do you transpose matrix t?
Kp = x(1); Ki = x(2); d = 0.001; I_ref = [-1.1 : d : 1]; dt = 0.01; t = [0 : dt : 1]; e_t = I_ref - (Kp.*e_t + Ki.*sum(t'.*abs(e_t)*dt));
f = sum(t'.*abs(e_t)*dt);% line 10
end

How do I define parameters in a convolution equation?

I am trying to compute the convolution of a sound signal without using the built in conv function but instead using arrays. x is the input signal and h is are the impulse responses. However, when I run my other main function to call onto my_conv I am getting these errors:
Undefined function or variable 'nx'.**
Error in my_conv (line 6)
ly=nx+nh-1;
Error in main_stereo (line 66)
leftchannel = my_conv(leftimp, mono); % convolution of left ear impulse response and mono
This is my function my_conv:
function [y]=my_conv(x,h)
x=x(:);
h=h(:);
lx=length(x);
lh=length(h);
ly=nx+nh-1;
Y=zeros(nh,ny);
for i =1:nh
Y((1:nx)+(i-1),i)=x;
end
y=Y*h;
What changes should I make to fix these errors and get this code running?
I am trying to immplement the function into this code:
input_filename = 'speech.wav';
stereo_filename = 'stereo2.wav';
imp_filename = 'H0e090a.dat';
len_imp = 128;
fp = fopen(imp_filename, 'r', 'ieee-be');
data = fread(fp, 2*len_imp, 'short');
fclose(fp);
[mono,Fs] = audioread(input_filename);
if (Fs~=44100)
end
len_mono = length(mono);
leftimp = data(1:2:2*len_imp);
rightimp = data(2:2:2*len_imp);
leftchannel = my_conv(leftimp, mono);
rightchannel = my_conv(rightimp, mono);
leftchannel = reshape(leftchannel , length(leftchannel ), 1);
rightchannel = reshape(rightchannel, length(rightchannel), 1);
norml = max(abs([leftchannel; rightchannel]))*1.05;
audiowrite(stereo_filename, [leftchannel rightchannel]/norml, Fs);
As pointed out by #SardarUsama in comments, the error
Undefined function or variable 'nx'.
Error in my_conv (line 6) ly=nx+nh-1;
tells you that the variable nx has not been defined before before its usage on the line ly=nx+nh-1. Given the naming of the variables and their usage, it looks like what you intended to do was:
nx = length(x);
nh = length(h);
ny = nx+nh-1;
After making these modifications and solving the first error, you are likely going to get another error telling you that
error: my_conv: operator *: nonconformant arguments
This error is due to an inversion in the specified size of the Y matrix. This can be fixed by initializing Y with Y = zeros(ny, nh);. The resulting my_conv function follows:
function [y]=my_conv(x,h)
nx=length(x);
nh=length(h);
ny=nx+nh-1;
Y=zeros(ny,nh);
for i =1:nh
Y((1:nx)+(i-1),i)=x;
end
y=Y*h;
Note that storing every possible shifts of one of the input vectors in the matrix Y to compute the convolution as a matrix multiplication is not very memory efficient (requiring O(NM) storage). A more memory efficient implementation would compute each element of the output vector directly:
function [y]=my_conv(x,h)
nx=length(x);
nh=length(h);
if (nx < nh)
y = my_conv(h,x);
else
ny=nx+nh-1;
y = zeros(1,ny);
for i =1:ny
idh = [max(i-(ny-nh),1):min(i,nh)]
idx = [min(i,nx):-1:max(nx-(ny-i),1)]
y(i) = sum(x(idx).*h(idh));
end
end
An alternate implementation which can be more computationally efficient for large arrays would make use of the convolution theorem and use the Fast Fourier Transform (FFT):
function [y]=my_conv2(x,h)
nx=length(x);
nh=length(h);
ny=nx+nh-1;
if (size(x,1)>size(x,2))
x = transpose(x);
end
if (size(h,1)>size(h,2))
h = transpose(h);
end
Xf = fft([x zeros(size(x,1),ny-nx)]);
Hf = fft([h zeros(size(h,1),ny-nh)]);
y = ifft(Xf .* Hf);

Something's wrong with my Logistic Regression?

I'm trying to verify if my implementation of Logistic Regression in Matlab is good. I'm doing so by comparing the results I get via my implementation with the results given by the built-in function mnrfit.
The dataset D,Y that I have is such that each row of D is an observation in R^2 and the labels in Y are either 0 or 1. Thus, D is a matrix of size (n,2), and Y is a vector of size (n,1)
Here's how I do my implementation:
I first normalize my data and augment it to include the offset :
d = 2; %dimension of data
M = mean(D) ;
centered = D-repmat(M,n,1) ;
devs = sqrt(sum(centered.^2)) ;
normalized = centered./repmat(devs,n,1) ;
X = [normalized,ones(n,1)];
I will be doing my calculations on X.
Second, I define the gradient and hessian of the likelihood of Y|X:
function grad = gradient(w)
grad = zeros(1,d+1) ;
for i=1:n
grad = grad + (Y(i)-sigma(w'*X(i,:)'))*X(i,:) ;
end
end
function hess = hessian(w)
hess = zeros(d+1,d+1) ;
for i=1:n
hess = hess - sigma(w'*X(i,:)')*sigma(-w'*X(i,:)')*X(i,:)'*X(i,:) ;
end
end
with sigma being a Matlab function encoding the sigmoid function z-->1/(1+exp(-z)).
Third, I run the Newton algorithm on gradient to find the roots of the gradient of the likelihood. I implemented it myself. It behaves as expected as the norm of the difference between the iterates goes to 0. I wrote it based on this script.
I verified that the gradient at the wOPT returned by my Newton implementation is null:
gradient(wOP)
ans =
1.0e-15 *
0.0139 -0.0021 0.2290
and that the hessian has strictly negative eigenvalues
eig(hessian(wOPT))
ans =
-7.5459
-0.0027
-0.0194
Here's the wOPT I get with my implementation:
wOPT =
-110.8873
28.9114
1.3706
the offset being the last element. In order to plot the decision line, I should convert the slope wOPT(1:2) using M and devs. So I set :
my_offset = wOPT(end);
my_slope = wOPT(1:d)'.*devs + M ;
and I get:
my_slope =
1.0e+03 *
-7.2109 0.8166
my_offset =
1.3706
Now, when I run B=mnrfit(D,Y+1), I get
B =
-1.3496
1.7052
-1.0238
The offset is stored in B(1).
I get very different values. I would like to know what I am doing wrong. I have some doubt about the normalization and 'un-normalization' process. But I'm not sure, may be I'm doing something else wrong.
Additional Info
When I tape :
B=mnrfit(normalized,Y+1)
I get
-1.3706
110.8873
-28.9114
which is a rearranged version of the opposite of my wOPT. It contains exactly the same elements.
It seems likely that my scaling back of the learnt parameters is wrong. Otherwise, it would have given the same as B=mnrfit(D,Y+1)

ODE 15s with time dependent input parameters

I have a MATLAB code that solves a large scale ODE system of following type
function [F] = myfun(t,C,u)
u here is a time dependent vector used as a input in the function myfun. My current code reads as:-
u = zeros(4,1);
u(1) = 0.1;
u(2) = 0.1;
u(3) = 5.01/36;
u(4) = 0.1;
C0 = zeros(15*4*20+12,1);
options = odeset('Mass',Mf,'RelTol',1e-5,'AbsTol',1e-5);
[T,C] = ode15s(#OCFDonecolumnA, [0,5000] ,C0,options,u);
I would like to have the entire time domain split into 5 different sections and have the elements of u take different values at different times(something like a multiple step function). what would be the best way to code it considering that I later want to solve a optimization problem to determine values of u for each time interval in the domain [0,5000].
Thanks
ode15s expects your model function to accept a parameter t for time and a vector x (or C as you named it) of differential state variables. Since ode15s will not let us pass in another vector u of control inputs, I usually wrap the ODE function ffcn inside a model function:
function [t, x] = model(x0, t_seg, u)
idx_seg = 0;
function y = ffcn(t, x)
% simple example of exponential growth
y(1) = u(idx_seg) * x(1)
end
...
end
In the above, the parameters of model are the initial state values x0, the vector of switching times t_seg, and the vector u of control input values in different segments. You can see that idx_seg is visible from within ffcn. This allows us to integrate the model over all segments (replace ... in the above with the following):
t_start = 0;
t = t_start;
x = x0;
while idx_seg < length(t_seg)
idx_seg = idx_seg + 1;
t_end = t_seg(idx_seg);
[t_sol, x_sol] = ode15s(#ffcn, [t_start, t_end], x(end, :));
t = [t; t_sol(2 : end)];
x = [x; x_sol(2 : end, :)];
t_start = t_end;
end
In the first iteration of the loop, t_start is 0 and t_end is the first switching point. We use ode15s now to only integrate over this interval, and our ffcn evaluates the ODE with u(1). The solution y_sol and the corresponding time points t_sol are appended to our overall solution (t, x).
For the next iteration, we set t_start to the end of the current segment and set the new t_end to the next switching point. You can also see that the last element of t_seg must be the time at which the simulation ends. Importantly, we pass to ode15s the current tail y(end, :) of the simulated trajectory as the initial state vector of the next segment.
In summary, the function model will use ode15s to simulate the model segment by segment and return the overall trajectory y and its time points t. You could convince yourself with an example like
[t, x] = model1(1, [4, 6, 12], [0.4, -0.7, 0.3]);
plot(t, x);
which for my exponential growth example should yield
For your optimization runs, you will need to write an objective function. This objective function can pass u to model, and then calculate the merit associated with u by looking at x.

State space system gives different bode plot then transfer function matrix

I have a state space system with matrices A,B,C and D.
I can either create a state space system, sys1 = ss(A,B,C,D), of it or compute the transfer function matrix, sys2 = C*inv(z*I - A)*B + D
However when I draw the bode plot of both systems, they are different while they should be the same.
What is going wrong here? Does anyone have a clue? I know btw that the bodeplot generated by sys1 is correct.
The system can be downloaded here: https://dl.dropboxusercontent.com/u/20782274/system.mat
clear all;
close all;
clc;
Ts = 0.01;
z = tf('z',Ts);
% Discrete system
A = [0 1 0; 0 0 1; 0.41 -1.21 1.8];
B = [0; 0; 0.01];
C = [7 -73 170];
D = 1;
% Set as state space
sys1 = ss(A,B,C,D,Ts);
% Compute transfer function
sys2 = C*inv(z*eye(3) - A)*B + D;
% Compute the actual transfer function
[num,den] = ss2tf(A,B,C,D);
sys3 = tf(num,den,Ts);
% Show bode
bode(sys1,'b',sys2,'r--',sys3,'g--');
Edit: I made a small mistake, the transfer function matrix is sys2 = C*inv(z*I - A)*B + D, instead of sys2 = C*inv(z*I - A)*B - D which I did wrote done before. The problem still holds.
Edit 2: I have noticted that when I compute the denominator, it is correct.
syms z;
collect(det(z*eye(3) - A),z)
Your assumption that sys2 = C*inv(z*I- A)*B + D is incorrect. The correct equivalent to your state-space system (A,B,C,D) is sys2 = C*inv(s*I- A)*B + D. If you want to express it in terms of z, you'll need to invert the relationship z = exp(s*T). sys1 is the correct representation of your state-space system. What I would suggest for sys2 is to do as follows:
sys1 = ss(mjlsCE.A,mjlsCE.B,mjlsCE.C,mjlsCE.D,Ts);
sys1_c = d2c(sys1);
s = tf('s');
sys2_c = sys1_c.C*inv(s*eye(length(sys1_c.A)) - sys1_c.A)*sys1_c.B + sys1_c.D;
sys2_d = c2d(sys2_c,Ts);
That should give you the correct result.
Due to inacurracy of the inverse function extra unobservable poles and zeros are added to the system. For this reason you need to compute the minimal realization of your transfer function matrix.
Meaning
% Compute transfer function
sys2 = minreal(C*inv(z*eye(3) - A)*B + D);
What you are noticing is actually a numerical instability regarding pole-zero pair cancellations.
If you run the following code:
A = [0, 1, 0; 0, 0, 1; 0.41, -1.21, 1.8] ;
B = [0; 0; 0.01] ;
C = [7, -73, 170] ;
D = 1 ;
sys_ss = ss(A, B, C, D) ;
sys_tf_simp = tf(sys_ss) ;
s = tf('s') ;
sys_tf_full = tf(C*inv(s*eye(3) - A)*B + D) ;
zero(sys_tf_simp)
zero(sys_tf_full)
pole(sys_tf_simp)
pole(sys_tf_full)
you will see that the transfer function formulated by matrices directly has a lot more poles and zeros than the one formulated by MatLab's tf function. You will also notice that every single pair of these "extra" poles and zeros are equal- meaning that they cancel with each other if you were to simply the rational expression. MatLab's tf presents the simplified form, with equal pole-zero pairs cancelled out. This is algebraically equivalent to the unsimplified form, but not numerically.
When you call bode on the unsimplified transfer function, MatLab begins its numerical plotting routine with the pole-zero pairs not cancelled algebraically. If the computer was perfect, the result would be the same as in the simplified case. However, numerical error when evaluating the numerator and denominators effectively leaves some of the pole-zero pairs "uncancelled" and as many of these poles are in the far right side of the s plane, they drastically influence the output behavior.
Check out this link for info on this same problem but from the perspective of design: http://ctms.engin.umich.edu/CTMS/index.php?aux=Extras_PZ
In your original code, you can think of the output drawn in green as what the naive designer wanted to see when he cancelled all his unstable poles with zeros, but the output drawn in red is what he actually got because in practice, finite-precision and real-world tolerances prevent the poles and zeros from cancelling perfectly.
Why is an unobservable / uncontrollable pole? I think this issue comes only because the inverse of a transfer function matrix is inaccurate in Matlab.
Note:
A is 3x3 and the minimal realization has also order 3.
What you did is the inverse of a transfer function matrix, not a symbolic or numeric matrix.
# Discrete system
Ts = 0.01;
A = [0 1 0; 0 0 1; 0.41 -1.21 1.8];
B = [0; 0; 0.01];
C = [7 -73 170];
D = 1;
z = tf('z', Ts)) # z is a discrete tf
A1 = z*eye(3) - A # a tf matrix with a direct feedthrough matrix A
# inverse it, multiply with C and B from left and right, and plus D
G = D + C*inv(A1)*B
G is now a scalar (SISO) transfer function.
Without "minreal", G has order 9 (funny, I don't know how Matlab computes it, perhaps the "Adj(.)/det(.)" method). Matlab cannot cancel the common factors in the numerator and the denominator, because z is of class 'tf' rather than a symbolic variable.
Do you agree or do I have misunderstanding?