Subversion Repositories libIgnTiming

Rev

Rev 4 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include <cstdint>
  2. #include <assert.h>
  3. #include "libIgnTiming/timing.h"
  4.  
  5. namespace
  6. {
  7.  
  8.     unsigned constexpr INTERP_SCALE = 256;
  9.  
  10.     unsigned constexpr MAX_TIMING_POINTS = 8;
  11.     unsigned constexpr MAX_VACUUM_POINTS = 8;
  12.     unsigned constexpr TimingScale = TIMING_SCALE;
  13.  
  14.     int16_t rpmMap[MAX_TIMING_POINTS] = {400, 750, 1000, 1500, 2500, 3500, 4500, 6000};
  15.     int16_t vacuumMap[MAX_VACUUM_POINTS] = {0, 166, 225, 300, 700, (int16_t)-1,(int16_t) -1, (int16_t)-1};
  16.     uint8_t mapping[MAX_VACUUM_POINTS][MAX_TIMING_POINTS] = {
  17.         /* Table in degrees. */
  18.         /* row for 0mb = centrifugal only */
  19.         {12, 7, 7, 19, 25, 29, 29, 22},
  20.         /* row for 166 mB*/
  21.         {12, 7, 7, 21, 27, 31, 31, 24},
  22.         /*   row for 225 mB */
  23.         {12, 7, 7, 25, 31, 35, 35, 28},
  24.         /* row for 300 mB*/
  25.         {12, 7, 7, 29, 35, 39, 39, 33},
  26.         /* row for 700 mB*/
  27.         {12, 7, 7, 29, 35, 39, 39, 33},
  28.         /* unused */
  29.         {0, 0, 0, 0, 0, 0, 0, 0},
  30.         /* unused */
  31.         {0, 0, 0, 0, 0, 0, 0, 0},
  32.         /* unused */
  33.         {0, 0, 0, 0, 0, 0, 0, 0}};
  34.  
  35.  
  36. };
  37.  
  38. /// @brief Lookup a point using linear interpolation
  39. /// @param point value to lookup
  40. /// @param curve data point list
  41. /// @param size number of data points in list
  42. /// @param [out] frac fraction of distance between points
  43. /// @return index of first point
  44. int lookup(int point, int16_t const curve[], int size, int16_t *frac)
  45.  
  46. {
  47.     // check lower bounds
  48.     if (point < curve[0])
  49.     {
  50.         *frac = 0;
  51.         return 0;
  52.     }
  53.     // check upper bounds
  54.     // find the upper boundary by looking for non -1 points
  55.     int upper = size - 1;
  56.     while (curve[upper] <= 0)
  57.         upper--;
  58.  
  59.     if (point >= curve[upper])
  60.     {
  61.         frac = 0;
  62.         return upper;
  63.     }
  64.     for (int pt = 1; pt <= upper; pt++)
  65.     {
  66.         if ((point >= curve[pt - 1]) && (point < curve[pt]))
  67.         {
  68.             // how far along axis ?
  69.             int offset = point - curve[pt - 1];
  70.  
  71.             int range1 = curve[pt] - curve[pt - 1];
  72.  
  73.             int range2 = INTERP_SCALE;
  74.  
  75.             *frac = ((offset * range2) / range1);
  76.             return pt - 1;
  77.         }
  78.     }
  79.     *frac = 0;
  80.     return -1; // give up.
  81. };
  82.  
  83. extern "C"
  84. {
  85.  
  86.     int mapTiming(int rpm, int vacuumMb)
  87.     {
  88.         int angle = 0;
  89.         /* lookup the interpolated RPM point */
  90.         int16_t rpm_frac = 0;
  91.         int rpm_index = lookup(rpm, rpmMap, MAX_TIMING_POINTS, &rpm_frac);
  92.  
  93.         /* lookup the interpolated vacuum point */
  94.         int16_t vacuum_frac = 0;
  95.         int vacuum_index = lookup(vacuumMb, vacuumMap, MAX_VACUUM_POINTS, &vacuum_frac);
  96.  
  97.         /* perform a bilinear mapping */
  98.         int top_advance;
  99.         // we now have a position between two points in X and Y
  100.         if (rpm_frac == 0)
  101.             top_advance = mapping[vacuum_index][rpm_index] * INTERP_SCALE;
  102.         // if fractional part then interpolate points off the map
  103.         else
  104.             top_advance = mapping[vacuum_index][rpm_index] * (INTERP_SCALE - rpm_frac) + mapping[vacuum_index][rpm_index + 1] * rpm_frac;
  105.  
  106.         int bottom_advance;
  107.         // if no fractional part, then the top and bottom advance point is the same
  108.         if (vacuum_frac == 0)
  109.         {
  110.             angle = top_advance * TimingScale / INTERP_SCALE ;
  111.         }
  112.         else
  113.         {
  114.             bottom_advance = mapping[vacuum_index + 1][rpm_index] * (INTERP_SCALE - rpm_frac) + mapping[vacuum_index + 1][rpm_index + 1] * rpm_frac;
  115.             /* interpolate down Y axis this time */
  116.             int advance = top_advance * (INTERP_SCALE - vacuum_frac) + bottom_advance * vacuum_frac;
  117.             /* point is scaled by two multiplications */
  118.             angle = advance * TimingScale / (INTERP_SCALE * INTERP_SCALE);
  119.         }
  120.  
  121.         assert((angle >= TimingScale * 7) && (angle < TimingScale * 50 ));
  122.         return angle;
  123.     }
  124. }
  125.  
  126.