Subversion Repositories libIgnTiming

Rev

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

Rev Author Line No. Line
2 mjames 1
#include <cstdint>
2
#include <assert.h>
3
#include "libIgnTiming/timing.h"
4
 
5
namespace
6
{
7
 
8
    unsigned constexpr INTERP_SCALE = 256;
9
 
5 mjames 10
    unsigned constexpr MAX_TIMING_POINTS = 10;
11
    unsigned constexpr MAX_VACUUM_POINTS = 10;
4 mjames 12
    int constexpr TimingScale = TIMING_SCALE;
5 mjames 13
    int16_t constexpr NO_DATA = -1;
2 mjames 14
 
5 mjames 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"))) = {
2 mjames 19
        /* Table in degrees. */
20
        /* row for 0mb = centrifugal only */
5 mjames 21
        {12, 7, 7, 19, 25, 29, 29, 22, 22, 22},
2 mjames 22
        /* row for 166 mB*/
5 mjames 23
        {12, 7, 7, 21, 27, 31, 31, 24, 24, 22},
2 mjames 24
        /*   row for 225 mB */
5 mjames 25
        {12, 7, 7, 25, 31, 35, 35, 28, 24, 22},
2 mjames 26
        /* row for 300 mB*/
5 mjames 27
        {12, 7, 7, 29, 35, 39, 39, 33, 28, 22},
2 mjames 28
        /* row for 700 mB*/
5 mjames 29
        {12, 7, 7, 29, 35, 39, 39, 33, 28, 22},
2 mjames 30
        /* unused */
5 mjames 31
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
2 mjames 32
        /* unused */
5 mjames 33
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
2 mjames 34
        /* unused */
5 mjames 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
    };
2 mjames 41
 
5 mjames 42
}
2 mjames 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
        {
5 mjames 115
            angle = top_advance * TimingScale / INTERP_SCALE;
2 mjames 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
 
5 mjames 126
        assert((angle >= TimingScale * 7) && (angle < TimingScale * 50));
127
        return angle + timingAdjust;
2 mjames 128
    }
129
}