I am trying to mimic the behavior of MATLAB's Simulink relay block with just MATLAB code.
My code is as follows (not familiar with persistent variable? click) :
function out = fcn(u,delta)
persistent y;
if isempty(y)
y = 0;
end
if u >= delta
y = 1;
elseif u <= -delta
y = 0;
end
out = y;
When I look to the output and compare with the real relay block I see :
Where does the difference come from?
Both blocks insert the same sample time, does the relay block have something extra to show the discontinuity?
Simulink block diagram download
I'm not quite sure about this explanation, maybe somebody can support it.
The MATLAB function Block does not support Zero-Crossing Detection, the Relay Block does. That means the latter knows in advance, when your sine will reach the threshold delta and sets the output accordingly to the correct time. The MATLAB function Block needs 2 or more steps to detect the slope (respectively the crossing of the threshold). So from one step to another it realizes that the condition for the new output was set and updates the output and you get a ramp, not a step.
C/C++ S-Functions do have Zero-Crossing Detection - though it seems quite complicated.
Related
I have the model of a dynamic system in Simulink (I cannot change the programming framework). It can be described as an oscillator subject to periodic oscillations. I am trying to control its motion, in particular, to maximize it (for energy generation).
With latching control (a popular control strategy), the idea is to 'latch', i.e. lock in place, the device when its velocity is 0 for a predefined time, and then release it until its velocity reaches 0 again.
So, what I need to do in Simulink is to output a signal 1 once the velocity signal reaches (or is close to) 0, hold it constant for a time period (at 1), then release it (the signal becomes 0), and repeat the process once the velocity reaches 0 again.
I have found a good blog on holding signals constant in Simulink:
http://blogs.mathworks.com/simulink/2014/08/06/how-do-you-hold-the-value-of-a-signal/
However, in my case, I have two conditions for determining the signal: the magnitude of the velocity and the time within the time period. Now, the problem is that as soon as the period is finished, and the device is released (signal = 0), the velocity is still very small, which could result in an incorrect signal of 1 if an if-loop is used.
I think using an S-function may be the best solution, but then I will have to use a fixed time-step. Are there any Simulink-native solutions for this problem?
I ended up using a Matlab function as a temporary solution, and it is very effective. I have taken inspiration from https://uk.mathworks.com/matlabcentral/answers/11323-hold-true-value-for-finite-length-of-time
u is the velocity signal.
function y = fcn(u,nlatch)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This function is used to determine the latching signal.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Using persistent memory:
persistent tick started sign;
% Initialize variables:
if isempty(tick)
tick = 0;
started = 0;
sign = (u>0);
end
U=0; % no latching
s=(u>0);
if s~=sign
started = 1;
end
if started
if tick<nlatch
tick=tick+1;
U = 1;
else
tick = 0;
started = 0;
sign = s;
end
end
y = U;
end
However, as I mentioned, I have to use a fixed step solver, which is no big deal to me, but it can create problems to other users.
If anyone has a more "Simulink-native" solution, please let me know!
Edit
I have now modified the function: the latching is now applied when there is a change in sign in the velocity signal rather than looking at a small magnitude as earlier on (abs(u)<0.005), which was too case-specific.
A colleague of mine has also found a Simulink-native solution:
However, the Matlab function is faster (less computing intensive) when the same time step is employed. Maybe the least computing-intensive solution is a C S-function.
I have one "Thermal Mass" block in Simulink, which represents a thermal mass, which is the ability of a material or combination of materials to store internal energy. In this standard block of Simulink, the initial temperature must be entered. Only one signal can be connected to the block. The source code of the block looks like following:
component mass
% Thermal Mass
% The block represents a thermal mass, which is the ability of a material
% or combination of materials to store internal energy. The property is
% characterized by mass of the material and its specific heat.
%
% The block has one thermal conserving port.
% The block positive direction is from its port towards the block. This
% means that the heat flow is positive if it flows into the block.
% Copyright 2005-2013 The MathWorks, Inc.
nodes
M = foundation.thermal.thermal; % :top
end
parameters
mass = { 1, 'kg' }; % Mass
sp_heat = { 447, 'J/(kg*K)' }; % Specific heat
end
variables
Q = { 0, 'J/s' }; % Heat flow
end
variables(Conversion=absolute)
T = { 300, 'K' }; % Temperature
end
function setup
% Parameter range checking
if mass <= 0
pm_error('simscape:GreaterThanZero','Mass')
end
if sp_heat <= 0
pm_error('simscape:GreaterThanZero','Specific heat')
end
end
branches
Q : M.Q -> *;
end
equations
T == M.T;
Q == mass * sp_heat * T.der;
assert(T>0, 'Temperature must be greater than absolute zero')
end
end
I would like to build another component, whose initial temperature can come from another block, so that it can be also calculated somewhere else. So, one input parameter and everything else should be the same. I am new to Simulink and don't know much about the domains. Any idea, how this can be done?
Thank you!
Parameters entered on a Simulink block are usually utilized for initial values and tuning of block behavior. While newer versions of Simulink will allow you to tune some parameters during simulation, others will be locked down and un-modifiable. This may mean that you need to first execute a model to calculate the initial value for your Thermal Mass, and then start up a second simulation using that temperature as an initial value.
I believe the Simulink help on how to control block parameters will be useful. Depending on the specific design of your model, different techniques found here may be more or less applicable, but generally speaking I know of 2 easy and simple ways to accomplish modifying a mask value.
Set the value to a variable in your Matlab base workspace.
Place the block inside a Masked subsystem. The mask can be used to define a variable that accessible to all the blocks inside it.
This is not possible, while you can execute some pre-processing to determine initial temperature you can not have this as an input from other blocks.
The workaround described by Jared is probably what you're looking for.
It's actually pretty rare to need to do this, if you tell us why you'r looking to set this up, we may be able to help.
I need a Simulink block or a group of blocks to make peak detection: compare each value of an input stream to its previous and post values. If it's larger than the previous AND larger than the next value, output this value.
I've tried to do it with a Matlab Function Block, but I cannot make the required delay. I mean it's not possible, as far as I tried, to store previous values for example.
So, what should I do?
Update: Another example
In responding to the comments, suggested solutions are helpful if I'm dealing with discrete values. So here is another example to represent my need:
A Schmidt Trigger
I need to implement a Matlab function to implement the given scenario. I can do something like
if u >= 2
y = 3;
elseif (u < 2)
y = -3;
But still this is not correct as I need to look at the previous value (hysteresis) of the input, other wise I'll end up having something like the following
PS: I know there is nothing called previous value in analog, but we all know that Simulink is dealing with analog values as a discrete in the end (much larger sampling). So I think maybe there is a way to do it.
I think your code is fine except for one minor mistake:
if u > 2
y = 3;
elseif u < -2
y = -3;
else
y = u;
The variable 'u' in elseif part should get compared with the -2 (upper threshold but with a negative sign)
Hope it helps!
I have an ODE for calculating how acidicity changes. Everything is working just fine, only I would like to change a constant whenever acidicity reaches a critical point. It is supposed to be some kind of irreversible effect I wish to simulate.
My constants are coming from a structure file (c) I load once in the ODE function.
[Time,Results] = ode15s(#(x, c) f1(x, c),[0 c.length],x0,options);
The main problem I have here is not telling Matlab to change the constant but remember if it happened already during the simulation once. so Matlab should take the irreversibly changed constant rather than the one I supply at the beginning.
I would like to write a flag that is saved while the ODE is running and an if condition, "if flag exists, change constant". How to do that?
UPDATE I:
PROBLEM SOLVED
Here a first own solution, it is not polished and requires a structure file approach. Which means, the constants which should suddenly changed upon an event, must be struct files which are handed in the ODE function into the function that should be evaluated (look above for the ODE syntax). The function accepts the inputs like this:
function [OUTPUT] = f1(t, x, c)
% So here, the constants all start with c. followed by the variable name. (because they are structs instead of globals)
%% write a flag when that event happens
if c.someODEevent <= 999 && exist ('flag.txt') == 0
dlmwrite ('flag.txt',1);
end
%% next iteration will either write the flag again or not. more importantly, if it exists, the constant will change because of this.
if exist ('flag.txt') == 2
c.changingconstant = c.changingconstant/2;
end
end
Please look into Horchlers kind answer where you have to take care that such a step may introduce inaccuracies and you have to be careful to check if your code does what it is supposed to do.
To do this accurately, you should use event detection within the ODE solver. I can't give you a specific answer because you've only provided the ode15s call it in your question, but you'll need to write an events function and then specify it via odeset. Something like this:
function acidity_main
% load c data
...
x0 = ...
options = odeset('Events',#events); % add any other options too
% integrate until critical value and stop
[Time1,Results1] = ode15s(#(x,c)f1(x,c),[0 c.length],x0,options);
x0 = Results(end,:); % set new initial conditions
% pass new parameters -it's not clear how you're passing parameters
% if desired, change options to turn off events for faster integration
[Time2,Results2] = ode15s(#(x,c)f1(x,c),[0 c.length],x0,options);
% append outputs, last of 1 is same as first of 2
Time = [Time1;Time2(2:end)];
Results = [Results1;Results2(2:end,:)];
...
function y=f1(x,c)
% your integration function
...
function [value,isterminal,direction] = events(x,c)
value = ... % crossing condition, evaluates to zero at event condition
isterminal = 1; % stop integration when event detected
direction = ... % see documentation
You'll want to use the events to integrate right to the point where the "acidicity reaches a critical point" and stop the integration. Then call ode15s again with the new value and continue the integration. This may seem crude, but it how this sort of thing can be done accurately.
You can see an example of basic event detection here. Type ballode in your command window to see the code for this. You can see a slightly more complex version of this demo in my answer here. Here's an example of using events to accurately change an ODE at specified times (rather than your case of specified state values).
Note: I find it strange that you're passing what you call "constants", c, as the second argument to ode15s. This function has strict input argument requirements: the first is the independent variable (often time), and the second is the array of state variables (same as your initial condition vector). Also if f1 only takes two arguments, #(x,c)f1(x,c) is superfluous – it's sufficient to pass in #f1.
I have written the following code in MATLAB to process large images of the order of 3000x2500 pixels. Currently the operation takes more than half hour to complete. Is there any scope to improve the code to consume less time? I heard parallel processing can make things faster, but I have no idea on how to implement it. How do I do it, given the following code?
function dirvar(subfn)
[fn,pn] = uigetfile({'*.TIF; *.tiff; *.tif; *.TIFF; *.jpg; *.bmp; *.JPG; *.png'}, ...
'Select an image', '~/');
I = double(imread(fullfile(pn,fn)));
ld = input('Enter the lag distance = '); % prompt for lag distance
fh = eval(['#' subfn]); % Function handles
I2 = uint8(nlfilter(I, [7 7], fh));
imshow(I2); % Texture Layer Image
imwrite(I2,'result_mat.tif');
% Zero Degree Variogram
function [gamma] = ewvar(I)
c = (size(I)+1)/2; % Finds the central pixel of moving window
EW = I(c(1),c(2):end); % Determines the values from central pixel to margin of window
h = length(EW) - ld; % Number of lags
gamma = 1/(2 * h) * sum((EW(1:ld:end-1) - EW(2:ld:end)).^2);
end
The input lag distance is usually 1.
You really need to use the profiler to get some improvements out of it. My first guess (as I haven't run the profiler, which you should as suggested already), would be to use as little length operations as possible. Since you are processing every image with a [7 7] window, you can precalculate some parts,
such that you won't repeat these actions
function dirvar(subfn)
[fn,pn] = uigetfile({'*.TIF; *.tiff; *.tif; *.TIFF; *.jpg; *.bmp; *.JPG; *.png'}, ...
'Select an image', '~/');
I = double(imread(fullfile(pn,fn)));
ld = input('Enter the lag distance = '); % prompt for lag distance
fh = eval(['#' subfn]); % Function handles
%% precalculations
wind = [7 7];
center = (wind+1)/2; % Finds the central pixel of moving window
EWlength = (wind(2)+1)/2;
h = EWlength - ld; % Number of lags
%% calculations
I2 = nlfilter(I, wind, fh);
imshow(I2); % Texture Layer Image
imwrite(I2,'result_mat.tif');
% Zero Degree Variogram
function [gamma] = ewvar(I)
EW = I(center(1),center(2):end); % Determines the values from central pixel to margin of window
gamma = 1/(2 * h) * sum((EW(1:ld:end-1) - EW(2:ld:end)).^2);
end
end
Note that by doing so, you trade performance for clearness of your code and coupling (between the function dirvar and the nested function ewvar). However, since I haven't profiled your code (you should do that yourself using your own inputs), you can find what line of your code consumes the most time.
For batch processing, I would also recommend to leave out any input, imshow, imwrite and uigetfile. Those are commands that you typically call from a more high-level function/script and that will force you to enter these inputs even when you want them to stay the same. So instead of that code, make each of the variables they produce (/process) a parameter (/return value) for your function. That way, you could leave MATLAB running during the weekend to process everything (without having manually enter to all those values), even if you are unable to speed up the code.
A few general purpose tricks:
1 - use the MATLAB profiler to determine all the computational bottlenecks
2 - parallel processing can make things faster and there are a lot of tools that you can use, but it depends on how your entire code is set up and whether the code is optimized for it. By far the easiest trick to learn is parfor, where you can replace the top level for loop by parfor. This does mean you must open the MATLAB pool with matlabpool open.
3 - If you have a rather recent Nvidia GPU as well as MATLAB 2011, you can also write some CUDA code.
All in all 30 mins to me is peanuts, so don't fret it too much.
First of all, I strongly suggest you follow the advice by #Egon: Write a separate function that collects a list of files (the excellent UIPICKFILES from the FEX is your friend here), and then runs your filtering code in a loop for each image. Note that you should definitely keep the call to imwrite in your filtering code: In case the analysis crashes at image 48 (e.g. due to power failure), you don't want to lose all the previous work.
Running thusly in batch mode has two big advantages: (1) you can start running your code and go home for the week-end, and (2) you can easily parallelize this outside loop using PARFOR. However, with only a dual-core machine, it is unlikely that you get any significant improvements from parallelization - your OS also wants to run stuff at times, and the overhead of parallelization might be more than the gain from running two workers. Also, 2.5GB of RAM is seriously limiting.
As to your specific code: in my experience using IM2COL is often faster than NLFILTER. im2col creates a nElementsInMask-by-nMasks array out of your image, so that you can apply the filtering in one single operation. With a 7x7 window, the output of im2col will be 3000*2500*49 bytes, which is close to 400MB. Thus, it should just work. All that you need to do is rewrite ewvar so that it works on a 49x1 array of pixels that make up the pixels your mask, which will require some index juggling, if I understand your code correctly.