在simulink中将可变大小数组填充为固定大小
Padding variable size array to fixed size in simulink
我对MATLAB比较熟悉,但对Simulink是个新手。
我正在尝试构建一个模型,我需要(似乎需要)使用可变大小的数组,其维度随每个时间步而变化。
考虑以下问题:
- 假设我的模拟时长为10秒,我的时间步长固定为1秒。然后我可以构造我的时间数组 TT = [1 2 3 4 5 6 7 8 9 10].
- 我有一个固定大小的数组 A [5 6 3]。
- 我的目标是在每个时间步构造一个数组 AA,使得:
时间 = 0,AA = [5 6 3 0 0 0 0 0 0 0]
在时间 = 1,AA = [0 5 6 3 0 0 0 0 0 0]
在时间 = 2,AA = [0 0 5 6 3 0 0 0 0 0]
...
在时间 = 7,AA = [0 0 0 0 0 0 0 5 6 3]
在时间 = 8,AA = [0 0 0 0 0 0 0 0 5 6]
在时间 = 9,AA = [0 0 0 0 0 0 0 0 0 5]
在时间 =10,AA = [0 0 0 0 0 0 0 0 0 0]
实现此目标的最简单方法是什么?
我尝试创建一个 2 级 MATLAB S-Function,只是调整了一个给定的例子。请参阅下面的代码。该功能只是生成一个零数组,该数组是当前时间的大小。这导致可变大小的数组。
这是我使用的 2 级 MATLAB S-Function。我只更改了 msfcndemo_varsize 中名为 'expand' 的示例代码的最后一行,以生成零数组 [0 0 0 ...] 而不是 [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);
我正在使用此函数生成 AA 中的零,这些零位于 A = [5 6 3] 之前。我的想法是将这个零数组与 A 连接起来,这样我就可以将结果数组填充(截断)到 TT 的大小。但是我遇到了问题,因为填充块不接受可变大小的数组作为其输入。
我也试过一个更简单的方法涉及pad和offset块,但问题是我无法根据模拟中的每个时间指定输出向量的长度。也许我遗漏了什么?
任何其他方法或建议或指导都会很棒!
谢谢!
我自己找到了答案。我尽量避免使用 S-Function,看来我可以使用 if/else 块、偏移块、赋值块和填充块来做到这一点。
第一个 if 是我的迭代计数(或时间)使得我不需要 trim A 的地方。在这种情况下,我可以简单地使用赋值块将 A 分配给长度为 10 的预定义零数组.
else 部分有点棘手。我需要 trim A 并将 trimmed A 与零数组连接起来,同时将结果的长度保持为 10。首先,我计算出 trim A 需要多少(比如这个长度是你)。 u 可以根据 AA 和 A 的长度以及当前 time/iteration 计数来计算。然后我用 u 在最后抵消 A。由于我无法使用变量改变每个步骤的截断长度,因此我只是对截断部分进行零填充。然后我使用这个结果数组将它分配给另一个预定义的零向量,但这次它的长度大于 10。(这部分很难弄清楚)。我想这次零向量必须至少是 AA 的长度 + A 的长度。赋值的结果是零,直到当前迭代计数,然后是截断的 A,然后是一些长度的零。然后可以将零填充掉,因为我们希望 AA 的长度为 10。
所以是的,在我的示例中,事实证明我不需要在每个时间步都使用 S-Function 来操作数组。我希望避免使用 S-Function 而使用 simulink 块可以节省一些计算时间。
我对MATLAB比较熟悉,但对Simulink是个新手。
我正在尝试构建一个模型,我需要(似乎需要)使用可变大小的数组,其维度随每个时间步而变化。
考虑以下问题:
- 假设我的模拟时长为10秒,我的时间步长固定为1秒。然后我可以构造我的时间数组 TT = [1 2 3 4 5 6 7 8 9 10].
- 我有一个固定大小的数组 A [5 6 3]。
- 我的目标是在每个时间步构造一个数组 AA,使得:
时间 = 0,AA = [5 6 3 0 0 0 0 0 0 0]
在时间 = 1,AA = [0 5 6 3 0 0 0 0 0 0]
在时间 = 2,AA = [0 0 5 6 3 0 0 0 0 0]
...
在时间 = 7,AA = [0 0 0 0 0 0 0 5 6 3]
在时间 = 8,AA = [0 0 0 0 0 0 0 0 5 6]
在时间 = 9,AA = [0 0 0 0 0 0 0 0 0 5]
在时间 =10,AA = [0 0 0 0 0 0 0 0 0 0]
实现此目标的最简单方法是什么?
我尝试创建一个 2 级 MATLAB S-Function,只是调整了一个给定的例子。请参阅下面的代码。该功能只是生成一个零数组,该数组是当前时间的大小。这导致可变大小的数组。
这是我使用的 2 级 MATLAB S-Function。我只更改了 msfcndemo_varsize 中名为 'expand' 的示例代码的最后一行,以生成零数组 [0 0 0 ...] 而不是 [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);
我正在使用此函数生成 AA 中的零,这些零位于 A = [5 6 3] 之前。我的想法是将这个零数组与 A 连接起来,这样我就可以将结果数组填充(截断)到 TT 的大小。但是我遇到了问题,因为填充块不接受可变大小的数组作为其输入。
我也试过一个更简单的方法涉及pad和offset块,但问题是我无法根据模拟中的每个时间指定输出向量的长度。也许我遗漏了什么?
任何其他方法或建议或指导都会很棒!
谢谢!
我自己找到了答案。我尽量避免使用 S-Function,看来我可以使用 if/else 块、偏移块、赋值块和填充块来做到这一点。
第一个 if 是我的迭代计数(或时间)使得我不需要 trim A 的地方。在这种情况下,我可以简单地使用赋值块将 A 分配给长度为 10 的预定义零数组.
else 部分有点棘手。我需要 trim A 并将 trimmed A 与零数组连接起来,同时将结果的长度保持为 10。首先,我计算出 trim A 需要多少(比如这个长度是你)。 u 可以根据 AA 和 A 的长度以及当前 time/iteration 计数来计算。然后我用 u 在最后抵消 A。由于我无法使用变量改变每个步骤的截断长度,因此我只是对截断部分进行零填充。然后我使用这个结果数组将它分配给另一个预定义的零向量,但这次它的长度大于 10。(这部分很难弄清楚)。我想这次零向量必须至少是 AA 的长度 + A 的长度。赋值的结果是零,直到当前迭代计数,然后是截断的 A,然后是一些长度的零。然后可以将零填充掉,因为我们希望 AA 的长度为 10。
所以是的,在我的示例中,事实证明我不需要在每个时间步都使用 S-Function 来操作数组。我希望避免使用 S-Function 而使用 simulink 块可以节省一些计算时间。