Implement data type propagation for custom block

24 次查看(过去 30 天)
After some discussion and playing around, I got some ways in defining a block mask that sets the Simulink (fixed point) data type of an output. i have a mask parameter called "quotype" that is a Data Type parameter, and I can pass a related parameter into my MATLAB Function block that has that data type which can then be acted upon. However, I'd like to support rules such as "Inherit: Inherit via internal rule" and "Inherit: Inherit via back propagation". To do so, I need to be able to retrieve information on the signals/ports as they're compiling in Mask call back function. To wit: I have the current code that for instance works correctly when a specific data type is invoked:
% Initialization code section
function initialization()
if ~isa(quotype,'Simulink.NumericType')
ports = get_param(gcb,"PortHandles");
out1 = ports.Outport(1);
in1 = ports.Inport(1);
in2 = ports.Inport(2);
disp(ports)
switch quotype
case 'Inherit: Inherit via internal rule'
ttmp = fixdt(0,10,2);
case 'Inherit: Inherit via back propagation'
ttmp = fixdt(0,10,2);
case 'Inherit: Same as first input'
ttmp = fixdt(0,10,2);
otherwise
disp(quotype)
ttmp = fixdt(0,10,2);
end
qtype = fi(0,ttmp);
else
qtype = fi(0,quotype);
end
end
So, if a specific numeric type is provided in the dialog, I see I get a Simulink.NumericType object and life is good. If one of the other rules is selected, I get a string. As you can see, I can access stuff like the block port handles, but they're doubles not objects so I have no idea what to do next. I can't run this in the debugger apparently so I'm limited to my disp() statements that put stuff in the Diagnostic Viewer. The qtype is passed as a parameter into the underlying MATLAB function and the numeric type can be re-fetched by the call fixed.extractNumericType().
Help!

采纳的回答

Umar
Umar 2025-9-26

Hi @Martin Ryba,

Thanks for sharing the screenshot and your notes — they helped clarify exactly what’s happening in your masked subsystem. You’re absolutely right: when the mask dialog specifies an explicit numeric type, the parameter comes through as a `Simulink.NumericType` object, which you can pass directly into your MATLAB Function block. The difficulty appears when you choose one of the inheritance options such as “Inherit: Same as first input,” “Inherit: Inherit via internal rule,” or “Inherit: Inherit via back propagation.” In those cases Simulink only gives you a string in the mask workspace because the actual resolved type doesn’t exist until after the model compiles. That’s why your switch statement only sees text and why the port handles you queried are just doubles — the mask initialization runs before compiled attributes are available.

If you truly need the concrete type during mask initialization, the documented approach is to temporarily compile the model, query the compiled port data types, convert the result into a usable `Simulink.NumericType`, and then terminate compilation. A concise pattern looks like this:

ports = get_param(gcb,'PortHandles');
outp  = ports.Outport(1);
mdl   = bdroot(gcb);
% Compile, query, and terminate safely
feval(mdl,[],[],[], 'compile');
dtstr = get_param(outp, 'CompiledPortDataTypes');
feval(mdl,[],[],[], 'term');
% Convert the resolved type into fi
ntype = Simulink.NumericType(dtstr.Outport{1});
qtype = fi(0, ntype);

This gives you the `fi` object you’re already passing into your MATLAB Function block, and it works with `fixed.extractNumericType()`. The main caveats are performance (compiling from inside the mask makes the dialog slower), potential recursion issues if the model is already compiling, and the possibility that inactive or variant ports may yield empty results.

Because of those caveats, the cleaner design is often to let Simulink handle inheritance itself: assign the inheritance string directly to the child block’s `OutDataTypeStr` and let the type propagate naturally, with your MATLAB Function block discovering the concrete type at compile time. Another option is to require an explicit numeric type when downstream code generation absolutely demands it. In short, your existing approach is already correct for explicit types, inheritance rules can only be resolved via the compile/query/term recipe if you need them early, and in many cases the safest approach is to rely on Simulink’s propagation engine.

  1 个评论
Martin Ryba
Martin Ryba 2025-9-29,15:10
Thanks for the tips! I ended up backing off a little bit, and not trying to support the back propagation option. Is there a way for a (HDL Coder compatible) MATLAB function block to query the back-propagated type? The mask function now looks like:
% Initialization code section
function initialization()
if isa(quotype,"Simulink.NumericType")
typeflag = fi(0,quotype);
else
switch quotype
case "Inherit: Inherit via internal rule"
typeflag = uint8(1);
case "Inherit: Same as first input"
typeflag = uint8(2);
otherwise
error("Unknown data type: %s", quotype)
end
end
end
And inside the function block I handle the resulting parameter thusly (note since the actual division math is always unsigned I have to temporarily lengthen the working output by a bit to accommodate the sign bit). I also force the resulting type to be signed or unsigned based on the types of the numerator and denominator
% Get numeric types of numerator and denominator
Ttop = fixed.extractNumericType(dividend);
Tbot = fixed.extractNumericType(divisor);
LTOP = Ttop.WordLength;
FTOP = Ttop.FractionLength;
LBOT = Tbot.WordLength;
FBOT = Tbot.FractionLength;
NBROUND = 4; % Added bits calculated to support accurate rounding
if Ttop.Signed || Tbot.Signed
sQ = 1;
else
sQ = 0;
end
switch typeflag
case 0
Ttmp = fixed.extractNumericType(typeflag);
QLEN = Ttmp.WordLength;
QFRAC = Ttmp.FractionLength;
case 1
QLEN = LTOP + LBOT;
QFRAC = FTOP + LBOT - FBOT;
case 2
QLEN = LTOP;
QFRAC = FTOP;
otherwise
error("Unrecognized type: %d",typeflag)
end
Fquo = fimath("RoundingMethod","Convergent");
Tquo = numerictype(sQ,QLEN,QFRAC);
% Skipping most of the functional logic
else
% Create outputs
running = false;
val_reg = true;
if ~sign_out
quo_reg = fi(q_tmp,Tquo,Fquo);
else
t1 = fi(q_tmp,1,QLEN+NBROUND+1,QFRAC+NBROUND);
quo_reg = fi(-t1,Tquo,Fquo);
end
end

请先登录,再进行评论。

更多回答(0 个)

类别

Help CenterFile Exchange 中查找有关 Create Block Masks 的更多信息

产品


版本

R2024a

Community Treasure Hunt

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

Start Hunting!

Translated by