Subversion Repositories libIgnTiming

Rev

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