I'm trying to use a soliton plus a step for my initial condition for KdV equation, however the Heaviside function I use as a step is producing oscillations. I want to replace Heaviside function in my code with tanh(x/epsilon), but I get an error in Matlab saying 'Data must be numeric, datetime, duration or an array convertible to double.' at the following line:
figure(1); plot(x,u,'r.'); pause(1);
It's probably a straightforward fix but I can't seem to figure it out.
Please find the sample of my code below for reference.
close all
clear all
x = linspace(-20,20,401);
N=401;
h=x(2)-x(1); % grid size
dt=0.0005;
%Soliton initial condition
Am=8; %Amplitude
mu=sqrt(Am/2);
x0=-15;
eps=0.0005;
c=1;
syms y
H(y)=piecewise(y < 0,0,y > 0,tanh(y/eps));
u= Am*(sech(mu*(x'))).^2+c^2*H(x)';
u1=u;
figure(1); plot(x,u,'r.'); pause(1);
Related
I started off with using Euler's Method before realizing the error size was too large so I started using the trapezoid method. My issue is when I try and implement the two-body solver it doesn't, well, do anything. I've tried several different things but either it runs and doesn't do anything or I get an error with array sizes.
Here is the working one-body code:
%Program 6.4 Plotting program for one-body problem
% Inputs: time interval inter, initial conditions
% ic = [x0 vx0 y0 vy0], x position, x velocity, y pos, y vel,
% number of steps n, steps per point plotted p
% Calls a one-step method such as trapstep.m
% Example usage: orbit([0 100],[0 1 2 0],10000,5)
function orbit(inter,ic,n,p)
h=(inter(2)-inter(1))/n; % plot n points
x0=ic(1);vx0=ic(2);y0=ic(3);vy0=ic(4); % grab initial conds
y(1,:)=[x0 vx0 y0 vy0];t(1)=inter(1); % build y vector
set(gca,'XLim',[-5 5],'YLim',[-5 5],...
'XTick',[-5 0 5],'YTick',[-5 0 5]);
sun=animatedline('color','y','Marker','.','markersize',50);
addpoints(sun,0,0)
head=animatedline('color','r','Marker','.','markersize',35);
tail=animatedline('color','b','LineStyle','-');
%[px,py]=ginput(1); % include these three lines
%[px1,py1]=ginput(1); % to enable mouse support
%y(1,:)=[px px1-px py py1-py]; % 2 clicks set direction
for k=1:n/p
for i=1:p
t(i+1)=t(i)+h;
y(i+1,:)=trapstep(t(i),y(i,:),h);
end
y(1,:)=y(p+1,:);t(1)=t(p+1);
clearpoints(head);addpoints(head,y(1,1),y(1,3))
addpoints(tail,y(1,1),y(1,3))
drawnow;
end
function y=eulerstep(t,x,h)
%one step of the Euler method
y=x+h*ydot(t,x);
function y = trapstep(t,x,h)
%one step of the Trapezoid Method
z1=ydot(t,x);
g=x+h*z1;
z2=ydot(t+h,g);
y=x+h*(z1+z2)/2;
function z = ydot(t,x)
m2=3;g=1;mg2=m2*g;px2=0;py2=0;
px1=x(1);py1=x(3);vx1=x(2);vy1=x(4);
dist=sqrt((px2-px1)^2+(py2-py1)^2);
z=zeros(1,4);
z(1)=vx1;
z(2)=(mg2*(px2-px1))/(dist^3);
z(3)=vy1;
z(4)=(mg2*(py2-py1))/(dist^3);
I may just be overthinking it, as I am not used to using Matlab, however I cannot get the two-body solver to work. I know I need to change the function z = ydot(t,x) to the code below:
m2=0.3;g=1;mg2=m2*g;m1=0.03;mg1=m1*g;
px1=x(1);py1=x(3);vx1=x(2);vy1=x(4);
px2=x(5);py2=x(7);vx2=x(6);vy2=x(8);
dist=sqrt((px2-px1)^2+(py2-py1)^2);
z=zeros(1,8);
z(1)=vx1;
z(2)=(mg2*(px2-px1))/(dist^3);
z(3)=vy1;
z(4)=(mg2*(py2-py1))/(dist^3);
z(5)=vx2;
z(6)=(mg1*(px1-px2))/(dist^3);
z(7)=vy2;
z(8)=(mg1*(py1-py2))/(dist^3);
Then get rid of the addpoint sun as well as add a new point, head, and tail. I have tried turning the input ic into an 8 element array as well as change y(1,:)=[x0 vx0 y0 vy0]; to contain 8 elements but the code does not work. As I said I am not very familiar with matlab so if anyone could help point me in the right direction it would be greatly appreciated!
I'm trying to plot the cosine function and the Taylor series for cosine on a subplot. I'm getting an error in my code saying that I haven't defined "symsum for input arguments of type 'double'". I don't know how to fix it.
x=0:10;
y1=cos(x);
y2=0;
for k=0:10
y2=y2+symsum((-1)^k*(x^(2*k))/factorial(2*k));
end
figure
subplot(2,1,1)
plot(x,y1)
title('Cosine')
subplot(2,1,2)
plot(x,y2)
title('Taylor Series')
You need to include
syms k
in your code to declare a symbolic variable k.
Also, the start and end to your sum should be included as arguments to symsum. Get rid of your for statement and include this instead:
y2 = y2+symsum((-1)^k*(x^(2k))/factorial(2*k), 0, 10);
function yp = nonlinear (t,y)
e=0.2;
yp(1)=y(2);
yp(2) = (-y(1)-e*y(1)^3);
tspan = [0.20];
y0=[0;0]
[t,y]=ode45('nonlinear',tpsan,y0)
plot (t,y(:,1))
grid
xlabel('time')
ylabel('u')
title ('u vs. t')
hold on;
Sorry I am absolutely noob at matlab, when I try to execute the code, it says "undefined function of variable t". I am trying to use ode45 to solve a differential equation
Read the documentation on ode45. You need to save the following lines of your code into a file nonlinear.m
function yp = nonlinear (t,y)
e=0.2;
yp(1)=y(2);
yp(2) = (-y(1)-e*y(1)^3);
and then in a separate (script) file, save the rest of your code:
tspan = [0.20];
y0=[0;0]
[t,y]=ode45('nonlinear',tpsan,y0)
plot (t,y(:,1))
grid
xlabel('time')
ylabel('u')
title ('u vs. t')
hold on;
You might also want to familiarise yourself with MATLAB before attempting that sort of thing. Check out the tutorials.
I'm using fzero function to solve a non-linear equation depending on one parameter
and I'm not satisfied with my method. I have these issues:
1) Can for loop for the parameter be avoided ?
2) In order to avoid complex solutions I first have to pre-compute valid interval for fzero.
Is there is a better solution here ?
If I reduce the parameter step size the execution time becomes slow. If I don’t pre-compute
the interval I get an error "Function values at interval endpoints must be finite and real."
in Matlab and "fzero: not a valid initial bracketing" in Octave.
Here is the code
% solve y = 90-asind(n*(sind(90-asind(sind(a0)/n)-y)))
% set the equation paramaters
n=1.48; a0=0:0.1:60;
% loop over a0
for i = 1:size(a0,2)
% for each a0 find where the argument of outer asind()
% will not give complex solutions, i.e. argument is between 1 and -1
fun1 = #(y) n*(sind(90-asind(sind(a0(i))/n)-y))-0.999;
y1 = fzero(fun1,[0 90]);
fun2 = #(y) n*(sind(90-asind(sind(a0(i))/n)-y))+0.999;
y2 = fzero(fun2,[0 90]);
% use y1, y2 as limits in fzero interval
fun3 = #(y) 90-asind(n*(sind(90-asind(sind(a0(i))/n)-y)))-y;
y(i) = fzero(fun3, [y1 y2]);
end
% plot the result
figure; plot(y); grid minor;
xlabel('Incident ray angle [Deg]');
ylabel('Lens surface tangent angle');
With Matlab, I obtained the plot below with the following simplified loop.
for i = 1:size(a0,2)
fun3 = #(y) sind(90-y) - n*(sind(90-asind(sind(a0(i))/n)-y));
y(i) = fzero(fun3, [0,90]);
end
The difference is in the form of equation: I replaced 90-y = asind(something) with sin(90-y) = something. When "something" is greater than 1 in absolute value, the former version throws an error due to complex value of asind. The latter proceeds normally, recognizing that this is not a solution (sin(90-y) can't be equal to something that is greater than 1).
No precomputing of the bracket was necessary, [0,90] simply worked. Another change I made was in the plot: plot(a0,y) instead of plot(y), to get the correct horizontal axis.
And you can't avoid for loop here, nor should you worry about it. Vectorization means eliminating loops where the content is a low-level operation that can be done en masse by operating on some C array. But fzero is totally not that. If the code takes long to run, it's because solving a bunch of equations takes long, not because there's a for loop.
I am using the code below and am trying to plot a velocity and acceleration curve after differentiation of a position function but I am getting errors. Could someone give me a hand?
clc,clear,close all
t=0:.0001:2*pi/150;
theta= (150*t) ;
r=.2.*cos(theta)+sqrt(.75^2 - (.2.*sin(theta)).^2);
plot(t,r)
hold on
syms t
theta= (150*t);
r=.2.*cos(theta)+sqrt(.75^2 - (.2.*sin(theta)).^2);
v=diff(r,t);
a=diff(r,t,2);
t=0:.0001:2*pi/150;
plot(t,v);
plot(t,a);
hold off
The reason why you're getting errors is because when you are using diff, you are using it symbolically. When you're plotting stuff, you need to get the numerical output. As such, you'll need an additional call to subs, plus a cast using double if you want to get this working. So:
syms t;
theta= (150*t);
r=.2.*cos(theta)+sqrt(.75^2 - (.2.*sin(theta)).^2);
v=diff(r,t);
a=diff(r,t,2);
%// Change
t_vec=0:.0001:2*pi/150;
v = double(subs(v, t, t_vec));
a = double(subs(a, t, t_vec));
hold on;
%// Change
plot(t_vec,v);
plot(t_vec,a);
hold off