FAQ: Why does Fixed-Point fi variable times MATLAB floating-point variable error out in code generation, MATLAB Function Block, etc.?

13 views (last 30 days)
FAQ: Why does Fixed-Point fi variable multiplied by a MATLAB floating-point variable error out in code generation, MATLAB Function Block, etc.?
When simulating with base MATLAB, it works fine.
But when using codegen command, Simulink's MATLAB function block, I get an error like the following.
In fi .* non-fi, or non-fi .* fi, the non-fi must be a constant.

Accepted Answer

Andy Bartlett
Andy Bartlett on 22 Dec 2023
Edited: Andy Bartlett on 2 Jan 2024
fi op float: auto convert float to fixed-point "constant"
Fixed-Point Designer's fi variables are designed to prioritize ease of creating an algorithm that is 100% fixed-point.
When authoring an algorithm, it is very convenient to be able to simply enter constants using their "ideal" decimal value.
y = 0.789 * u
Fixed-Point Designer fi variables seek to support that significant convenience AND achieve the goal of getting a 100% fixed-point algorithm.
By MATLAB language rules, the literal constant 0.789 is a floating-point double. But if the other variable in a binary (i.e. two input) operation is a fi variable, then fi handles the operation according to "Fixed-Point Designer fi rules."
These rules say to treat the other input as if it was a constant, and convert that constant to a fixed-point type in a sensible way for the specific operation being performed.
For multiplication, the rule says convert the "constant" to a fixed-point type with the same word length and signedness as the fixed-point argument. Automatically decide the scaling of the constant to give the maximum precision representation of the value using the given signedness and word length. This is known as "Best Precision Scaling."
Using this rule, line below computing y1 implicitly behaves the same as the more explicit line computing y2
u = fi(123.45, 1,16,7)
u =
123.4531 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 16 FractionLength: 7
y1 = u * 0.789
y1 =
97.4047 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 22
y2 = u * fi(0.789, 1,16)
y2 =
97.4047 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 22
isSame = y1 == y2
isSame = logical
1
If value changes enough, data types can change
A weakness of the fi-op-float design is that if the floating-point variable isn't really constant, then the data type of the constant may change, and data type of the output may change to.
Notice that when the following code is executed, the data type of y changes in the third iteration.
kVec = [0.789, 0.65, 6.54];
u = fi(123.45, 1,16,7);
for i=1:length(kVec)
y = u * kVec(i)
end
y =
97.4047 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 22
y =
80.2438 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 22
y =
807.3883 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 19
In an algorithm running on a real-time embedded system, it is not practical to change data types on the fly. Too costly and too slow. An algorithm is not ready for practical embedded deployment until all the numeric data types are locked down.
Code generation "hates" if data types might change
Code generation has a hard rule that the numeric data type of a variable must NOT change.
MathWorks code generation technology used by MATLAB Coder, Simulink accelerator, MATLAB Function Blocks, etc. will apply sophisticated analysis techniques seeking to prove that a data type will NOT change. If it can prove that, the code generation process happily continues.
When MathWorks code generation technology sees a literal constant times a fi variable,
y = 0.789 * u
it easily proves to itself that data type for the constant and for y will not change and is happy.
But if the other term is presented as a variable,
y = otherVar * u
then code generation technology will have to work much harder to prove that the data types do NOT change.
That analysis may fail to prove no data type changes. Moreover, it may be that otherVar really is a variable and not a constant.
The code generation technology will throw an error if it can't prove constantness with a message such as
In fi .* non-fi, or non-fi .* fi, the non-fi must be a constant.
Three paths to code generation happiness
When constantness analysis does not succceed, there are three paths to making the code generation technology happy about data type constness.
1) One path is to explicitly inform the tools that a variable is actually constant.
See the help of these utilities for techniques.
help coder.Constant
help coder.const
2) A second path is to explicitly cast the other variable to a fully defined fixed-point type.
% Solution 1
% explictly define the vector to be fixed-point
%
kVec = fi( [0.789, 6.54], 0, 16 );
u = fi(123.45, 1,16,7);
for i=1:length(kVec)
y = u * kVec(i)
end
y =
97.3972 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 20
y =
807.3883 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 20
or
% Solution 2
kVecDbl = [0.789, 6.54];
u = fi(123.45, 1,16,7);
for i=1:length(kVec)
% cast the floating-point variable at run-time
currentK = fi( kVecDbl(i), 1, 16, 11 )
y = u * currentK
end
currentK =
0.7891 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 16 FractionLength: 11
y =
97.4122 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 18
currentK =
6.5400 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 16 FractionLength: 11
y =
807.3883 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 18
3) A third path is to do the math in floating-point.
If the other argument to the operation really should be a floating-point variable in the embedded design, then doing the math in floating-point may be preferable.
Simulink blocks like Product follow a default rule similar to the C language. If one of the input arguments to a operation is floating-point, then the biggest floating-point type wins. So in double precision floating-point times fixed-point, double is used for the operation and the output. In fixed-point times single precision floating-point, single is used for the operation and the output.
To do this in MATLAB code involving fi variables, you need to insert an explicit cast of the fi variable to the desired floating-point type.
% Solution 3
kVec = single( [0.789, 6.54] );
u = fi(123.45, 1,16,7);
% simple approach
% u2 = single(u);
% Fancy approach automatically adapting to type of kVec
% using Cast-Like technique
%
if isfloat(kVec)
u2 = cast(u, 'like', kVec);
else
u2 = u;
end
for i=1:length(kVec)
y = u2 * kVec(i)
end
y = single 97.4045
y = single 807.3834

More Answers (0)

Community Treasure Hunt

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

Start Hunting!