Finding the sample time of a Simulink signal/line programmatically with Simulink.B​lock.getSa​mpleTimes

72 views (last 30 days)
I am trying to find the actual sample time of a signal/line in a Simulink model, programmatically, using Matlab commands.
So far I can't do it, although the information must be there, because Simulink can create the "Sample Time Color" overlay.
A simple demo model is attached, "FindSignalSampleTime.slx".
Clearly Simulink knows that the signal/line "Signal_1ms" has a discrete sample rate of 1e-3 s (1ms).
Now the challenge is to determine the sample time of that signal/line, called "Signal_1ms" programmatically. In this example I KNOW that the answer is 1e-3 s. But, so far, I cannot find a way to find it using code. How can it be done?
The handle of the signal can be found by:
loggedSignalName = 'Signal_1ms';
loggedSignalWire.Handle = find_system(modelName, ...
'FollowLinks','on', ...
'FindAll', 'on', ...
'LookUnderMasks','all',...
'type', 'line', ...
'Name', loggedSignalName);
fprintf('loggedSignalWire.Handle = %g\n', loggedSignalWire.Handle);
which produces
loggedSignalWire.Handle = 11.0004
I would like to now do:
ts = Simulink.Block.getSampleTimes(loggedSignalWire.Handle);
but that throws an error "The first argument to Simulink.Block.getSampleTimes must be a block".
Next I can find the "Source Port" that the line/signal is created by:
loggedSignalWireSrcPort.Handle = get_param(loggedSignalWire.Handle,'SrcPortHandle');
fprintf('loggedSignalWireSrcPortHandle = %g\n', loggedSignalWireSrcPort.Handle);
which produces
loggedSignalWireSrcPortHandle = 14.0004
Again, I would like to try:
ts = Simulink.Block.getSampleTimes(loggedSignalWireSrcPortHandle);
but again that throws an error "The first argument to Simulink.Block.getSampleTimes must be a block".
So finally I can find the block that contains that source port, and feeds the signal/line:
loggedSignalWireSrcPort.DataLoggingSampleTime = get_param(loggedSignalWireSrcPort.Handle, 'DataLoggingSampleTime');
loggedSignalWireSrcPort.ParentBlockName = get_param(loggedSignalWireSrcPort.Handle, 'Parent');
loggedSignalWireSrcPort.ParentBlockHandle = getSimulinkBlockHandle(loggedSignalWireSrcPort.ParentBlockName);
loggedSignalWireSrcPort.PortNumber = get_param(loggedSignalWireSrcPort.Handle, 'PortNumber');
fprintf('loggedSignalWireSrcPort.DataLoggingSampleTime = %s\n', loggedSignalWireSrcPort.DataLoggingSampleTime); % -1. Not much help.
fprintf('loggedSignalWireSrcPort.ParentBlockName = %s\n', loggedSignalWireSrcPort.ParentBlockName); % 'FindSignalSampleTime/SignalGeneration'
fprintf('loggedSignalWireSrcPort.ParentBlockHandle = %g\n', loggedSignalWireSrcPort.ParentBlockHandle); % 'slexVariableTransportDelayR2021bWithSimPowerSystems/vGain Library Variant Subsystem'
fprintf('loggedSignalWireSrcPort.PortNumber = %d\n', loggedSignalWireSrcPort.PortNumber); % 2
fprintf('Signal "%s" comes from output port %d of block handle %g with name "%s".\n', loggedSignalName, loggedSignalWireSrcPort.PortNumber, loggedSignalWireSrcPort.ParentBlockHandle, loggedSignalWireSrcPort.ParentBlockName);
which produces:
Signal "Signal_1ms" comes from output port 1 of block handle 4.00037 with name "FindSignalSampleTime/SignalGeneration".
Now finally a call to Simulink.Block.getSampleTimes() can return without error, using the handle for that whole block:
ts = Simulink.Block.getSampleTimes(loggedSignalWireSrcPort.ParentBlockHandle);
but the information I need is not there. The information only contains:
ts.Description = "Multirate"
ts.Value = ""
I would like the information in ts to tell me the sample rates for each output port, but it doesn't, it just says that the block is "Multirate", and that's not much help in this instance.
So I am still stuck with my problem. How can I determine the sample time of the signal/line? Simulink must know, but I can't find any valid commands/syntax that will tell me.

Answers (2)

Sumukh
Sumukh on 30 Oct 2024 at 7:32
Hi Andrew,
The sample time is defined for a block, not a signal line. The sample time of the data on a signal line depends on the block it is connected to. The sample time of a particular block in a Simulink model can be obtained using the following command:
ts = Simulink.Block.getSampleTimes(block)
The “block” input argument must be a block handle and not a port handle. The output "ts" of this command is a “Simulink.SampleTime” object. You can refer to the following documentation to understand more about the command:
You can refer to the following documentation to understand more about the “Simulink.SampleTime” object returned as an output:
I hope this answers your query.
  1 Comment
Andrew Roscoe
Andrew Roscoe on 30 Oct 2024 at 11:47
In the original question I describe exactly that, and how it does not produce the required information. The block reports only that it is "Multirate".
Doing:
ts = Simulink.Block.getSampleTimes(block);
with block set to 'FindSignalSampleTime/SignalGeneration' in the example produces:
and the information required is not there.
What I need to find out is the actual sample rates applied to each of the block output ports, but this does not seem to be possible as I cannot call Simulink.Block.getSampleTimes() on the source block output ports themselves.
But I am hoping that there is a way to extract the information, hence this question

Sign in to comment.


Paul
Paul on 30 Oct 2024 at 16:57
Hi Andrew,
If the block has multiple outputs, like in your case, check out
ts.ComponentSampleTimes
which should be an array of SampleTime obejcts, one for each output of the block.
Also, check out CompiledSampleTime at this doc page. Not sure if/how it differs from Simulink.Block.getSampleTimes.
  8 Comments
Paul
Paul on 5 Nov 2024 at 4:40
I think, as in I'm pretty sure, that I misunderstood the intended functionality of Simulink.Block.getSampleTimes. I'm now pretty sure that's not the function to use.
I also agree with you that CompiledSampleTime is not a shown property of a port handle (I can't find any documenation on port handle properties at all).
There has to be a way to do what you want w/o resorting to using undocumented features and unshown object parameters ....
Andrew Roscoe
Andrew Roscoe on 5 Nov 2024 at 10:28
Hi Paul,
Thanks for the updates. I'm glad that my original question wasn't stupid. It seems to have raised a number of questions.
In summary, right now, basically there is an answer, but it seems to rely on an undocumented parameter of a source port handle. The procedure which seems to work is:
1) Execute the "compilation" phase of a simulation. This will leave the model in a "Compiled" and part-simulated state. After extracting all the sample time information, do a clean termination using the "term" command, to put the model back into a "Ready" state.
feval(modelName, [], [], [], "compile");
The model should now say "Compiled".
2) Find the wire handle for the wire/signal name (loggedSignalName) that you wish to find the sample time of, in model modelName.
signalWireHandle = find_system(modelName, ...
'FollowLinks','on', ...
'FindAll', 'on', ...
'LookUnderMasks','all',...
'type', 'line', ...
'Name', loggedSignalName);
3) Find the relevant "SrcPortHandle" for the wire/signal (signalWireHandle) that you wish to find the sample time of. This is the output port handle, related to the block that produces the line/signal of interest.
sourcePortHandle = get_param(signalWireHandle,"SrcPortHandle");
4) Take the handle of that output port and execute the following statement:
sampleTime = get_param(sourcePortHandle, "CompiledSampleTime");
Repeat 2-4 for all the signals of interest.
5) Clean termination of the simulation that was "started" with the compilation phase. If you don't do this it leaves the model in a "compiled" and part-simulated state.
feval(modelName, [], [], [], "term");
Notes:
1) This procedure uses an essentially undocumented parameter "CompiledSampleTime" of a port handle. You don't find it on the list of available parameters if you do
listOfPropertiesAsStruct = get_param(sourcePortHandle, "ObjectParameters");
However the parameter "CompiledSampleTime" is a documented property of a block.
2) You must put the model into a compiled state. If you just do a normal model update command:
set_param(modelName,'SimulationCommand','update');
it is not enough, and you will get "NaN" results.
3) If you want, you can add dialogue about where the signal comes from, which is nice to see:
parentBlockName = get_param(sourcePortHandle, 'Parent');
portNumber = get_param(sourcePortHandle, 'PortNumber');
fprintf('Signal "%s" comes from output port %d of block "%s" and has sample time %g s with offset %g s.\n', ...
loggedSignalName, portNumber, parentBlockName, sampleTime(1), sampleTime(2))
4) You can attempt to find the information and sample times for a block handle using commands like:
parentBlockHandle = getSimulinkBlockHandle(parentBlockName);
ts = Simulink.Block.getSampleTimes(parentBlockHandle)
for k=1:length(ts.ComponentSampleTimes)
fprintf('Parent block "%s" : Component sample time %d : [%g %g]\n', parentBlockName, k, ts.ComponentSampleTimes(k).Value);
end
This is the route that documentation may lead you.
However the information in ts.ComponentSampleTimes doesn't appear to be helpful.
Some blocks like signal sources return 0x0 SampleTime values in ts.ComponentSampleTimes.
Other blocks return 1xN SampleTime values in ts.ComponentSampleTimes, where N is not equal to the number of output ports, input ports, or input+output ports, but contains a list of sample times that are used anywhere within the block. The order of the SampleTime values is not obvious and certainly doesn't match the order of the output ports. Therefore you can't tell which of the ts.ComponentSampleTimes entries is connected to which output or signal from the block.
Tests I did in Matlab 2021b and 2024b suggests that 2021b can return 0x0 SampleTime values but 2024b can return 1xN SampleTime values, for, apparently, the same models, suggesting that the procedure is not fully stable.

Sign in to comment.

Products


Release

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!