comp.lang.ada
 help / color / mirror / Atom feed
From: Niklas Holsti <niklas.holsti@nospam.please>
Subject: Re: Translating an embedded C algorithm
Date: Thu, 18 Jan 2007 18:17:34 +0200
Date: 2007-01-18T18:17:34+02:00	[thread overview]
Message-ID: <45af9c60$0$22524$39db0f71@news.song.fi> (raw)
In-Reply-To: <45acc0c3$0$22514$39db0f71@news.song.fi>

Niklas Holsti wrote:
> ...
> 
> I agree with other posters that simply translating this function into 
> Ada does not give a good comparison between C and Ada. The first steps 
> in an Ada design would be to consider encapsulation (packages) and data 
> representation (types), for which the C version gives no model.

I'm replying to my own post because I've changed my opinion a bit: I 
think that an Ada translation of this C function can, with a bit of 
elaboration, illustrate several Ada features for "programming in the 
small", even if not for "programming in the large".

So here is my try at an Ada version of the code and some of the context. 
This makes for a long post, for which I apologize in advance. Putting 
the sources somewhere for download seemed like overkill, and I prefer to 
expose my suggestion to the purifying flames of c.l.a instead of sending 
it privately to the OP. The Ada code below has been compiled
and tested (gnat 3.15p, Debian). It is hereby put in the public domain.

In this code, I tried to use as many relevant Ada features as possible, 
without trying to limit myself to some "8-bit subset". It would be 
interesting to compile this code with AVR-Ada; I don't happen to have 
that installed, but I may try it later, if no-one else does it.

First, the context. The C function deals with two kinds of data: ADC 
readings ("counts") and temperatures expressed in deci-degrees Celsius 
(that is, units of 0.1 degrees C). The ADC count-type does not depend on 
temperatures, and the temperature type does not depend on the ADC, so I 
would define these types in different packages, so:

    package ADC is

       type Count_T is range 0 .. 1023;
       --
       -- An ADC reading.

       -- More ADC stuff ...

    end ADC;

and

    package Temperatures is

       type Celsius_T is delta 0.1 digits 5 range -40.0 .. 120.0;
       --
       -- A temperature in degrees Celsius.

       -- More temperature stuff ...

    end Temperatures;

The function to convert ADC counts to temperatures then seems suitable 
for a child of package ADC. Here is the package declaration, in which I 
have added a Saturation option and two Ada idioms of reporting 
out-of-range results (discriminated type; exception):

    with Temperatures;

    package ADC.Thermometer is

       type Reading_T (In_Range : Boolean := False) is record
          case In_Range is
          when False => null;
          when True  => Temperature : Temperatures.Celsius_T;
          end case;
       end record;
       --
       -- A temperature, measured through the ADC.
       -- The ADC reading can be In the expected Range, in which
       -- case we have a Temperature. If the reading is out of
       -- range, we have no temperature (it might be interesting
       -- to have here the ADC count, for diagnostic purposes).
       --
       -- The default initial value of a Reading is "not In Range".

       Saturation : Boolean := True;
       --
       -- Whether the temperature is saturated at its lower or
       -- upper limit when the ADC count is out of range.
       -- If this option is True, the Temperature functions below
       -- always return a temperature, never an out-of-range
       -- indication. If the ADC count is below the minimum
       -- expected value, the minimum temperature is returned;
       -- if the ADC count is above the maximum expected value,
       -- the maximum temperature is returned. If this option is
       -- False, the Temperature functions do not return a
       -- temperature when the ADC count is out of range but
       -- instead give an out-of-range indication.

       function Temperature (Count : Count_T)
       return Reading_T;
       --
       -- The temperature corresponding to the given ADC Count,
       -- following the Saturation option defined above. When
       -- saturation is not used the in-range/out-of-range
       -- status is shown by the In_Range component.

       Out_Of_Range : exception;
       --
       -- Signals an out-of-range ADC reading for temperature.
       -- See function Temperature, below.

       function Temperature (Count : Count_T)
       return Temperatures.Celsius_T;
       --
       -- The temperature corresponding to the given ADC Count,
       -- following the Saturation option defined above. When
       -- saturation is not used and the Count is out of the
       -- range expected for the thermometer, the function
       -- propagates the Out_Of_Range exception.

    end ADC.Thermometer;


To finish this posting, here is the package body. It follows the 
inerpolation logic of the C code but makes saturation optional. Also, it 
handles separately the case where the Index becomes the last index of 
the calibration table, where I think the C code uses Index+1 incorrectly 
as an index to the Table.


package body ADC.Thermometer is

    use type Temperatures.Celsius_T;
    --
    -- We will need to compute with values of this type, so we
    -- like to have easy access to the operators for this type.

    -- The conversion from ADC counts to Celsius degrees uses linear
    -- interpolation in a table of temperatures for a sequence of
    -- calibration points corresponding to equispaced ADC counts in
    -- increasing order.

    Points : constant := 32;
    --
    -- The number of calibration points.

    type Point_Count_T is range 0 .. Points - 1;
    --
    -- A count of calibration points. For example, the number of
    -- points (spacings) from the first calibration point to the
    -- calibration point that precedes a given ADC reading.

    subtype Index_T is Point_Count_T;
    --
    -- The index of a calibration point.

    First_Count : constant Count_T := 220;
    --
    -- The ADC count for the first calibration point.

    Spacing : constant := 8;
    --
    -- The spacing of calibration points (difference in ADC counts
    -- between two adjacent calibration points).

    Last_Count : constant Count_T :=
       First_Count + (Points - 1) * Spacing;
    --
    -- The ADC count for the last calibration point.

    Table : constant array (Index_T) of Temperatures.Celsius_T := (
        0 => 117.1,
        1 => 111.6,
        2 => 106.1,
        3 => 100.6,
        4 =>  95.2,
        5 =>  89.9,
        6 =>  84.6,
        7 =>  79.3,
        8 =>  74.1,
        9 =>  68.9,
       10 =>  63.8,
       11 =>  58.8,
       12 =>  53.7,
       13 =>  48.8,
       14 =>  43.8,
       15 =>  38.9,
       16 =>  34.1,
       17 =>  29.3,
       18 =>  24.6,
       19 =>  19.9,
       20 =>  15.2,
       21 =>  10.6,
       22 =>   6.1,
       23 =>   1.6,
       24 =>  -2.9,
       25 =>  -7.3,
       26 => -11.6,
       27 => -16.0,
       28 => -20.2,
       29 => -24.4,
       30 => -28.6,
       31 => -32.7);
    --
    -- The calibration table. The first entry corresponds to First_Count
    -- and the last entry to Last_Count.

    subtype Interpolation_Distance_T is Natural range 0 .. Spacing - 1;
    --
    -- The difference in ADC counts between an ADC reading and the
    -- preceding calibration point.


    function Temperature (Count : Count_T)
    return Reading_T
    is

       Index : Index_T;
       -- The index in the calibration Table such that the Count
       -- lies in the interval between the calibration points
       -- number Index (inclusive) and Index + 1 (exclusive).

       Interpolation_Distance : Interpolation_Distance_T;
       -- The difference in ADC counts between Count and the
       -- calibration point at Table(Index).

       Temp_Diff : Temperatures.Celsius_T;
       -- The difference in temperature between the calibration
       -- points at Index and Index + 1.
       --
       -- We assume that calibration points are spaced closely
       -- enough that Temp_Diff * (Spacing - 1) stays in range
       -- for Celsius_T.

    begin

       if Count in First_Count .. Last_Count then
          -- The ADC reading is in range for this calibration table.

          Index := Point_Count_T ((Count - First_Count) / Spacing)
                   + Table'First;

          if Index = Table'Last then
             -- Count is Last_Count, so Index + 1 is out of the Table.
             -- But in this case we do not need to interpolate.

             return (In_Range => True, Temperature => Table(Table'Last));

          else
             -- Both Index and Index + 1 are valid Table indices.

             Interpolation_Distance := Interpolation_Distance_T (
                (Count - First_Count) mod Spacing);

             Temp_Diff := Table(Index) - Table(Index + 1);

             return (
                In_Range    => True,
                Temperature =>
                     Table(Index)
                   - (Temp_Diff * Interpolation_Distance) / Spacing);

          end if;

       elsif not Saturation then
          -- We report the out-of-range status.

          return (In_Range => False);

       elsif Count < First_Count then
          -- Saturate at minimum temperature.

          return (In_Range => True, Temperature => Table(Table'First));

       else
          -- Saturate at maximum temperature.

          return (In_Range => True, Temperature => Table(Table'Last));

       end if;

    end Temperature;


    function Temperature (Count : Count_T)
    return Temperatures.Celsius_T
    is

       Reading : constant Reading_T := Temperature (Count);
       -- The temperature, with an in-range/out-of-range indication.

    begin

       if Reading.In_Range then

          return Reading.Temperature;

       else

          raise Out_Of_Range;

       end if;

    end Temperature;

end ADC.Thermometer;



-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .



  parent reply	other threads:[~2007-01-18 16:17 UTC|newest]

Thread overview: 102+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-01-15 14:36 Translating an embedded C algorithm Talulah
2007-01-16  0:06 ` Jeffrey Carter
2007-01-16  1:10   ` Marc A. Criley
2007-01-16  2:21   ` Cesar Rabak
2007-01-16 10:40     ` Markus E Leypold
2007-01-16 14:48       ` Larry Kilgallen
2007-01-16 17:32     ` Jeffrey Carter
2007-01-16 18:04       ` Cesar Rabak
2007-01-17  0:09         ` Jeffrey Carter
2007-01-17  1:07           ` Cesar Rabak
2007-01-16  4:37   ` Alexander E. Kopilovich
2007-01-16 13:37     ` Cesar Rabak
2007-01-16 23:47     ` Simon Wright
2007-01-17  1:02       ` Cesar Rabak
2007-01-16  3:50 ` Vo, Anh (US SSA)
2007-01-16 12:15   ` Niklas Holsti
2007-01-16 23:50     ` Simon Wright
2007-01-18 16:17     ` Niklas Holsti [this message]
2007-01-18 16:41       ` Ludovic Brenta
2007-01-18 20:02         ` Niklas Holsti
2007-01-18 22:25         ` Cesar Rabak
2007-01-19  8:32           ` Niklas Holsti
2007-01-19 19:15             ` Cesar Rabak
2007-01-19 20:49             ` Simon Wright
2007-01-18 16:55       ` Robert A Duff
2007-01-18 18:54         ` Jeffrey Carter
2007-01-19  0:45           ` Robert A Duff
2007-01-18 21:25         ` Niklas Holsti
2007-01-19  0:50           ` Robert A Duff
2007-01-19  4:43           ` Jeffrey Carter
2007-01-18 18:43       ` Jeffrey Carter
2007-01-18 20:19         ` Niklas Holsti
2007-01-18 20:30       ` Niklas Holsti
2007-01-18 23:34       ` Cesar Rabak
2007-01-19  8:57         ` Niklas Holsti
2007-01-19  2:11       ` Steve Whalen
2007-01-19 10:27         ` Niklas Holsti
2007-01-16 13:32   ` Cesar Rabak
2007-01-16 14:47   ` Gautier
2007-01-16 15:15     ` Cesar Rabak
2007-01-16 15:16     ` Jean-Pierre Rosen
2007-01-16 16:12       ` Ludovic Brenta
2007-01-16 17:10         ` Georg Bauhaus
2007-01-16 22:32           ` Ludovic Brenta
2007-01-17 20:22             ` Georg Bauhaus
2007-01-18  9:23               ` Ludovic Brenta
2007-01-16 17:12         ` Cesar Rabak
2007-01-16 17:20           ` Frank J. Lhota
2007-01-16 18:09             ` Cesar Rabak
2007-01-16 17:36           ` Dmitry A. Kazakov
2007-01-16 18:08             ` Cesar Rabak
2007-01-16 18:48               ` Dmitry A. Kazakov
2007-01-16 20:03                 ` Cesar Rabak
2007-01-18 19:33                   ` Björn Persson
2007-01-18 22:32                     ` Cesar Rabak
2007-01-19 20:26                       ` Björn Persson
2007-01-19 23:25                         ` Cesar Rabak
2007-01-19  7:15                     ` Maciej Sobczak
2007-01-19 20:27                       ` Björn Persson
2007-01-19 20:34                         ` Robert A Duff
2007-01-17 13:48           ` Maciej Sobczak
2007-01-17 23:32             ` Translating an embedded C algorithm -- OT Cesar Rabak
2007-01-18  8:56               ` Talulah
2007-01-18 22:05                 ` Cesar Rabak
2007-01-18  9:03               ` Maciej Sobczak
2007-01-18 10:22                 ` Alex R. Mosteo
2007-01-18 18:34                 ` Jeffrey Carter
2007-01-18 22:26                   ` Cesar Rabak
2007-01-19  4:45                     ` Jeffrey Carter
2007-01-18 22:18                 ` Cesar Rabak
2007-01-19 20:53                   ` Simon Wright
2007-01-16 15:55   ` Translating an embedded C algorithm Cesar Rabak
2007-01-17  3:00     ` Vo, Anh (US SSA)
2007-01-17 10:48       ` Cesar Rabak
2007-01-17 11:44       ` Niklas Holsti
2007-01-17 13:31         ` Talulah
2007-01-17 19:20           ` Jeffrey Carter
2007-01-18 14:19             ` Talulah
2007-01-18 15:28               ` Jean-Pierre Rosen
2007-01-18 23:27                 ` Cesar Rabak
2007-01-18 18:51               ` Jeffrey Carter
2007-01-18 22:30                 ` Cesar Rabak
2007-01-19  4:48                   ` Jeffrey Carter
2007-01-19 19:13                     ` Cesar Rabak
2007-01-20 20:56                       ` Jeffrey Carter
2007-01-19  2:21                 ` Alexander E. Kopilovich
2007-01-19  3:25                   ` Larry Kilgallen
2007-01-20  0:46                     ` Alexander E. Kopilovich
2007-01-20 13:03                       ` Larry Kilgallen
2007-01-20 16:54                         ` Alexander E. Kopilovich
2007-01-20 23:53                           ` Larry Kilgallen
2007-01-20 21:02                         ` Jeffrey Carter
2007-01-25 21:59                     ` Markus E Leypold
2007-01-26  4:06                       ` Larry Kilgallen
2007-01-26 11:26                         ` Markus E Leypold
2007-01-26 12:25                           ` Cesar Rabak
2007-01-19  4:52                   ` Jeffrey Carter
2007-01-19 10:13                   ` Warner BRUNS
2007-01-19 14:54                   ` Robert A Duff
2007-01-19  4:08 ` Steve
2007-01-19 20:41   ` Simon Wright
  -- strict thread matches above, loose matches on Subject: below --
2007-01-17  7:07 AW: " Grein, Christoph (Fa. ESG)
2007-01-17 10:26 ` Ludovic Brenta
2007-01-17 16:44   ` Markus E Leypold
2007-01-18  8:49     ` Ludovic Brenta
2007-01-19  9:33       ` Stephen Leake
2007-01-19 19:23         ` Cesar Rabak
2007-01-19 20:27           ` Robert A Duff
2007-01-20  9:54             ` Dmitry A. Kazakov
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox