Main Content

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

| | |

Related Topics