How to define a peicewise function in a function file - Matlab - matlab

I made a funnction file and defined a peicewise function inside it using conditionals and a for loop. I tried calling the function in a seperate m.file but the variables 't' and 'v' aren't showing in the workspace, rather it is just outputting a vector with the t values called 'ans.
I tried putting the exact code (without the function definition) into a regular m file and it worked just fine showing both variables t and v
#function file
function [t, v] = VPieceWise(t_start, t_end);
t = t_start:0.01:t_end;
for i = 1:length(t);
if (t(i) >= 0) && (t(i) <= 10);
v(i) = 11.*(t(i).^2) - (5.*t(i));
elseif (t(i) >= 10) && (t(i) <= 20);
v(i) = 1100 - 5.*t(i);
elseif (t(i) >= 20) && (t(i) <= 30);
v(i) = 50.*t(i) + 2*((t(i)-20).^2.5);
elseif (t(i) >= 30) && (t(i) <= 100);
v(i) = 1520.*exp(-0.1.*(t(i)-30));
elseif (t(i) >= -100) && (t(i) <= 0);
v(i) = 0;
end
end
end
#m file
clear all; clc; close all
t_start = input('enter the start time');
t_end = input('enter the end time');
VPieceWise(t_start,t_end)
plot(t,v)

Since your function has two outputs, you should also assign them when calling the function. If you do not do that, only the first output will be put in the ans variable.
So call your function as follows:
clear all; clc; close all
t_start = input('enter the start time');
t_end = input('enter the end time');
[t,v] = VPieceWise(t_start,t_end);
plot(t,v)

Related

MATLAB function in Simulink cannot access variable 'Q' Error: "Undefined function or variable 'Q'. "

I have a MATLAB function block (named Q_learning in the visual below) in Simulink. The code needs to update an existing matrix (denoted by 'Q') which was initially declared in a script (initialpara.m file) as a 7 by 10^7 matrix of zeros.
But it appears that it cannot access the initial declaration of the matrix. The error message is as follows:
Undefined function or variable 'Q'. The first assignment to a local
variable determines its class.
Function 'Control Centre/MATLAB Function' (#174.774.775), line 32,
column 21: "Q" Launch diagnostic report.
initialpara.m file
%%% Q Learning Parameters %%%
Q = zeros(7,100*100*1000);
gamma = 0.8;
previous_state = 0;
previous_reward = 0;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Q_learning.m file
function [KP, KI, KD, state, reward] = Qlearning(e_now, previous_state, previous_reward)
%#codegen
if (e_now >= -1 && e_now <= 1)
state = 1;
reward = 7;
elseif (e_now >= -5 && e_now <= 5)
state = 2;
reward = 6;
elseif (e_now >= -10 && e_now <= 10)
state = 3;
reward = 5;
elseif (e_now >= -15 && e_now <= 15)
state = 4;
reward = 4;
elseif (e_now >= -20 && e_now <= 20)
state = 5;
reward = 3;
elseif (e_now >= -25 && e_now <= 25)
state = 6;
reward = 2;
elseif (e_now >= -30 && e_now <= 30)
state = 7;
reward = 1;
end#
subMatrix = Q(state, :);
[maxQ_value, max_column] = max(subMatrix);
Q(state, previous_state) = previous_reward + 0.9 * maxQ_value;
[KP, KI, KD] = action_decode(max_column);
end
I have tried to declare the variable 'Q' in the model workspace (although it was already declared in the base workspace) but it didn't solve the problem.
Can anyone help me solve this issue? Thanks!
Declare Q global. See help global in MATLAB.
In this case, you need to 'declare' Q. You could do it going to Edit Data option and then Add Data. Follow the configuration options.
Another way is to define the signal in Simulink and give it as a parameter to the Matlab function.
By the way, it's a good practice to keep the read signals on the left side and out - on right. This improves a lot the readability.

Loop does not return correct values for piecewise function

I have tried to write a code, part of a bigger program, that would return value of z at every point of s. However, when I run the code I only get z=0, or if last else is ignored code returns zero vector.
Does someone have a clue where I made mistake? I have used method 1 from this source. Any help will be greatly appreciated, I have trying to get this work for months now.
% clc;close all; %// not generally appreciated
%initial values
b=1.25;
h=0.313;
%define the s coordinate
s= 0:0.001:2*(b+h);
%create zero matrix for speed
z=zeros(size(s));
%calculate z at every point of s coordinate
for i =length(s)
if 0 <= s(i) && s(i) <=b %0<=s<=b
z=0.5*h;
elseif b <= s(i) && s(i) <=(b+h) %b<=s<=(b+h)
z=0.5*h+((-0.5*h)/(b+h-b))*(s-b);
elseif b <= s(i) && s(i) <=(b+h) %(h+b)<=s<=(b+h)
z=-0.5*h;
elseif b <= s(i) && s(i) <=(b+h) %(h+2b)<=s<=(2b+2h)
z=-0.5*h+((-0.5*h)/(b+h-b))*(s-b);
else z=0;
end
end
For further reference, this solved my problem. Thank you #Dan!
%// initial values
b=1.25;
h=0.313;
%// define the s coordinate
s= 0:0.001:2*(b+h);
%// Create z
z = zeros(size(s));
idx1 = 0 <= s & s <=b;
idx2 = b <= s & s <=(b+h);
idx3 = (b+h) <= s & s <= (2*b+h);
idx4 = (2*b+h) <= s & s <=(2*b+2*h);
z(idx1) = 0.5*h;
z(idx2) = 0.5*h+((-0.5*h-0.5*h)/(b+h-b))*(s(idx2)-b);
z(idx3) = -0.5*h;
z(idx4) =-0.5*h+((0.5*h+0.5*h)/((2*b+2*h-b)-(h+b+b)))*(s(idx4)-b)
There are many issues with your code. You need to assign to an index of z otherwise you're just overwirting a scalar every time (i.e. z(i)=...). You need to loop over a vector so fori=1:length(s) and your last three loop conditions are identical!
%// initial values
b=1.25;
h=0.313;
%// define the s coordinate
s= 0:0.001:2*(b+h);
%// create zero matrix for speed
z=zeros(size(s));
%// calculate z at every point of s coordinate
for i = 1:length(s)
if 0 <= s(i) && s(i) <=b %// 0<=s<=b
z=0.5*h;
elseif b <= s(i) && s(i) <=(b+h) %// b<=s<=(b+h)
z(i)=0.5*h+((-0.5*h)/(b+h-b))*(s-b);
elseif (b+h) <= s(i) && s(i) <= (2*b+h) %// (h+b)<=s<=(2b+h)
z(i)=-0.5*h;
elseif (2*b+h) <= s(i) && s(i) <=(2*b+2*h) %// (h+2b)<=s<=(2b+2h)
z(i)=-0.5*h+((-0.5*h)/(b+h-b))*(s-b);
else z(i)=0;
end
end
With all the said, in MATLAB you don't even need a loop at all to do this and it is usually preferable not to use one:
%// initial values
b=1.25;
h=0.313;
%// define the s coordinate
s= 0:0.001:2*(b+h);
%// Create z
z = zeros(size(s));
idx1 = 0 <= s && s <=b;
idx2 = b <= s && s <=(b+h);
idx3 = (b+h) <= s && s <= (2*b+h);
idx4 = (2*b+h) <= s && s <=(2*b+2*h);
z(idx1) = 0.5*h;
z(idx2) = 0.5*h+((-0.5*h)/(b+h-b))*(s(idx2)-b);
z(idx3) = -0.5*h;
z(idx4) = -0.5*h+((-0.5*h)/(b+h-b))*(s(idx4)-b);
b=1.25;
h=0.313;
%define the s coordinate
s= 0:0.001:2*(b+h);
%create zero matrix for speed
z=zeros(size(s));
%calculate z at every point of s coordinate
for ii =1:length(s)
if 0 <= s(ii) && s(ii) <=b %0<=s<=b
z(ii)=0.5*h;
elseif b <= s(ii) && s(ii) <=(b+h) %b<=s<=(b+h)
z(ii)=0.5*h+((-0.5*h)/(b+h-b))*(s(ii)-b);
elseif b <= s(ii) && s(ii) <=(b+h) %(h+b)<=s<=(b+h)
z(ii)=-0.5*h;
elseif b <= s(ii) && s(ii) <=(b+h) %(h+2b)<=s<=(2b+2h)
z(ii)=-0.5*h+((-0.5*h)/(b+h-b))*(s(ii)-b);
else z(ii)=0;
end
end
Let your for loop run over more than 1 iteration, hence the for ii = 1:length(s).
Use allocation per element, thus z(ii) = some function
Don't use i as a variable.

Matlab wont quit using the cross sign in the waitbar when there is an out of bound exception for the image

The value for the columns is 51 and 50, but when we use anything more than that the waitbar freezes due to index out of bound exception since its a large image and it wont fit in there, so the matlab dosent shut using the waitbar or anything. Need a way to shut the matlab when it encounters any error.
h = waitbar(0,'Progress','Name','Calculating Feature Heights...',...
'CreateCancelBtn','setappdata(gcbf,''canceling'',1)');
setappdata(h,'canceling',0); %initiallizes waitbar
s1 = size(A);
s2 = size(B);
if (s1(1) < s2(1))
n = s1(1);
else
n = s2(1); % ensures that bounds of i are within the bounds of both images
end
for i = 21:1:n % sets bounds for rows
if getappdata(h,'canceling') %checks for user pushing the cancel button on the waitbar
break
end
waitbar(i/(n-1),h) %progress bar
for j = 61:1:(m-60) % sets bounds for columns
if A(i,j) == A(i,j-1) %if adjacent pixels are the same,
Z(i,j) = Z(i,j-1); %they have the same height
disp(i,j) = disp(i,j-l);
elseif A((i), j) == B(i, j) && A(i,j) ~= A(i,j-1) && A(i,j-1) == B(i,j-1)
Z(i,j) = Z0; %condiions for pixels/features in the 'focal plane'
disp(i,j) = 0;
else
for l = 1:1:20 %sets scan range in rows for disparity
for k = 1:1:60 %sets disparity scan range in cols
if (A(i,j) == B(i-l, j-k) && B(i-l, j-k-1) == B(i-l, j-k))
Z(i,j) = Z(i-l,(j-k-1)); %allows for multipixel features
disp(i,j) = disp(i-l,(j-k-1));
break
elseif (A(i, j) == B(i-l, j-k) && B(i-l, j-k-1) ~= B(i-l, j-k))
xA = [i j];
xB = [i-l j-k];
d = xB-xA;
Z(i,j) = Z0 - (fl*shift)/sqrt((d(1)^2)+(d(2)^2));
disp(i,j) = sqrt((d(1)^2)+(d(2)^2));
break
elseif (A(i,j) == B(i-l, j+k) && B(i-l, j+k-1) == B(i-l, j+k))
Z(i,j) = Z(i-l,(j+k-1));
disp(i,j) = disp(i-l,(j+k-1));
break
elseif (A(i, j) == B(i-l, j+k) && B(i-l, j+k-1) ~= B(i-l, j+k))
xA = [i j];
xB = [i-l j+k];
d = xB-xA;
Z(i,j) = Z0 - (fl*shift)/sqrt((d(1)^2)+(d(2)^2));
disp(i,j) = sqrt((d(1)^2)+(d(2)^2));
break
else
continue
end
end
end
end
end
end
delete(h)
Use a try/catch block.
try
% whatever that might error
catch
delete(h)
end

Plotting bisect method in matlab

So I had a problem in which I needed to find roots using the bisect method:
Function:
function [ c,k ] = bisect(f,a,b,tol)
k=0;
while b-a > tol
c=(a+b)/2;
if sign(f(c)) == sign(f(b))
b=c;
else
a=c;
end
k=k+1;
end
Script:
f = #(x) (((1800).*log((160000)./(160000 - (x.*2600))) - (9.812).*x)./750) - 1;
a = 10;
b = 50;
tol = 1e-4;
[root, iter] = bisect(f,a,b,tol);
fprintf(' iterations = %i root = %15.10e ' ,iter, root);
This works perfectly, now I need to use an embedded function in Matlab to find the value of c for different values of q (in the above example q is a fixed number 2600) from 2000 to 3000 in increments of 10 and plot x vs q. In order to do this I have the following script:
function myFunction
h = 10;
a = 10;
b = 50;
tol = 1e-4;
function y = f(x)
y = (((1800).*log((160000)./(160000 - (x.*q))) - (9.812).*x)./750) - 1;
end
for q = (2000:h:3000)
k=0;
while b-a > tol
c=(a+b)/2;
if sign(f(c)) == sign(f(b))
b=c;
cArray(q) = c;
else
a=c;
cArray(q) = c;
end
k=k+1;
end
end
plot(q,cArray)
end
This code has no errors but when I run it there is no graph. Can someone please help me with this issue? I don't even know if my code to find c vs q is correct.
Major issues with your myFunction code:
The endpoints a,b should be reset within the for loop, so that the root search begins anew.
Using q as index in cArray(q) results in a too-large array filled with zeros for indices below 2000. You need an index variable to keep track of that array. (I used j below)
plot(q,cArray) should be plot(2000:h:3000,cArray), because q is not an array, it's a scalar.
Minor issues:
You never used k
You assign to cArray(q) within the while loop; this only needs to be done once the loop has ran.
Corrected function:
function myFunction
h = 10;
tol = 1e-4;
function y = f(x)
y = (((1800).*log((160000)./(160000 - (x.*q))) - (9.812).*x)./750) - 1;
end
j = 0;
for q = 2000:h:3000
a = 10;
b = 50;
while b-a > tol
c=(a+b)/2;
if sign(f(c)) == sign(f(b))
b=c;
else
a=c;
end
end
j=j+1;
cArray(j)=c;
end
plot(2000:h:3000,cArray)
end
and its output:

How to chose random lines that hit a rectangular in MatLab

I am creating random starting and ending points. I want to plot those who cross/intersect with a rectangular which is placed at the origin. I found out that my code misses some lines, as shown in the figure. After that, I want to count were the tracks hit the rectangle. For expample the track came from top side and exited from right side etc.
My code is
function [hot, cold, h] = MuonTracks(tracks)%#eml
% NOTE: no variables larger than 1x1 are initialized
width = 1e-4;
height = 2e-4;
% constant used for Laplacian noise distribution
bL = 15 / sqrt(2);
% Loop through all tracks
X = [];
bhit= [];
hot = 0;
ii = 0;
TopBottom= 0;
LeftRight= 0;
TopRight= 0;
TopLeft= 0;
LeftBottom= 0;
RightBottom= 0;
ihit= 0;
while ii <= tracks
ii = ii + 1;
% Note that I've inlined (== copy-pasted) the original laprnd()
% function call. This was necessary to work around limitations
% in loops in Matlab, and prevent the nececessity of those HUGE
% variables.
%
% Of course, you can still easily generalize all of this:
% the new data
u = rand-0.5;
Ystart = 15;
Xstart = 80*rand-40;
Xend = Xstart - bL*sign(u)*log(1-2*abs(u));
%Xend=laprnd(tracks,1,Xstart,15);
b = (Ystart*Xend)/(Xend-Xstart);
% the test
if ((b < height && b > 0)) ||...
(Xend < width/2 && Xend > -width/2)
hot = hot+1;
% growing an array is perfectly fine when the chances of it
% happening are so slim
X = [X [Xstart; Xend]]; %#ok
bhit=b;
end
end
% This is trivial to do here, and prevents an 'else'
cold = tracks - hot;
% Now plot the chosen ones
h = figure;
hold all
%Y = bsxfun(#times, 15, ones(size(X)));
if (size(X)==0)
%Disp('No hits were found');
msgbox('No tracks were found','Result','warn');
elseif (size(X)>1)
Y = bsxfun(#times, [15; 0], ones(size(X)));
plot(X, Y, 'r');
msgbox( [num2str(hot) ' tracks were found'],'Result','help',num2str(hot));
else
Y = bsxfun(#times, [15; 0], ones(size(X)));
plot(X, Y, 'r');
msgbox( [num2str(hot) ' track was found'],'Result','help',num2str(hot));
end
%X;
%Y;
%size(X,2)
while ihit<size(X,2)
ihit=ihit+1
%X(2,ihit)
if ((X(2,ihit)==-width && (bhit<=0 && bhit<=height))&&(bhit==0 && (X(2,ihit)>=-width && X(2,ihit)>=width)))
LeftBottom=LeftBottom+1;
elseif ((bhit==height && (X(2,ihit)>=-width && X(2,ihit)>=width)) && (X(2,ihit)==width && (bhit<=0 && bhit<=height)))
TopRight=TopRight+1;
elseif ((bhit==height && (X(2,ihit)>=-width && X(2,ihit)>=width)) && (bhit==0 && (X(2,ihit)>=-width && X(2,ihit)>=width)))
TopBottom=TopBottom+1;
elseif ((X(2,ihit)==-width && (bhit<=0 && bhit<=height)) && (X(2,ihit)==width && (bhit<=0 && bhit<=height)))
LeftRight=LeftRight+1;
elseif ((X(2,ihit)==-width && (bhit<=0 && bhit<=height)) && (bhit==height && (X(2,ihit)>=-width && X(2,ihit)>=width)))
TopLeft=TopLeft+1;
elseif ((X(2,ihit)==width && (bhit<=0 && bhit<=height)) && (bhit==0 && (X(2,ihit)>=-width && X(2,ihit)>=width)))
RightBottom=RightBottom+1;
else
display('sth is wrong');
end
X(2,ihit)
end
%X(1,:);
%Y(1,:);
LeftBottom
TopRight
TopBottom
LeftRight
TopLeft
RightBottom
%display('sdfghjk');
end
Any ideas would be more than welcome!
Here you have a function that is capable of intersecting whole groups of segments and returning the intersection points. I hope it helps.