Simulink - Output 1 every 30 seconds, 0 otherwise - matlab

I need a subsystem that needs to output 1 at interval or 30 seconds or slightly over 30 seconds.
Written in matlab code it should work like that
function y = fcn(time,uplinkTimeInterval)
%#codegen
persistent lastTriggerTime
if isempty(lastTriggerTime)
lastTriggerTime = 0;
end
if time>=lastTriggerTime || time == 0
y = 1;
lastTriggerTime = time + uplinkTimeInterval;
else
y = 0;
end
end
where ulplinkTimeInterval is 30 seconds. Of course I tried to use the matlab function block with this code but for some reason it does not work (in debug mode I can see that y takes value 1 as it should but it simply does not ouput the value outside the block), therefore I wanted to use blocks but I do not know how to do it.
Thanks very much for your help

You can make this logic relatively easily with code or blocks. As you requested a solution using blocks, here it is!
Use the clock block to keep track of time, and some constant block to determine the interval (in seconds) at which to give 1 instead of 0.
Use the memory block to delay the clock signal by 1 timestep, so we can compare consecutive steps' values.
Divide the times by the interval, and round down, to give how many intervals have passed.
Finally, compare consecutive "number of intervals passed" using a relational operator. If more intervals have passed on the upper line, then you have just stepped over the interval threshold.
Note: this will return a 0 for every timestep where you have not crossed a new interval, and a 1 at each individual timestep where you have. The accuracy of the output will depend on the step size of your model.
Edit: It may be clearer / easier to just add the memory block after the floor block, so you are only doing the division / rounding once. It would still allow you to do a comparison to the previous time step. That would look like:

Easiest way to do this is with a just a single Pulse Generator block, set to have a "high" of 1 every 30 seconds. That is shown as part of the image below. The signal will be high for whatever the percentage of the period is specified in the block dialog.
If for some reason you really need to use a subsystem then use a Triggered and Enabled Subsystem (See top right of image). Feed the same pulse signal into both the trigger and the enable port, and set the outport inside the subsystem to have Output when disabled to reset, and to have an Initial Output of 0 (See the lower right of the image).
The model below shows how to do this. In this instance the pulse has been set to have a period of 30s with the rising edge happening every 1% of that period (See the top left of the image).
The output signal will be high for one time step every time the input rises (assuming the trigger is set to rising edge.)

Related

MATLAB SIMULINK implementing a discrete increment/decrement counter?

I have a signal which will be either 1,0 or -1 for a discrete time interval (say 10s) then change depending on other parameters. I want a counter to keep a running count of an Initial Value modified by the input signal.
example:
t0->t1, input=1, output=initialvalue+1
t1->t2, input=0, output=initialvalue+1
t2->t3, input=1, output=(initialvalue+1)+1
t3->t4, input=-1, output=((initialvalue+1)+1)-1
etc. Ideally I would want this to work for input being any integer but I'll take what I can get...
There's a counter block but it only counts up or down, not both. I tried using edge detection but I'm not sure how to implement the discrete counter on which it operates. Any help highly appreciated.

Is it possible to stop a Simulink simulation when a certain condition is met?

Assume that you have a Simulink simulation where a certain signal is first positive and after some time t in a given interval, it becomes negative. Your goal is to find the zero-crossing.
A first approach would be to plot the signal over the given interval, save it and calculate the zero-crossing.
When repeating this simulation numerous times for varying parameters, it would be beneficial to be able to stop the simulation after the signal has become negative. Then there is already enough information for the calculation of the zero-crossing in Matlab. How could you do that?
Yes, use the Stop Simulation block with the appropriate logical input to the block:
You can use an if / else block to control the flow in the Simulink model. In the if / else block, you can choose the condition if u > 0, continue as normal if it's true, and use the else-option to bypass the rest of the flow you would otherwise run. For instance jump directly to the scope.
Another ways:
You can use Hit Crossing Block in Simulink to find time at the moment of hitting zero.
Another way - use any Trigger or Resettable system. It detects the zero crossing too. For example: this question at SO.
Of course you can also use User Defined function to detect zero crossing by your hand and do whatever you want with the signal at the same time.
About making a lot of simulations and then stops:
you can use Check Upper Static Bound for automatically stops simulation at the moment when zero will be crossed in nth time. For example:
I set upper bound = 10 for this block and this stops at 10th crossing.
There are a lot of ways to save function values in this points or just array of times but this is an another question :)

Scope displays unexpected puls generator output

I am having troubles understanding the output of my scope in this simple simulink model:
I am using a fixed step solver (tried with ode3 and ode8).
Pulse type of the puls generator is set to Sample based and I varied the Period and Pulse Width.
First I set the simulation time to 10 and set the puls generator to Period = 10 and Puls width = 5. The output of the scope is as expected:
But when I tried with simulation time 10,000 and the puls generator with Period = 1,000 and Puls width = 500 it seems my scope is wrong:
Why is the first falling edge at 5,500? I used the Autoscale button every time.
Using sim time 100,000 and Period = 10,000 and Puls width = 5,000 I don't even get a single falling edge:
Even with longer simulation time there seems to be a single rising edge at the end of the scope window.
What am I doing wrong? Is the scope not suitable for such long simulation times using fixed step solver? Or is it not "safe" to use the Autoscale button?
All of the plots you show are correct. Simulink is fine with long simulation times. It is "safe" to use the Autoscale button.
By default a scope is set to only display the last 5000 simulation time steps. Since your model is taking a step size of 1s (this is based on using the default step size of the Pulse Generator, which is 1s), in your second plot you are only seeing points from t=5000 to t=10000 (so the first down step in that time period is at 5500), and in your third plot you are only seeing points from t=95000 to t=100000 (which is a period in which the value of the pulse is low/zero).
To see all simulation times, open the Scope block's parameters (by clicking the button with a picture of a cog on it), go to the History tab, and deselect the Limit data points to last: check box.
Then rerun your simulation and press the autoscale button. You'll then see what (I think) you are expecting.

Simulink and Monoflops

I'm using Matlab 7 and have a problem in creating a monoflop which shall raise for a specific time to "1" and after that time fall to "0". How can I do this with Matlab/Simulink 7?
I don't have any other version, so I can't use the "Monostable" Block from newer versions.
Any ideas?
greets, poeschlorn
There are a couple of ways to do this, depending on whether or not you want the pulse (i.e. "monoflop") to occur at a predetermined time or in response to another signal (like a rising edge)...
Creating a pulse at a predetermined time:
If you want to create a single pulse that steps from 0 to 1 at time tOnset, then steps back to 0 after a time tDur has elapsed, you can do this using a Step block, a Transport Delay block, and a Sum block. Here is what the layout would look like:
You would set the Step time of the Step block to tOnset, the Time delay of the Transport Delay block to tDur, and then subtract the delayed signal from the original signal.
Creating a pulse in response to a rising edge:
This is will be a bit more complicated. It will require two Detect Increase blocks, a Relay block, a Transport Delay block, a Gain block, and a Sum block. Here's what the layout would look like:
Assuming your input signal is either a 1 or a 0, the first Detect Increase block will output a 1 when the input steps from 0 to 1. By setting the Switch on point to 0.5 and the Switch off point to -0.5 for the Relay block, this will create hysteresis in the Relay such that the output will persist in the "on" state (i.e. an output of 1) after the brief pulse that occurs when the rising edge is detected.
To get the Relay block to switch back into the "off" state (i.e. an output of 0) after a specified time tDur, you would set the Time delay of the Transport Delay block to tDur. The Detect Increase block in the feedback loop will output a 1 when the delayed signal steps from 0 to 1, and this output will then be scaled by setting the Gain of the Gain block to 2.
When subtracted from the input signal, this gain will ensure that the output from the Sum block can be pulled below -0.5 no matter what the positive input is (0 or 1), thus ensuring that the Switch off point of the Relay block is reached and its output is turned off when the delayed signal has a rising edge (i.e. after tDur has elapsed). One result of this is that any additional rising edges occurring in the model input after the first rising edge and during the time tDur will be ignored. Once the output from the model returns to 0, the next rising edge on the model input will trigger another pulse.

Measuring Frequency of Square wave in MATLAB using USB 1024HLS

I'm trying to measure the frequency of a square wave which is read through a USB 1024 HLS Daq module through MATLAB. What I've done is create a loop which reads 100 values from the digitial input and that gives me vector of 0's and 1's. There is also a timer in this loop which measures the duration for which the loop runs.
After getting the vector, I then count the number of 1's and then use frequency = num_transitions/time to give me the frequency. However, this doesn't seem to work well :( I keep getting different frequencies for different number of iterations of the loop. Any suggestions?
I would suggest trying the following code:
vec = ...(the 100-element vector of digital values)...
dur = ...(the time required to collect the above vector)...
edges = find(diff(vec)); % Finds the indices of transitions between 0 and 1
period = 2*mean(diff(edges)); % Finds the mean period, in number of samples
frequency = 100/(dur*period);
First, the code finds the indices of the transitions from 0 to 1 or 1 to 0. Next, the differences between these indices are computed and averaged, giving the average duration (in number of samples) for the lengths of zeroes and ones. Multiplying this number by two then gives the average period (in number of samples) of the square wave. This number is then multiplied by dur/100 to get the period in whatever the time units of dur are (i.e. seconds, milliseconds, etc.). Taking the reciprocal then gives the average frequency.
One additional caveat: in order to get a good estimate of the frequency, you might have to make sure the 100 samples you collect contain at least a few repeated periods.
Functions of interest used above: DIFF, FIND, MEAN
First of all, you have to make sure that your 100 samples contain at least one full period of the signal, otherwise you'll get false results. You need a good compromise of sample rate (i.e. the more samples per period you have the better the measurement is) and and number of samples.
To be really precise, you should either have a timestamp associated with every measurement (as you usually can't be sure that you get equidistant time spacing in the for loop) or perhaps it's possible to switch your USB module in some "running" mode which doesn't only get one sample at a time but a complete waveform with fixed samplerate.
Concerning the calculation of the frequency, gnovice already pointed out the right way. If you have individual timestamps (in seconds), the following changes are necessary:
tst = ...(the timestamps associated with every sample)...
period = 2*mean(diff(tst(edges)));
frequency = 1/period;
I can't figure out the problem, but if the boolean vector were v then,
frequency = sum(v)/time_to_give_me_the_frequency
Based on your description, it doesn't sound like a problem with the software, UNLESS you are using the Windows system timer, which is notoriously inaccurate (it is only accurate to about 15 milliseconds).
There are high-resolution timers available in Windows, but I don't know how to use them in Matlab. If you have access to the .NET framework, the Stopwatch class has 1 microsecond accuracy (or better), as does the QueryPerformanceCounter API in Win32.
Other than that, you might have some jitter. There could be something in your signal chain that is causing false triggers, etc.
UPDATE: The following CodeProject article should solve the timing problem, if there is one. You should check the Matlab documentation of your version of Matlab to see if it has a native high-resolution timer. Otherwise, you can use this:
C++/Mex wrapper adds microsecond resolution timer to Matlab under WinXP
http://www.codeproject.com/KB/cpp/Matlab_Microsecond_Timer.aspx
mersenne31:
Thanks everyone for your responses. I have tried the solutions that gnovice and groovingandi mentioned and I'm sure they will work as soon as the timing issue is solved.
The code I've used is shown below:
for i=1:100 tic; value = getvalue(portCH); vector(i) = value(1); tst(i) = toc; % gets an individual time sample end
% to get the total time I put total_time = toc after the for loop
totaltime = sum(tst); edges = find(diff(vec)); % Finds the indices of transitions between 0 and 1 period = 2*mean(diff(edges)); % Finds the mean period, in number of samples frequency = 100/(totaltime*period);
The problem is that measuring the time for one sample doesn't really help because it is nearly the same for all samples. What is needed is, as groovingandi mentioned, some "running" mode which reads 100 samples for 3 seconds.
So something like for(3 seconds) and then we do the data capture. But I can't find anything like this. Is there any function in MATLAB that could do this?
This won't answer your question, but it's what I thought of after reading you question. square waves have infinite frequency. The FFT of a square wave it sin(x)/x, which goes from -inf to +inf.
Also try counting only the rising edges in matlab. You can quantize the signal to just +1 and 0, and then only increment the count when you see [0 1] slice of your vector.
OR
You can quantize, decimate, then just sum. This will only work if the each square pulse is the same length and your sampling frequency is constant. I think this one would be harder to do.