Set Fixed-Point Math Attributes
This example shows how to set fixed point math attributes in MATLAB® code.
Use the fimath
object to control fixed-point math attributes for assignment, addition, subtraction, and multiplication. Use the setfimath
function to attach a fimath
object to a fi
object. Use the removefimath
function to remove a fimath
object from a fi
object.
You can use the MATLAB Coder™ software to generate C code from these examples.
Set and Remove Fixed Point Math Attributes
The user_written_sum
function shows an example of how to insulate fixed-point operations from global and local fimath
settings by using the setfimath
and removefimath
functions. You can also return from functions with no fimath
attached to output variables. This gives you local control over fixed-point math settings without interfering with the settings in other functions.
function y = user_written_sum(u) % Setup F = fimath('RoundingMethod','Floor',... 'OverflowAction','Wrap',... 'SumMode','KeepLSB',... 'SumWordLength',32); u = setfimath(u,F); y = fi(0,true,32,get(u,'FractionLength'),F); % Algorithm for i=1:length(u) y(:) = y + u(i); end % Cleanup y = removefimath(y); end
The fimath
controls the arithmetic inside the function, but the returned value has no attached fimath
. This is due to the use of setfimath
and removefimath
inside the user_written_sum
function.
u = fi(1:10,true,16,11); y = user_written_sum(u)
y = 55 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 11
Generate C Code
If you have a MATLAB Coder license, you can run these commands to generate C code.
u = fi(1:10,true,16,11); codegen user_written_sum -args {u} -config:lib -launchreport
The fimath
, setfimath
, and removefimath
functions control the fixed-point math, but the underlying data contained in the variables does not change and so the generated C code does not produce any data copies.
int user_written_sum(const short u[10]) { int i; int y; y = 0; /* Algorithm */ for (i = 0; i < 10; i++) { y += u[i]; } /* Cleanup */ return y; }
Mismatched fimath
When you operate on fi
objects, their fimath
properties must be equal or you get an error.
A = fi(pi,'ProductMode','KeepLSB'); B = fi(2,'ProductMode','SpecifyPrecision'); try C = A*B catch me disp(me.message) end
The embedded.fimath of both operands must be equal.
To avoid this error, you can remove fimath
from one of the variables in the expression. In this example, the fimath
is removed from B
in the context of the expression without modifying B
itself. The product is computed using the fimath
attached to A
.
C = A * removefimath(B)
C = 6.2832 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 26 RoundingMethod: Nearest OverflowAction: Saturate ProductMode: KeepLSB ProductWordLength: 32 SumMode: FullPrecision
Change fimath
on Temporary Variables
If you have variables with no attached fimath
, but you want to control a particular operation, then you can attach a fimath
in the context of the expression without modifying the variables.
For example, compute the product using the fimath
defined by F
.
F = fimath('ProductMode','KeepLSB',... 'OverflowAction','Wrap',... 'RoundingMethod','Floor'); A = fi(pi); B = fi(2); C = A * setfimath(B,F)
C = 6.2832 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 26 RoundingMethod: Floor OverflowAction: Wrap ProductMode: KeepLSB ProductWordLength: 32 SumMode: FullPrecision
The variable B
is not changed.
B
B = 2 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 16 FractionLength: 13
Remove fimath
Conflict in a Loop
You can compute products and sums to match the accumulator of a DSP with floor rounding and wrap overflow, and use nearest rounding and saturate overflow on the output. To avoid mismatched fimath
errors, you can remove the fimath
on the output variable when it is used in a computation with the other variables.
In the setfimath_removefimath_in_a_loop
function, the products are 32 bits and the accumulator is 40 bits, keeping the least-significant bits with floor rounding and wrap overflow like C's native integer rules. The output uses nearest rounding and saturate overflow.
function [y,z] = setfimath_removefimath_in_a_loop(b,a,x,zi) % Setup F_floor = fimath('RoundingMethod','Floor',... 'OverflowAction','Wrap',... 'ProductMode','KeepLSB',... 'ProductWordLength',32,... 'SumMode','KeepLSB',... 'SumWordLength',40); F_nearest = fimath('RoundingMethod','Nearest',... 'OverflowAction','Wrap'); % Set fimaths that are local to this function b = setfimath(b,F_floor); a = setfimath(a,F_floor); x = setfimath(x,F_floor); z = setfimath(zi,F_floor); % Create y with nearest rounding y = setfimath(zeros(size(x),'like',zi),F_nearest); % Algorithm for j=1:length(x) % Nearest assignment into y y(j) = b(1)*x(j) + z(1); % Remove y's fimath conflict with other fimaths z(1) = (b(2)*x(j) + z(2)) - a(2) * removefimath(y(j)); z(2) = b(3)*x(j) - a(3) * removefimath(y(j)); end % Cleanup: Remove fimath from outputs y = removefimath(y); z = removefimath(z); end
Generate C Code
If you have a MATLAB Coder license, you can run these commands to generate C code using the specified hardware characteristics.
N = 256; t = 1:N; xstep = [ones(N/2,1);-ones(N/2,1)]; num = [0.0299545822080925 0.0599091644161849 0.0299545822080925]; den = [1 -1.4542435862515900 0.5740619150839550];
b = fi(num,true,16); a = fi(den,true,16); x = fi(xstep,true,16,15); zi = fi(zeros(2,1),true,16,14);
B = coder.Constant(b); A = coder.Constant(a);
config_obj = coder.config('lib'); config_obj.GenerateReport = true; config_obj.LaunchReport = true; config_obj.TargetLang = 'C'; config_obj.DataTypeReplacement = 'CoderTypedefs'; config_obj.GenerateComments = true; config_obj.GenCodeOnly = true; config_obj.HardwareImplementation.ProdBitPerChar=8; config_obj.HardwareImplementation.ProdBitPerShort=16; config_obj.HardwareImplementation.ProdBitPerInt=32; config_obj.HardwareImplementation.ProdBitPerLong=40;
codegen -config config_obj setfimath_removefimath_in_a_loop -args {B,A,x,zi}
The fimath
, setfimath
and removefimath
functions control the fixed-point math, but the underlying data contained in the variables does not change and so the generated C code does not produce any data copies.
void setfimath_removefimath_in_a_loop(const int16_T x[256], const int16_T zi[2], int16_T y[256], int16_T z[2]) { int32_T j; int16_T i; int16_T i1; /* Set fimaths that are local to this function */ /* Create y with nearest rounding */ /* Algorithm */ i = zi[0]; i1 = zi[1]; for (j = 0; j < 256; j++) { int64_T i3; int32_T y_tmp; int16_T i2; int16_T i4; /* Nearest assignment into y */ i2 = x[j]; y_tmp = 15705 * i2; i3 = y_tmp + ((int64_T)i << 20); i4 = (int16_T)((i3 >> 20) + ((i3 & 524288L) != 0L)); y[j] = i4; /* Remove y's fimath conflict with other fimaths */ i = (int16_T)(((31410 * i2 + ((int64_T)i1 << 20)) - ((int64_T)(-23826 * i4) << 6)) >> 20); i1 = (int16_T)((y_tmp - ((int64_T)(9405 * i4) << 6)) >> 20); } z[1] = i1; z[0] = i; /* Cleanup: Remove fimath from outputs */ }
Polymorphic Code
You can use the setfimath
and removefimath
functions to write MATLAB code that can be used for both floating-point and fixed-point types.
function y = user_written_function(u) % Setup F = fimath('RoundingMethod','Floor',... 'OverflowAction','Wrap',... 'SumMode','KeepLSB',... 'SumWordLength',32); u = setfimath(u,F); % Algorithm y = u + u; % Cleanup y = removefimath(y); end
Fixed-Point Inputs
When the function is called with fixed-point inputs, then fimath
F
is used for the arithmetic and the output has no attached fimath
.
u = fi(pi/8,true,16,15,'RoundingMethod','Convergent'); y = user_written_function(u)
y = 0.7854 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 15
If you have a MATLAB Coder license, you can run these commands to generate C code.
u = fi(pi/8,true,16,15,'RoundingMethod','Convergent'); codegen user_written_function -args {u} -config:lib -launchreport
The fimath
, setfimath
and removefimath
functions control the fixed-point math, but the underlying data contained in the variables does not change and so the generated C code does not produce any data copies.
int user_written_function(short u) { /* Algorithm */ return u + u; /* Cleanup */ }
Floating-Point Double Inputs
The user_written_function
example works with floating-point types because the setfimath
and removefimath
functions are pass-through for floating-point types.
u = double(pi/8); codegen user_written_function -args {0} -config:lib -launchreport
When compiled with floating-point input, you get the following generated C code.
double user_written_function(double u) { /* Algorithm */ return u + u; /* Cleanup */ }
More Polymorphic Code
The user_written_sum_polymorphic
function is written so that the output is created to be the same type as the input. Both floating-point and fixed-point inputs can be used with the user_written_sum_polymorphic
function.
function y = user_written_sum_polymorphic(u) % Setup F = fimath('RoundingMethod','Floor',... 'OverflowAction','Wrap',... 'SumMode','KeepLSB',... 'SumWordLength',32); u = setfimath(u,F); if isfi(u) y = fi(0,true,32,get(u,'FractionLength'),F); else y = zeros(1,1,class(u)); end % Algorithm for i=1:length(u) y(:) = y + u(i); end % Cleanup y = removefimath(y); end
Generate Fixed-Point C Code
If you have a MATLAB Coder license, you can run these commands to generate C code.
u = fi(1:10,true,16,11); codegen user_written_sum_polymorphic -args {u} -config:lib -launchreport
The fimath
, setfimath
and removefimath
functions control the fixed-point math, but the underlying data contained in the variables does not change and so the generated C code does not produce any data copies.
int user_written_sum_polymorphic(const short u[10]) { int i; int y; y = 0; /* Algorithm */ for (i = 0; i < 10; i++) { y += u[i]; } /* Cleanup */ return y; }
Generate Floating-Point C Code
If you have a MATLAB Coder license, you can run these commands to generate C code.
u = 1:10; codegen user_written_sum_polymorphic -args {u} -config:lib -launchreport
double user_written_sum_polymorphic(const double u[10]) { double y; int i; y = 0.0; /* Algorithm */ for (i = 0; i < 10; i++) { y += u[i]; } /* Cleanup */ return y; }
setfimath
on Integer Types
Following the established pattern of treating built-in integers like fi
objects, setfimath
converts integer input to the equivalent fi
with attached fimath
.
function y = user_written_u_plus_u(u) % Setup F = fimath('RoundingMethod','Floor',... 'OverflowAction','Wrap',... 'SumMode','KeepLSB',... 'SumWordLength',32); u = setfimath(u,F); % Algorithm y = u + u; % Cleanup y = removefimath(y); end
If you have a MATLAB Coder license, you can run these commands to generate C code.
u = int8(5); codegen user_written_u_plus_u -args {u} -config:lib -launchreport
The output type was specified by the fimath
to be 32-bit.
int user_written_u_plus_u(signed char u) { /* Algorithm */ return u + u; /* Cleanup */ }
Disable editor warnings.
%#ok<*NASGU>
See Also
fi
| fimath
| setfimath
| removefimath