Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use different fix point types in mathematical operations in Ada?

Tags:

ada

For the program at the end I get the following error messages from gnat:

test2.adb:23:61: error: invalid operand types for operator "-"
test2.adb:23:61: error: left operand has type "Gain_Type" defined at line 11
test2.adb:23:61: error: right operand has type "Offset_Type" defined at line 12

Unfortunately I did not find a good example how to resolve this in a way resulting in speed optimized code for rather small embedded targets.

Always casting everything to the biggest type does not make that much sense I feel. What is the best way to do that/ isn't there a good reference existing how to efficiently use fixed point for a bit more complicated mathematical problems?

procedure Test2 is
   Adc_Width   : constant Positive := 10;
   Adc_Delta   : constant Float    := 2.0**(-Adc_Width);
   Adc_Mod   : constant    := 2**Adc_Width;
   Error_Delta : constant          := 2.0**(-1);
   Gain_Min    : constant Float    := 1.0 - 2.0 * Adc_Delta;
   Gain_Max    : constant Float    := 1.0 + 2.0 * Adc_Delta;
   Offset_Min  : constant Float    := -0.5 * Adc_Delta;
   Offset_Max  : constant Float    := 2.0 * Adc_Delta;
   type Gain_Type is delta Adc_Delta * Error_Delta range Gain_Min .. Gain_Max;
   type Offset_Type is
      delta Adc_Delta * Error_Delta range Offset_Min .. Offset_Max;
   type Adc_Encoded_Type is mod Adc_Mod with
      Size => 16;
   subtype Adc_Value_Type is natural range 0 .. Adc_Encoded_Type'Modulus - 1;
   type Adc_Delta_Type is delta Adc_Delta range 0.0 .. 1.0 - Adc_Delta;
   function Compensate
    (Adc : in Adc_Encoded_Type; Gain : in Gain_Type; Offset : in Offset_Type)
     return Adc_Delta_Type
   is
   begin
      return Adc_Delta_Type (((Adc_Value_Type (Adc) * Gain) - Offset) / Adc_Mod);
   end Compensate;
begin
end Test2;
like image 948
Torsten Knodt Avatar asked Jan 28 '26 10:01

Torsten Knodt


1 Answers

If Gain_Type and Offset_Type are physically compatible, you could make them subtypes of a common type since they have the same delta.

procedure Test2 is
   Adc_Width   : constant := 10;
   Adc_Delta   : constant := 2.0**(-Adc_Width);
   Adc_Mod     : constant := 2**Adc_Width;
   Error_Delta : constant := 2.0**(-1);
   Gain_Min    : constant := 1.0 - 2.0 * Adc_Delta;
   Gain_Max    : constant := 1.0 + 2.0 * Adc_Delta;
   Offset_Min  : constant := -0.5 * Adc_Delta;
   Offset_Max  : constant := 2.0 * Adc_Delta;
   --
   type Super_Type is delta Adc_Delta * Error_Delta range -1.0 .. 2.0;
   subtype Gain_Type   is Super_Type range Gain_Min .. Gain_Max;
   subtype Offset_Type is Super_Type range Offset_Min .. Offset_Max;
   --
   type Adc_Encoded_Type is mod Adc_Mod with
      Size => 16;
   subtype Adc_Value_Type is natural range 0 .. Adc_Encoded_Type'Modulus - 1;
   type Adc_Delta_Type is delta Adc_Delta range 0.0 .. 1.0 - Adc_Delta;
   function Compensate
    (Adc : in Adc_Encoded_Type; Gain : in Gain_Type; Offset : in Offset_Type)
     return Adc_Delta_Type
   is
   begin
      return Adc_Delta_Type (((Adc_Value_Type (Adc) * Gain) - Offset) / Adc_Mod);
   end Compensate;
begin
  null;
end Test2;

BTW, I have removed the types in the constants in order to remove rounding errors.

like image 108
Zerte Avatar answered Jan 30 '26 14:01

Zerte