Unexpected length of array and plotting error as a result - matlab

I wanted to plot the load voltage across the resistor in series with a diode using matlab. This is a rather simple example involving piecewise functions, however I ran into an unexpected error.
t=[0:0.001:10]
vs=4*sin(pi * t)
for i =1:length(vs)
if(vs(i)<=0.7)
v(i)=0;
else
v(i)=vs(i)-0.7;
end
end
plot(t,v)
t is the time, vs is the source voltage, and v is the load voltage. Now, running this gave me an error saying "error, t and v are of different sizes..". Using length() I found out that while t and vs are of lengths 10001, v is somehow of length 1000001.
This is truly baffling to me. How can v and vs possibly differ in size? every element of vs was mapped to an element of v, and yet the size of v comes out to be about 100 times the size of vs.
Being new to matlab, I still am not very comfortable with not explicitly declaring the array v before using it in the for loop. However, I went through with it, because the example I worked on prior to this, used the same thing and it worked without any problems. We simply had a plot a piecewise function:
x=[-2 : 0.00001 : 20];
for i=1: length(x)
if(x(i)>=-2 && x(i)<0)
y(i)=sqrt(x(i)^2+1);
else if(x(i)>=0 && x(i)<10)
y(i)=3*x(i)+1;
else
y(i)=9*sin(5*x(i)-50);
end
end
end
plot(x,y)
This code worked flawlessly, and in my opinion the initial code is fundamentally doing the same thing, so again, I'm clueless as to why it failed.
The original code works if you initialise v to be of the same size as t (and therefore, vs), but still, I want to know why the code involving x,y worked (where y wasn't initialised) and the code involving (t,v) failed.
Also, my friend copy pasted the entire code into the command window of matlab 2016, and it worked. (and I'm using the 2021 version).

Its good practice to initialize variables before entering a loop. It will help avoid undefinied behaviour when you run the script multiple times. If you run the script with different lengths for t, it would fail the second run. One solution would be:
t=0:0.001:10;
vs=4*sin(pi * t);
v=nan(size(t));
for i =1:length(vs)
if(vs(i)<=0.7)
v(i)=0;
else
v(i)=vs(i)-0.7;
end
end
figure;
plot(t,v);
You could also avoid the for loop and use matrix operations instead:
t=0:0.001:10;
vs=4*sin(pi * t);
v=vs-0.7;
v(vs<=0.7)=0;
figure;
plot(t,v);

Related

MATLAB Initial Objective Function Evaluation Error

I am trying to create a plot in MATLAB by iterating over values of a constant (A) with respect to a system of equations. My code is pasted below:
function F=Func1(X, A)
%X(1) is c
%X(2) is h
%X(3) is lambda
%A is technology (some constant)
%a is alpha
a=1;
F(1)=1/X(1)-X(3)
F(2)=X(3)*(X(1)-A*X(2)^a)
F(3)=-1/(24-X(2))-X(3)*A*a*X(2)^(a-1)
clear, clc
init_guess=[0,0,0]
for countA=1:0.01:10
result(countA,:)=[countA,fsolve(#Func1, init_guess)]
end
display('The Loop Has Ended')
display(result)
%plot(result(:,1),result(:,2))
The first set of code, I am defining the set of equations I am attempting to solve. In the second set of lines, I am trying to write a loop which iterates through the values of A that I want, [1,10] with an increment of 0.01. Right now, I am just trying to get my loop code to work, but I keep on getting this error:
"Failure in initial objective function evaluation. FSOLVE cannot continue."
I am not sure why this is the case. From what I understand, this is the result of my initial guess matrix not being the right size, but I believe it should be of size 3, as I am solving for three variables. Additionally, I'm fairly confident there's nothing wrong with how I'm referencing my Func1 code in my Loop code.
Any advice you all could provide would be sincerely appreciated. I've only been working on MATLAB for a few days, so if this is a rather trivial fix, pardon my ignorance. Thanks.
Couple of issues with your code:
1/X(1) in function Func1 is prone to the division by zero miscalculations. I would change it to 1/(X(1)+eps).
If countA is incrementing by 0.01, it cannot be used as an index for result. Perhaps introduce an index ind to increment.
I have included your constant A within the function to clarify what optimization variables are.
Here is the updated code. I don't know if the results are reasonable or not:
init_guess=[0,0,0];
ind = 1;
for countA=1:0.01:10
result(ind,:)=[countA, fsolve(#(X) Func1(X,countA), init_guess)];
ind = ind+1;
end
display('The Loop Has Ended')
display(result)
%plot(result(:,1),result(:,2))
function F=Func1(X,A)
%X(1) is c
%X(2) is h
%X(3) is lambda
%A is technology (some constant)
%a is alpha
a=1;
F(1)=1/(X(1)+eps)-X(3);
F(2)=X(3)*(X(1)-A*X(2)^a);
F(3)=-1/(24-X(2))-X(3)*A*a*X(2)^(a-1);
end

Using Euler's Method in Matlab

First time post here. Pretty frustrated right now working on this assignment for class.
Basically, the idea is to use Euler's method to simulate and graph an equation of motion. The equation of motion is in the form of an ODE.
My professor has already put down some code for slightly similar system and would like us to derive the equation of motion using Lagrange. I believe that I have derived the EOM correctly, however I am running into problems on the Matlab side of things.
What's weird is that using a similar technique on another, seperate EOM, I have no issues. So I am unsure what I am doing wrong.
Here's the code for the part that is working correctly:
close all; clear all; clc;
% System parameters
w = 2*pi;
c = 0.02;
% Time vectors
dt = 1e-5;
t = 0:dt:4;
theta = zeros(size(t));
thetadot = zeros(size(t));
% Initial conditions
theta(1)=pi/2; %theta(0)
thetadot(1)=0; %thetadot(0)
for I = 1 : length(t)-1;
thetaddot = -c*thetadot(I)-w^2*sin(theta(I));
thetadot(I+1)=thetadot(I)+thetaddot*dt;
theta(I+1)=theta(I)+thetadot(I)*dt ;
end
figure(1);
plot(t,theta,'b');
xlabel('time(s)');
ylabel('theta');
title('Figure 1');
zoom on;
% Output the plot to a pdf file, and make it 6 inches by 4 inches
printFigureToPdf('fig1.pdf', [6,4],'in');
% Open the pdf for viewing
open fig1.pdf
Everything runs fine, except Matlab complains about the printFigureToPdf command.
Now, here is the code for the problem that I am having issues with.
close all; clear all; clc; clf
% System parameters
m=0.2;
g=9.81;
c=.2;
d=0.075;
L=0.001; %L is used for Gamma
B=0.001; %B is used for Beta
W=210*pi; %W is used for Omega
%Time vectors
dt = 1e-6; %Time Step
t=0:dt:10; %Range of times that simulation goes through
x=zeros(size(t));
xdot=zeros(size(t));
%Initialconditions
x(1)=0;%x(0)
xdot(1)=0; %xdot(0)
for I = 1 : length(t)-1;
xddot =-1/m*(c*xdot(I)-c*L*W*cos(W)+m*g-3*B*((d+x-L*W*sin(W*t)).^(-4)-(d-x-L*W*sin(W*t)).^(-4)));
xdot(I+1)=xdot(I)+xddot*dt;
x(I+1)=x(I)+xdot(I+1)*dt ;
end
figure(1);
plot(t,x,'b');
xlabel('time(s)');
ylabel('distance(m)');
title('Figure 2');
zoom on;
% Output the plot to a pdf file, and make it 6 inches by 4 inches
printFigureToPdf('fig1.pdf', [6,4],'in');
% Open the pdf for viewing
open fig1.pdf
With this code, I followed the same procedure and is giving an error on line 23: "In an assignment A(I) = B, the number of elements in B and I must be the same."
Like I said, I am confused because the other code worked okay, and this second set of code gives an error.
If anyone could give me a hand with this, I would greatly appreciate it.
Thanks in advance,
Dave
Edit: As suggested, I changed x(I+1)=x(I)+xdot(I+1)*dt to x(I+1)=x(I)+xdot(I)*dt. However, I am still getting an error for line 23: "In an assignment A(I) = B, the number of elements in B and I must be the same."
Line 23 is: xdot(I+1)=xdot(I)+xddot*dt;
So, I tried adjusting the code as suggested for the other line to xdot(I+1)=xdot(I)+xddot(I)*dt;
After making this change, Matlab gets stuck, I tried letting it run for a few minutes but won't execute. I ended up having to close and reopen the application.
The error In an assignment A(I) = B, the number of elements in B and I must be the same. is something you should understand because it may pop up frequently in Matlab if you are not careful.
In your case, you are trying to assign 1 element value xdot(I+1) with something which has more than 1 element xdot(I)+xddot*dt.
Indeed, if you step through the code line by line and observe your workspace, you will notice that xddot is not a scalar value as intended, but a full blown vector the size of t. This is because in the precedent line where you define xddot:
xddot =-1/m*(c*xdot(I)-c*L*W*cos(W)+m*g-3*B*((d+x-L*W*sin(W*t)).^(-4)-(d-x-L*W*sin(W*t)).^(-4)));
you still have many references to x (full vector) and t (full vector). You have to replace all these references to full vectors to only one index of them, i.e use x(I) and t(I). The line becomes:
xddot =-1/m*(c*xdot(I)-c*L*W*cos(W)+m*g-3*B*((d+x(I)-L*W*sin(W*t(I))).^(-4)-(d-x(I)-L*W*sin(W*t(I))).^(-4)));
With that your code runs just fine. However, it is far from optimized and it runs relatively slow. I have a powerful machine and it still takes a long time to run for me. I suggest you reduce your time step to something more sensible, at least when you are still trying your code. If you really need that kind of precision, first make sure your code runs fine then when it is ready let it run at full precision and go have a coffee while your computer is doing the work.
The snippet below is the loop part of your code with the correct assignment for xddot. I also added a simple progress bar so you can see that your code is doing something.
hw = waitbar(0,'Please wait...') ;
npt = length(t)-1 ;
for I = 1 : npt
xddot =-1/m*(c*xdot(I)-c*L*W*cos(W)+m*g-3*B*((d+x(I)-L*W*sin(W*t(I))).^(-4)-(d-x(I)-L*W*sin(W*t(I))).^(-4)));
xdot(I+1) = xdot(I)+xddot*dt;
x(I+1) = x(I)+xdot(I+1)*dt ;
pcdone = I / npt ;
waitbar(pcdone,hw,[num2str(pcdone*100,'%5.2f') '% done'])
end
close(hw)
I strongly suggest you reduce your time step to dt = 1e-3; until you are satisfied with everything else.
In the final version, you can remove or comment the calls to the waitbar as it slows down things too.

Symbolic Math Toolbox hitting divide by zero error when it used to evaluate to NaN

I've just updated to Matlab 2014a finally. I have loads of scripts that use the Symbolic Math Toolbox that used to work fine, but now hit the following error:
Error using mupadmex
Error in MuPAD command: Division by zero. [_power]
Evaluating: symobj::trysubs
I can't post my actual code here, but here is a simplified example:
syms f x y
f = x/y
results = double(subs(f, {'x','y'}, {1:10,-4:5}))
In my actual script I'm passing two 23x23 grids of values to a complicated function and I don't know in advance which of these values will result in the divide by zero. Everything I can find on Google just tells me not to attempt an evaluation that will result in the divide by zero. Not helpful! I used to get 'inf' (or 'NaN' - I can't specifically remember) for those it could not evaluate that I could easily filter for when I do the next steps on this data.
Does anyone know how to force Matlab 2014a back to that behaviour rather than throwing the error? Or am I doomed to running an older version of Matlab forever or going through the significant pain of changing my approach to this to avoid the divide by zero?
You could define a division which has the behaviour you want, this division function returns inf for division by zero:
mydiv=#(x,y)x/(dirac(y)+y)+dirac(y)
f = mydiv(x,y)
results = double(subs(f, {'x','y'}, {1:10,-4:5}))

Function to find entries with same maximum value in a vector

In my project I need a function which returns the index of the largest element of a given vector. Just like max. For more than one entry with the same maximum value (which occurs frequently) the function should choose one randomly. Unlike max.
The function is a subfunction in a MATLAB Function Block in Simulink. And the whole Simulink model is compiled.
My basic idea was:
function ind = findOpt(vector)
index_max = find(vector == max(vector));
random = randi([1,length(index_max)],1);
ind = index_max(random);
end
But I got problems with the comparison in find and with randi.
I found out about safe comparison here: Problem using the find function in MATLAB. Also I found a way to replace randi([1,imax],1): Implement 'randi' using 'rand' in MATLAB.
My Code now looks like this:
function ind = findOpt(vector)
tolerance = 0.00001;
index_max = find(abs(vector - max(vector)) < tolerance);
random = ceil(length(index_max)*rand(1));
ind = index_max(random);
end
Still doesn't work. I understand that the length of index_max is unclear and causes problems. But I can not think of any way to know it before. Any ideas how to solve this?
Also, I'm shocked that ceil doesn't work when the code gets executed?? In debug mode there is no change to the input visible.
I thought about creating an array like: index_max = abs(vector - max(vector)) < tolerance; But not sure how that could help. Also, it doesn't solve my problem with the random selection.
Hopefully somebody has more ideas or at least could give me some hints!
I am using MATLAB R2012b (32bit) on a Windows7-64bit PC, with the Lcc-win32 C 2.4.1 compiler.
Edit:
Vector usually is of size 5x1 and contains values between -2000 and zero which are of type double, e.g. vector = [-1000 -1200 -1000 -1100 -1550]'. But I think such a simple function should work with any kind of input vector.
The call of length(index_max) causes an system error in MATLAB and forces me to shut it down. I guess this is due to the strange return I get from find. For a vector with all the same values the return from find is something like [1.000 2.000 1.000 2.000 0.000]' which doesn't make any sense to me at all.
function v= findOpt(v)
if isempty(v)
return;
end
v = find((max(v) - v) < 0.00001);
v = v(ceil(rand(1)*end));
end
I was indeed overloading, just like user664303 suggested! Since I can not use objects in my project, I wanted an function that behaves similar, so I wrote:
function varargout = table(mode, varargin)
persistent table;
if isempty(table) && ~strcmp(mode,'writeTable')
error(...)
end
switch mode
case 'getValue'
...
case 'writeTable'
table = ...
...
end
end
Wanted to avoid passing the dimensions for the table in every call and thought it would be enough if the first call initializes the Table with mode='writeTable'. Looks like this caused my problem.
No problems after changing to:
if isempty(table)
table = zeros(dim1,dim2,...)
end

Using MATLAB pcg to Solve Inexactly

I am using MATLAB's PCG subroutine to solve a system of linear equations. However, I don't want it to solve exactly. I want it to run for only 20 iterations and if it doesn't converge, I want it to return the value at the 20th iteration.
What MATLAB (My version is the latest one) is doing however is returning a zero vector if it doesn't find an acceptable solution by 20 iterations. Is there any way to override this without changing the source code of pcg.m?
I have a code which I wrote which does that (I just copied from Wikipedia) but obviously, it is not close to how robust MATLAB's version is.
function [x] = conjgrad(A,b,x)
r=b-A*x;
p=r;
rsold=r'*r;
for i=1:20
Ap=A*p;
alpha=rsold/(p'*Ap);
x=x+alpha*p;
r=r-alpha*Ap;
rsnew=r'*r;
if sqrt(rsnew)<1e-10
break;
end
p=r+rsnew/rsold*p;
rsold=rsnew;
end

Categories