Subversion Repositories libIgnTiming

Rev

Rev 8 | 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"
11 mjames 4
 
5
#if !defined WRITABLE_TABLE
6
#define CONST_ATTR constexpr
7
#endif
8
 
7 mjames 9
#if defined __cplusplus
10
extern "C"
2 mjames 11
{
7 mjames 12
#endif
2 mjames 13
 
7 mjames 14
    namespace
15
    {
11 mjames 16
        int8_t timingAdjust = 0 * TIMING_SCALE; // in TIMING_SCALE
2 mjames 17
 
7 mjames 18
        unsigned constexpr INTERP_SCALE = 256;
2 mjames 19
 
7 mjames 20
        int constexpr TimingScale = TIMING_SCALE;
21
        int16_t constexpr NO_DATA = -1;
6 mjames 22
 
11 mjames 23
        int16_t constexpr MAX_ADVANCE = 50 * TIMING_SCALE;
24
        int16_t constexpr MIN_ADVANCE = 7 * TIMING_SCALE;
2 mjames 25
 
7 mjames 26
        // array of column headings
11 mjames 27
        int16_t CONST_ATTR rpmMap[MAX_RPM_POINTS] = {400, 750, 1000, 1500, 2500, 3500, 4500, 6000};
28
        // column of row values - in 1000-pressure
29
        int16_t CONST_ATTR vacuumMap[MAX_VACUUM_POINTS] = {0, 166, 225, 300, 700, 1000, NO_DATA, NO_DATA};
30
        uint8_t CONST_ATTR mapping[MAX_VACUUM_POINTS][MAX_RPM_POINTS] = {
7 mjames 31
            /* Table in degrees. */
32
            /* row for 0mb = centrifugal only */
33
            {12, 7, 7, 19, 25, 29, 29, 22},
34
            /* row for 166 mB*/
35
            {12, 7, 7, 21, 27, 31, 31, 24},
36
            /*   row for 225 mB */
37
            {12, 7, 7, 25, 31, 35, 35, 28},
38
            /* row for 300 mB*/
39
            {12, 7, 7, 29, 35, 39, 39, 33},
40
            /* row for 700 mB*/
11 mjames 41
            {12, 7, 7, 19, 25, 29, 29, 22},
7 mjames 42
            /* row for 1000 mB - used when pressure drops off the scale */
43
            {7, 7, 7, 7, 7, 7, 7, 7},
44
            /* unused */
45
            {0, 0, 0, 0, 0, 0, 0, 0},
46
            /* unused */
47
            {0, 0, 0, 0, 0, 0, 0, 0},
48
            /* unused */
2 mjames 49
 
7 mjames 50
        };
6 mjames 51
 
7 mjames 52
    }
6 mjames 53
 
7 mjames 54
    uint8_t getTimingAdjust() { return timingAdjust; };
6 mjames 55
 
7 mjames 56
    void setTimingAdjust(int8_t adjust) { timingAdjust = adjust; }
6 mjames 57
 
7 mjames 58
    int16_t getRpmMap(unsigned int i)
59
    {
60
        if (i >= 0 && i < MAX_RPM_POINTS)
61
            return rpmMap[i];
62
        else
63
            return 0;
64
    }
6 mjames 65
 
7 mjames 66
    void setRpmMap(unsigned int i, uint16_t val)
67
    {
11 mjames 68
#if WRITABLE_TABLE
7 mjames 69
        if (i >= 0 && i < MAX_RPM_POINTS)
70
            rpmMap[i] = val;
11 mjames 71
#endif
7 mjames 72
    }
6 mjames 73
 
7 mjames 74
    uint16_t getVacuumMap(unsigned int i)
75
    {
76
        if (i >= 0 && i < MAX_VACUUM_POINTS)
77
            return vacuumMap[i];
78
        else
79
            return 0;
80
    }
6 mjames 81
 
7 mjames 82
    void setVacuumMap(unsigned int i, uint16_t val)
83
    {
11 mjames 84
#if WRITABLE_TABLE
7 mjames 85
        if (i >= 0 && i < MAX_VACUUM_POINTS)
86
            vacuumMap[i] = val;
11 mjames 87
#endif
7 mjames 88
    }
6 mjames 89
 
7 mjames 90
    void setTiming(unsigned int vacuumIndex, unsigned int rpmIndex, uint8_t value)
2 mjames 91
    {
11 mjames 92
 
93
#if WRITABLE_TABLE
7 mjames 94
        if (vacuumIndex < 0 && vacuumIndex >= MAX_VACUUM_POINTS)
95
            return;
96
        if (rpmIndex < 0 && rpmIndex >= MAX_RPM_POINTS)
97
            return;
98
        mapping[vacuumIndex][rpmIndex] = value;
11 mjames 99
#endif
2 mjames 100
    }
101
 
7 mjames 102
    uint8_t getTiming(unsigned int vacuumIndex, unsigned int rpmIndex)
2 mjames 103
    {
7 mjames 104
        if (vacuumIndex < 0 && vacuumIndex >= MAX_VACUUM_POINTS)
105
            return 0;
106
        if (rpmIndex < 0 && rpmIndex >= MAX_RPM_POINTS)
107
            return 0;
108
        return mapping[vacuumIndex][rpmIndex];
2 mjames 109
    }
7 mjames 110
 
11 mjames 111
    /// @brief Lookup a point in a 1 dimensional array -
112
    /// @param point Value to lookup
113
    /// @param curve Lookup table
114
    /// @param size Size of lookup table
115
    /// @param [out] frac fraction of distance from first point in array
116
    /// @return index in array or NO_DATA if operations fail 
7 mjames 117
    int lookup(int point, int16_t const curve[], int size, int16_t *frac)
2 mjames 118
    {
7 mjames 119
        // check lower bounds
120
        if (point < curve[0])
2 mjames 121
        {
7 mjames 122
            *frac = 0;
123
            return 0;
124
        }
125
        // check upper bounds
126
        // find the upper boundary by looking for non -1 points
127
        int upper = size - 1;
8 mjames 128
        while (upper != 0 && curve[upper] == NO_DATA)
7 mjames 129
            upper--;
2 mjames 130
 
7 mjames 131
        if (point >= curve[upper])
132
        {
133
            *frac = 0;
134
            return upper;
135
        }
136
        for (int pt = 1; pt <= upper; pt++)
137
        {
138
            if ((point >= curve[pt - 1]) && (point < curve[pt]))
139
            {
2 mjames 140
 
7 mjames 141
                int range1 = curve[pt] - curve[pt - 1];
2 mjames 142
 
7 mjames 143
                if (range1 == 0)
144
                {
145
                    *frac = 0;
146
                    return pt - 1;
147
                }
148
 
149
                // how far along axis ?
150
                int offset = point - curve[pt - 1];
151
 
152
                int range2 = INTERP_SCALE;
153
 
154
                *frac = ((offset * range2) / range1);
155
                return pt - 1;
156
            }
2 mjames 157
        }
7 mjames 158
        *frac = 0;
11 mjames 159
        return NO_DATA; // give up.
7 mjames 160
    };
2 mjames 161
 
7 mjames 162
    extern "C"
2 mjames 163
    {
164
 
7 mjames 165
        int mapTiming(int rpm, int vacuumMb)
166
        {
167
            int angle = 0;
168
            /* lookup the interpolated RPM point */
169
            int16_t rpm_frac = 0;
170
            int rpm_index = lookup(rpm, rpmMap, MAX_RPM_POINTS, &rpm_frac);
171
            if (rpm_index == NO_DATA)
172
                return timingAdjust + MIN_ADVANCE;
2 mjames 173
 
7 mjames 174
            /* lookup the interpolated vacuum point */
175
            int16_t vacuum_frac = 0;
176
            int vacuum_index = lookup(vacuumMb, vacuumMap, MAX_VACUUM_POINTS, &vacuum_frac);
177
            /* if there is a problem, bail out */
178
            if (vacuum_index == NO_DATA)
179
                return timingAdjust + MIN_ADVANCE;
2 mjames 180
 
7 mjames 181
            /* perform a bilinear mapping */
182
            int top_advance;
183
            // we now have a position between two points in X and Y
184
            if (rpm_frac == 0)
185
                top_advance = mapping[vacuum_index][rpm_index] * INTERP_SCALE;
186
            // if fractional part then interpolate points off the map
187
            else
188
                top_advance = mapping[vacuum_index][rpm_index] * (INTERP_SCALE - rpm_frac) + mapping[vacuum_index][rpm_index + 1] * rpm_frac;
189
 
190
            int bottom_advance;
191
            // if no fractional part, then the top and bottom advance point is the same
192
            if (vacuum_frac == 0)
193
            {
194
                angle = top_advance * TimingScale / INTERP_SCALE;
195
            }
196
            else
197
            {
198
                bottom_advance = mapping[vacuum_index + 1][rpm_index] * (INTERP_SCALE - rpm_frac) + mapping[vacuum_index + 1][rpm_index + 1] * rpm_frac;
199
                /* interpolate down Y axis this time */
200
                int advance = top_advance * (INTERP_SCALE - vacuum_frac) + bottom_advance * vacuum_frac;
201
                /* point is scaled by two multiplications */
202
                angle = advance * TimingScale / (INTERP_SCALE * INTERP_SCALE);
203
            }
204
 
205
            if (angle < MIN_ADVANCE)
206
                angle = MIN_ADVANCE;
207
            if (angle > MAX_ADVANCE)
208
                angle = MAX_ADVANCE;
209
 
210
            return angle + timingAdjust;
2 mjames 211
        }
212
    }
7 mjames 213
#if defined __cplusplus
2 mjames 214
}
7 mjames 215
#endif