Padding variable size array to fixed size in simulink

3.8k views Asked by At

I am relatively familiar with MATLAB but new to Simulink.

I am trying to build a model where I need to (seem to need to) use variable-sized array whose dimensions vary with each time step.


Consider the following problem:

  1. Assume that my simulation is 10 seconds long and my time step is fixed at 1 second. Then I can construct my time array TT = [1 2 3 4 5 6 7 8 9 10].
  2. I have a fixed-size array A [5 6 3].
  3. My goal is to construct an array AA at each time step such that:

at time = 0, AA = [5 6 3 0 0 0 0 0 0 0]
at time = 1, AA = [0 5 6 3 0 0 0 0 0 0]
at time = 2, AA = [0 0 5 6 3 0 0 0 0 0]
...
at time = 7, AA = [0 0 0 0 0 0 0 5 6 3]
at time = 8, AA = [0 0 0 0 0 0 0 0 5 6]
at time = 9, AA = [0 0 0 0 0 0 0 0 0 5]
at time =10,AA = [0 0 0 0 0 0 0 0 0 0]


What would be the easiest way to achieve this?

I tried creating a level-2 MATLAB S-function, merely tweaking a given example. See code below. The function is just to generate a zero array which is the size of current time. This results in variable sized array.

Here is the level 2 MATLAB S-function I used. I only changed the last line from the example code called 'expand' in msfcndemo_varsize to generate zero array [0 0 0 ...] instead of [1 2 3 4...].

function msfcn_varsize_expand(block)
% Level-2 MATLAB file S-Function.
%  Takes a scalar input and outputs a vector of length indicated 
% by its input value. The output is given by 1:n where n is the input
% value.
% For example
%  f(5) = [1 2 3 4 5]
%
% The parameter defines the maximum input value allowed.
%
%   Copyright 2009 The MathWorks, Inc.

setup(block);

function setup(block)

% Register number of ports and parameters
block.NumInputPorts  = 1;
block.NumOutputPorts = 1;
block.NumDialogPrms  = 1;

% Setup functional port properties to dynamically inherited
block.SetPreCompInpPortInfoToDynamic;
block.SetPreCompOutPortInfoToDynamic;

% Register the properties of the input port
block.InputPort(1).Complexity        = 'Inherited';
block.InputPort(1).DataTypeId        = -1;
block.InputPort(1).SamplingMode      = 'Sample';
block.InputPort(1).DimensionsMode    = 'Fixed';
block.InputPort(1).DirectFeedthrough = true;

% Register the properties of the output port
block.OutputPort(1).DimensionsMode = 'Variable';
block.OutputPort(1).SamplingMode   = 'Sample';

% Register sample times
%  [-1, 0] : Inherited sample time
block.SampleTimes = [-1 0];

% Register methods called during update diagram/compilation
block.RegBlockMethod('SetInputPortDimensions',      @SetInputPortDims);
block.RegBlockMethod('PostPropagationSetup',        @DoPostPropSetup);

% Register methods called at run-time
block.RegBlockMethod('Outputs', @Outputs);

% -------------------------------------------------------------------------
function SetInputDimsMode(block, port, dm)
% Set dimension mode
block.InputPort(port).DimensionsMode = dm;

% -------------------------------------------------------------------------
function SetInputPortDims(block, idx, di)
width = prod(di);
if width ~= 1  
     DAStudio.error('Simulink:blocks:multirateInvaliDimension'); 
end
% Set compiled dimensions 
block.InputPort(idx).Dimensions = di;
block.OutputPort(idx).Dimensions =[1 block.DialogPrm(1).Data];

% -------------------------------------------------------------------------
function DoPostPropSetup(block)
% Set the type of signal size to be dependent on input values, i.e.,
% dimensions have to be updated at output
block.SignalSizesComputeType = 'FromInputValueAndSize';

% -------------------------------------------------------------------------
function Outputs(block)
% Output function:
% -update output values
% -update signal dimensions
block.OutputPort(1).CurrentDimensions = [1 block.InputPort(1).Data];
block.OutputPort(1).Data = zeros(1,block.InputPort(1).Data);

I am using this function to generate the zeros in AA which would precede A = [5 6 3]. The idea was to concatenate this array of zeros with A, so that I could then pad(truncate) the resulting array to the size of TT. But I have encountered problems because the pad block does not accept variable sized array as its input.

A simpler method I also tried involved pad and offset blocks, but the problem was that I could not specify the length of the output vectors according to each time inside the simulation. Maybe I am missing something?

Any other methods or suggestions or guidance would be great!

Thank you!

1

There are 1 answers

0
Andrew Chey On BEST ANSWER

I found the answer myself. I tried to avoid using S-function as much as possible, and it seems I can do so using if/else block, offset block, assignment block, and pad block.

The first if is where my iteration count (or time) is such that I do not need to trim A. In this case, I can simply use assignment block to assign A onto a predefined array of zeros whose length is 10.

The else part is a bit trickier. I need to trim A AND concatenate the trimmed A with zero array while keeping the result at length 10. First, I calculate by how much I need to trim A (say this length is u). u can be calculated from the length of AA and A and current time/iteration count. Then I use u to offset A at the end. Since I cannot vary the truncated length for each step with a variable, I simply zero-pad the truncated part. Then I use this resulting array to assign it onto another predefined zeros vector, but this time, whose length is larger than 10. (This part was tricky to figure out). I figured that the zero vector this time had to be at least the length of AA + length of A. The result of the assignment is zeros up until current iteration count, and then the truncated A, and then some length of zeros. The zeros then can be padded away since we want the length of AA to be 10.

So yes, in my example, it turns out I do not need to use S-function to manipulate the array each time step. I am hoping that avoiding S-function and using the simulink blocks instead would save me some calculation time.