Saving a specific simulation time - matlab

I have a two-track model implemented in simulink. To control the velocity I use a PID-controller, so that the the output of the velocity looks like this:
now I want to implement a MATLAB function or simulink block that tracks the time when the velocity reaches a steady-state-behaviour and puts it into some kind of storage. I tried to implement something like this via the following MATLAB function with MATLAB-function-block:
function y = fcn(t,v,dv,tv)
%#codegen
if (v==tv+0.01) & (dv<0)
y=t
end
t is the clock-signal, v the velocity, dv the first derivation of the velocity and tv is the targetvelocity. The problem about this function is that there "y is not defined on some execution paths". do you have any ideas how to make this work?

I solved the problem without a MATLAB function using the simulink blocks data store memory and its read & write blocks. The signal that is coming in from bottom right side is the momentary velocity. The if statement is
(u1 >= 22.2) & (u1<=22.3) & (u2<0)
Since simulink is using time steps and the momentary velocity will never be exactly 22.2, you can not use u1==22.2

In SimuLink add a second output and a fifth input to your function. Then use that new output as a feedback to the function.
function [y, output] = fcn(t,v,dv,tv,input)
y = 0;
output = input;
if (v == tv + 0.01) && (dv < 0)
y = t;
if (input == -1)
output = t;
end
end
Attach the output to an IC block where you set the input initial value to -1 or whatever value you want to use. Then attach the IC block to the input of the function. output will be feedback constantly through the function. Once it's set it will reatin it's value forever.

function y = fcn(t,v,dv,tv)
%#codegen
y = zeros(length(t),1); % Initialise the array
for ii = 1:length(t)
if (v==tv+0.01) & (dv<0)
y(ii)=t;
else
y(ii)=0;
end
end
y(y==0)=[];
end
Two changes: added a semicolon after y=t to force it to not print it every time it is set. Second, your question, else y=[];, which means that y will be an empty matrix if you do not adhere to your if statement.
It now stores a 0 each time you do not adhere to the if statement. The line y(y==0)=[]; deletes all zeros, comment this line if you want your y to be the same length as the input variables.
function y = fcn(t,v,dv,tv)
%#codegen
y = zeros(length(t),1); % Initialise the array
ii=1;
while exist(t)
if (v==tv+0.01) & (dv<0)
y(ii)=t;
else
y(ii)=0;
end
ii = ii+1;
end
y(y==0)=[];
end

Related

Checking how function has been called in MATLAB

I have a task to write a function that has an optional output argument.
Let's say I have a function y = fun(a,b). From what I understood, depending on whether the user needs the value y, it will EITHER calculate y OR draw some diagram.
So I think it means that if user calls my function like this: z = fun(1,2), then it calculates y and returns it, but if he calls it like this: fun(3,4);, then it won't return anything and draw a diagram instead.
Is there any way to check how my function has been called inside it? If yes, then how?
You can use nargout here:
function y = q61527462(a,b)
if nargout > 0
% Calculate y
y = a + b;
else
% Plot
plot(a,b)
end
end
so when you call the function as:
>> y = q61527462(1,2)
you get:
y =
3
and when you call with:
>> q61527462(1,2)
you get the plot
Have a look at nargout, that roughly translates to number of argument to output (there is also a nargin to check the number of input arguments).
However, the function will return the return-value anyway if your just check for nargin. You will also need to use varargout (variable argument output) to make your function return something only if the output will be assigned to some external variable.
So you just write in your function
function varargout = fun()
if nargout % implicit cast to a logical. It is equivalent to nargout > 0
% return output
varargout{1} = true; % note that this requires to wrap your output in a cell
else
% do plotting
end
EDIT:
It is even not necessary to use varargout. If you don't assign a value to a return-variable, it won't appear. So MATLAB can manage a not-assigned return-variable (something I was surprised to learn myself^^). This even works with multiple outputs!

How to change a script to a function?

I've got a set of data in an excel sheet that I've imported onto MATLAB however there are NaNs within that set of data. I've figured out some code in the main script to replace the NaN's into the wanted values:
max = x(:, 2);
min = x(:, 3);
for j = 1:length(max)
for k = 1:length(min)
if isnan (max(j))
max (j) = ((max(j-1)+max(j+1))/2);
elseif isnan (min(k))
min (k) = ((min(k-1)+min(k+1))/2);
end
end
end
However, I need to be able to turn this code into a user-defined function and call it from the main script instead of having all the calculations on the main script.
I've tried to start making the function:
function [missingmax, missingmin] = missing(max, min)
However, I could not figure the rest out.
function [max_x, min_x] = missing(x)
max_x = x(:, 2);
min_x = x(:, 3);
for jj = 1:length(max_x)
for kk = 1:length(min_x)
if isnan (max_x(jj))
max_x (jj) = ((max_x(jj-1)+max_x(jj+1))/2);
elseif isnan (min_x(kk))
min_x (kk) = ((min_x(kk-1)+min_x(kk+1))/2);
end
end
end
end
You were on the right track. Couple of things:
Your input is x, not min,max
Your outputs are min and max, not missingmax and missingmin
j denotes the imaginary unit It's not recommended for use as a variable, hence I changed it.
You called variables min and max. Don't do that. Ever. Seriously. Don't. If you manage to do min=4 and then try to calculate the minimum of an array, you'll get a bunch of errors. Basically: never use the name of a build-in function for a variable.
Since you do a linear interpolation, you don't need to define a function here. It already exists in Matlab : fillmissing
So you can replace missing values in x like that
x_filled = fillmissing(x,'linear')

How do I adjust this code so that I can enter how many runs I want and it will store each run in a matrix?

I have created this code to generate a 1 set of lottery numbers, but I am trying to make it so that the user can enter how many sets they want (input n), and it will print out as one long matrix of size nX6? I was messing around with a few options from online suggestions, but to no avail. I put the initial for i=1:1:n at the beginning, but I do not know how to store each run into a growing matrix. Right now it still generates just 1 set.
function lottery(n)
for i=1:1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
m=1;
lottonum1=floor(ylow+rand*(yhigh-ylow+1));
z = horzcat(lottonum, lottonum1);
end
disp('The lotto numbers picked are')
fprintf('%g ',z)
disp (' ')
The problem is that you are not storing or displaying the newly generated numbers, only the last set. To solve this, initialize z with NaNs or zeros, and later index z to store each set in a row of z, by using z(i,:) = lottonum.
However, you are using i as iterator in the while loop already, so you should use another variable, e.g. k.
You can also set z as an output of the function, so you can use this matrix in some other part of a program.
function z = lottery(n)
% init z
z = NaN(n,6);
for k = 1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
lottonum1 = floor(ylow+rand*(yhigh-ylow+1));
z(k,:) = horzcat(lottonum, lottonum1); % put the numbers in a row of z
end
disp('The lotto numbers picked are')
disp(z) % prettier display than fprintf in this case.
disp (' ')
end
The nice answer from rinkert corrected your basic mistakes (like trying to modify your loop iterator i from within the loop => does not work), and answered your question on how to store all your results.
This left you with a working code, however, I'd like to propose to you a different way to look at it.
The porposed architecture is to divide the tasks into separate functions:
One function draw_numbers which can draw N numbers randomly (and does only that)
One function draw_lottery which call the previous function as many times as it needs (your n), collect the results and display them.
draw_lottery
This architecture has the benefit to greatly simplify your main function. It can now be as simple as:
function Draws = draw_lottery(n)
% define your draw parameters
xmin = 1 ; % minimum number drawn
xmax = 69 ; % maximum number drawn
nballs = 5 ; % number of number to draw
% pre allocate results
Draws = zeros( n , nballs) ;
for iDraw=1:1:n
% draw "nballs" numbers
thisDraw = draw_numbers(xmin,xmax,nballs) ;
% add them to the result matrix
Draws(iDraw,:) = thisDraw ;
end
disp('The lotto numbers picked are:')
disp (Draws)
disp (' ')
end
draw_numbers
Instead of using a intricated set of if conditions and several iterators (i/m/k) to branch the program flow, I made the function recursive. It means the function may have to call itself a number of time until a condition is satisfied. In our case the condition is to have a set of nballs unique numbers.
The function:
(1) draws N integer numbers randomly, using randi.
(2) remove duplicate numbers (if any). Using unique.
(3) count how many unique numbers are left Nu
(4a) if Nu = N => exit function
(4b) if Nu < N => Call itself again, sending the existing Nu numbers and asking to draw an additional N-Nu numbers to add to the collection. Then back to step (2).
in code, it looks like that:
function draw = draw_numbers(xmin,xmax,nballs,drawn_set)
% check if we received a partial set
if nargin == 4
% if yes, adjust the number of balls to draw
n2draw = nballs - numel(drawn_set) ;
else
% if not, make a full draw
drawn_set = [] ;
n2draw = nballs ;
end
% draw "nballs" numbers between "xmin" and "xmax"
% and concatenate these new numbers with the partial set
d = [drawn_set , randi([xmin xmax],1,n2draw)] ;
% Remove duplicate
drawn_set = unique(d) ;
% check if we have some more balls to draw
if numel(drawn_set) < nballs
% draw some more balls
draw = draw_numbers(xmin,xmax,nballs,drawn_set) ;
else
% we're good to go, assign output and exit funtion
draw = drawn_set ;
end
end
You can have both functions into the same file if you want.
I encourage you to look at the documentation of a couple of Matlab built-in functions used:
randi
unique

Matlab gui with pause function

I am using the GUIDE for matlab gui.
The gui built in order to communicate with keithley current measurement device through GPIB.
When using a toggle button for Current measurement while loop, i am using a pause() function inside the while loop for each iteration and a ytranspose on the y array reading results.
function Measure_Callback(hObject, eventdata, handles)
global GPIB1
global filename
global timeStep
disp('Measurement in progress \n stopwatch starts!');
tic
x=0;
n=0;
while get(hObject,'Value')
fprintf(GPIB1, 'printnumber(smua.measure.i(smua.nvbuffer1))');
fprintf(GPIB1, 'printbuffer(1,1,nvbuffer1)');
A = fscanf(GPIB1);
if length(A)<20
x = x+1;
n = n+1;
t(n) = toc ;
y(x) = str2double(A);
plot(t,y,'-bo',...
'LineWidth',2,...
'MarkerEdgeColor','k',...
'MarkerFaceColor',[.49 1 .63],...
'MarkerSize',10);
grid on
hold on
end
title('Current vs Time','FontSize', 15)
xlabel('Time [s]','FontSize', 15)
ylabel('Current [A]','FontSize', 15)
a = timeStep;
pause(a)
end
disp('Measurement terminated');
disp('Elapsed time: ');
elapsedtime = toc;
elapsedtime_string = num2str(elapsedtime);
disp(elapsedtime_string);
ytrans = transpose(y);
csvwrite(filename,ytrans);
fprintf(GPIB1, 'smua.source.output = smua.OUTPUT_OFF');
For the pause function i'm geting error:
?? Error using ==> pause Error while evaluating uicontrol Callback
For the transpose(y) function i'm also getting a error:
its undefined y.
Cant understand why are those errors and could use some help.
Thank you!
First off, as people say, post the errors and the code. Do you know if length(A) is smaller than 20 in the first time you run the loop? Because if not, A is not defined and you can't transpose something that is not there. Initialize A before the loop to something and see if the error persists (or print out length(A) to make sure the loop gets entered the first run).
As for the pause error, make sure pause is an int or double, not a string. If you get your global timeStep from the GUI field, it is probably a string and you need to covert it to double first.

How to get value of Eccentricity from struct of Eccentricity in MATLAB?

I want to print Eccentricity of each connected component of my image and following is part of my code:
[B,L] = bwboundaries(bw,'noholes');
stats = regionprops(L,'Eccentricity');
for k = 1:length(stats)
stats(k);
end
But it doesn't really print any thing on output console. I want to get Eccentricity of each component on console.
And I want to store the float value of Eccentricity of each component in new one dimensional array so how do I do it ?
The ; in MATLAB suppresses the output of the executed line, and unlike most other languages is not required to terminate the end of a line. The easy way to "fix" this is to remove the ; from the for loop:
for k = 1:length(stats)
stats(k)
end
But it's a best practice to always have a ; at the end of every line. Rather than display this way, consider using disp() instead:
for k = 1:length(stats)
disp(stats(k));
end