Set Fixed-Point Math Attributes

This example shows how to set fixed point math attributes in MATLAB® code.

You can control fixed-point math attributes for assignment, addition, subtraction, and multiplication using the fimath object. You can attach a fimath object to a fi object using setfimath. You can remove a fimath object from a fi object using removefimath.

You can generate C code from the examples if you have MATLAB Coder™ software.

Set and Remove Fixed Point Math Attributes

You can insulate your 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.

MATLAB Code

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

Output has no Attached FIMATH

When you run the code, the fimath controls the arithmetic inside the function, but the return value has no attached fimath. This is due to the use of setfimath and removefimath inside the function user_written_sum.

>> 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

Generated C Code

If you have MATLAB Coder software, you can generate C code using the following commands.

>> u = fi(1:10,true,16,11);
>> codegen user_written_sum -args {u} -config:lib -launchreport

Functions fimath, setfimath and removefimath 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.

int32_T user_written_sum(const int16_T u[10])
{
  int32_T y;
  int32_T i;
  /* Setup */
  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');
>> C = A * B
Error using embedded.fi/mtimes
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, and the product is computed using the fimath attached to A.

>> C = A * removefimath(B)
C =
                6.283203125
           DataTypeMode: Fixed-point: binary point scaling
             Signedness: Signed
             WordLength: 32
         FractionLength: 26
         RoundingMethod: Nearest
         OverflowAction: Saturate
            ProductMode: KeepLSB
      ProductWordLength: 32
                SumMode: FullPrecision

Changing 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, the product is computed with 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
       MaxSumWordLength: 128

Note that variable B is not changed.

>> B
B =
      2
           DataTypeMode: Fixed-point: binary point scaling
             Signedness: Signed
             WordLength: 16
         FractionLength: 13

Removing 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.

MATLAB Code

In this example, 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,z)
    % 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(z,F_floor);
    % Create y with nearest rounding
    y = coder.nullcopy(fi(zeros(size(x)),true,16,14,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

Code Generation Instructions

If you have MATLAB Coder software, you can generate C code with the specified hardware characteristics using the following commands.

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.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} -launchreport

Generated C Code

Functions fimath, setfimath and removefimath 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], int16_T z[2],
  int16_T y[256])
{
  int32_T j;
  int40_T i0;
  int16_T b_y;
  /* Setup */
  /* Set fimaths that are local to this function */
  /* Create y with nearest rounding */
  /* Algorithm */
  for (j = 0; j < 256; j++) {
    /* Nearest assignment into y */
    i0 = 15705 * x[j] + ((int40_T)z[0] << 20);
    b_y = (int16_T)((int32_T)(i0 >> 20) + ((i0 & 524288L) != 0L));
    /* Remove y's fimath conflict with other fimaths */
    z[0] = (int16_T)(((31410 * x[j] + ((int40_T)z[1] << 20)) - ((int40_T)(-23826
      * b_y) << 6)) >> 20);
    z[1] = (int16_T)((15705 * x[j] - ((int40_T)(9405 * b_y) << 6)) >> 20);
    y[j] = b_y;
  }
  /* Cleanup: Remove fimath from outputs */
}

Polymorphic Code

You can write MATLAB code that can be used for both floating-point and fixed-point types using setfimath and removefimath.

function y = user_written_function(u)
    % Setup
    F = fimath('RoundingMethod','Floor',...
        'OverflowAction','Wrap',...
        'SumMode','KeepLSB');
    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.785400390625
           DataTypeMode: Fixed-point: binary point scaling
             Signedness: Signed
             WordLength: 32
         FractionLength: 15

Generated C Code for Fixed Point

If you have MATLAB Coder software, you can generate C code using the following commands.

>> u = fi(pi/8,true,16,15,'RoundingMethod','Convergent');
>> codegen user_written_function -args {u} -config:lib -launchreport

Functions fimath, setfimath and removefimath 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.

int32_T user_written_function(int16_T u)
{
  /* Setup */
  /* Algorithm */
  /* Cleanup */
  return u + u;
}

Double Inputs

Since setfimath and removefimath are pass-through for floating-point types, the user_written_function example works with floating-point types, too.

function y = user_written_function(u)
    % Setup
    F = fimath('RoundingMethod','Floor',...
        'OverflowAction','Wrap',...
        'SumMode','KeepLSB');
    u = setfimath(u,F);
    % Algorithm
    y = u + u;
    % Cleanup
    y = removefimath(y);
end

Generated C Code for Double

When compiled with floating-point input, you get the following generated C code.

>> codegen user_written_function -args {0} -config:lib -launchreport
real_T user_written_function(real_T u)
{
  return u + u;
}

Where the real_T type is defined as a double:

typedef double real_T;

More Polymorphic Code

This function is written so that the output is created to be the same type as the input, so both floating-point and fixed-point can be used with it.

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

Fixed Point Generated C Code

If you have MATLAB Coder software, you can generate fixed-point C code using the following commands.

>> u = fi(1:10,true,16,11);
>> codegen user_written_sum_polymorphic -args {u} -config:lib -launchreport

Functions fimath, setfimath and removefimath 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.

int32_T user_written_sum_polymorphic(const int16_T u[10])
{
  int32_T y;
  int32_T i;
  /* Setup */
  y = 0;
  /* Algorithm */
  for (i = 0; i < 10; i++) {
    y += u[i];
  }
  /* Cleanup */
  return y;
}

Floating Point Generated C Code

If you have MATLAB Coder software, you can generate floating-point C code using the following commands.

>> u = 1:10;
>> codegen user_written_sum_polymorphic -args {u} -config:lib -launchreport
real_T user_written_sum_polymorphic(const real_T u[10])
{
  real_T y;
  int32_T i;
  /* Setup */
  y = 0.0;
  /* Algorithm */
  for (i = 0; i < 10; i++) {
    y += u[i];
  }
  /* Cleanup */
  return y;
}

Where the real_T type is defined as a double:

typedef double real_T;

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.

>> u = int8(5);
>> codegen user_written_u_plus_u -args {u} -config:lib -launchreport
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

The output type was specified by the fimath to be 32-bit.

int32_T user_written_u_plus_u(int8_T u)
{
  /* Setup */
  /* Algorithm */
  /* Cleanup */
  return u + u;
}