rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
instant_rpm_calculator.cpp
Go to the documentation of this file.
1
2#include "pch.h"
4
5/**
6 * sensorChartMode
7 */
8#include "engine_state.h"
9
10#if EFI_UNIT_TEST
11extern bool printTriggerDebug;
12#endif
13
14#if EFI_SHAFT_POSITION_INPUT
15
17 //https://en.cppreference.com/w/cpp/language/zero_initialization
18 timeOfLastEvent()
19 , instantRpmValue()
20 {
21}
22
24 // here we take timestamps of events which happened prior to synchronization and place them
25 // at appropriate locations
26 auto triggerSize = getTriggerCentral()->triggerShape.getLength();
27
28 size_t eventsToCopy = minI(spinningEventIndex, triggerSize);
29
30 size_t firstSrc;
31 size_t firstDst;
32
33 if (eventsToCopy >= triggerSize) {
34 // Only copy one trigger length worth of events, filling the whole buffer
35 firstSrc = spinningEventIndex - triggerSize;
36 firstDst = 0;
37 } else {
38 // There is less than one full cycle, copy to the end of the buffer
39 firstSrc = 0;
40 firstDst = triggerSize - spinningEventIndex;
41 }
42
43 memcpy(timeOfLastEvent + firstDst, spinningEvents + firstSrc, eventsToCopy * sizeof(timeOfLastEvent[0]));
44}
45
47 TriggerWaveform const & triggerShape, TriggerFormDetails *triggerFormDetails,
48 uint32_t current_index, efitick_t nowNt) {
49
50 // It's OK to truncate from 64b to 32b, ARM with single precision FPU uses an expensive
51 // software function to convert 64b int -> float, while 32b int -> float is very cheap hardware conversion
52 // The difference is guaranteed to be short (it's 90 degrees of engine rotation!), so it won't overflow.
53 uint32_t nowNt32 = nowNt;
54
55 assertIsInBoundsWithResult(current_index, timeOfLastEvent, "calc timeOfLastEvent", 0);
56
57 // Save previous timestamp before overwriting - needed for single-tooth triggers
58 // where prevIndex == current_index (see below)
59 uint32_t previousTimeAtIndex = timeOfLastEvent[current_index];
60
61 // Record the time of this event so we can calculate RPM from it later
62 timeOfLastEvent[current_index] = nowNt32;
63
64 // Determine where we currently are in the revolution
65 angle_t currentAngle = triggerFormDetails->eventAngles[current_index];
66 efiAssert(ObdCode::OBD_PCM_Processor_Fault, !std::isnan(currentAngle), "eventAngles", 0);
67
68 // Hunt for a tooth ~90 degrees ago to compare to the current time
69 angle_t previousAngle = currentAngle - 90;
70 wrapAngle(previousAngle, "prevAngle", ObdCode::CUSTOM_ERR_TRIGGER_ANGLE_RANGE);
71 int prevIndex = triggerShape.findAngleIndex(triggerFormDetails, previousAngle);
72
73 // now let's get precise angle for that event
74 angle_t prevIndexAngle = triggerFormDetails->eventAngles[prevIndex];
75 auto time90ago = timeOfLastEvent[prevIndex];
76 angle_t angleDiff = currentAngle - prevIndexAngle;
77
78 // Wrap the angle in to the correct range (ie, could be -630 when we want +90)
79 wrapAngle(angleDiff, "angleDiff", ObdCode::CUSTOM_ERR_6561);
80
81 // For single-tooth triggers, all event angles map to the same value, so
82 // findAngleIndex returns current_index. This causes two problems:
83 // 1) time90ago was just overwritten with nowNt32, yielding time=0
84 // 2) angleDiff is 0 since both angles are identical
85 // Fix: use the saved previous timestamp and the full engine cycle as angle delta,
86 // effectively measuring RPM from one revolution to the next.
87 if (prevIndex == (int)current_index) {
88 time90ago = previousTimeAtIndex;
89 angleDiff = getEngineState()->engineCycle;
90 }
91
92 // No previous timestamp, instant RPM isn't ready yet
93 if (time90ago == 0) {
95 }
96
97 uint32_t time = nowNt32 - time90ago;
98
99 // just for safety, avoid divide-by-0
100 if (time == 0) {
101 return prevInstantRpmValue;
102 }
103
104 float instantRpm = (60000000.0 / 360 * US_TO_NT_MULTIPLIER) * angleDiff / time;
105 assertIsInBoundsWithResult(current_index, instantRpmValue, "instantRpmValue", 0);
106 instantRpmValue[current_index] = instantRpm;
107
108 // This fixes early RPM instability based on incomplete data
109 if (instantRpm < RPM_LOW_THRESHOLD) {
110 return prevInstantRpmValue;
111 }
112
114
116
117 return instantRpm;
118}
119
121 // here we remember tooth timestamps which happen prior to synchronization
122 if (spinningEventIndex >= efi::size(spinningEvents)) {
123 // too many events while trying to find synchronization point
124 // todo: better implementation would be to shift here or use cyclic buffer so that we keep last
125 // 'PRE_SYNC_EVENTS' events
126 return;
127 }
128
129 uint32_t nowNt32 = nowNt;
131
132 // If we are using only rising edges, we never write in to the odd-index slots that
133 // would be used by falling edges
134 // TODO: don't reach across to trigger central to get this info
136}
137
139 uint32_t current_index,
140 TriggerWaveform const & triggerShape, TriggerFormDetails *triggerFormDetails,
141 uint32_t index, efitick_t nowNt) {
142 UNUSED(current_index);
143
144 m_instantRpm = calculateInstantRpm(triggerShape, triggerFormDetails, index,
145 nowNt);
146#if EFI_UNIT_TEST
147 if (printTriggerDebug) {
148 printf("instantRpm = %f\n", m_instantRpm);
149 }
150#endif
151
152}
153
154#endif // EFI_SHAFT_POSITION_INPUT
angle_t engineCycle
void setLastEventTimeForInstantRpm(efitick_t nowNt)
float instantRpmValue[PWM_PHASE_MAX_COUNT]
float calculateInstantRpm(TriggerWaveform const &triggerShape, TriggerFormDetails *triggerFormDetails, uint32_t index, efitick_t nowNt)
uint32_t timeOfLastEvent[PWM_PHASE_MAX_COUNT]
void updateInstantRpm(uint32_t current_index, TriggerWaveform const &triggerShape, TriggerFormDetails *triggerFormDetails, uint32_t index, efitick_t nowNt)
TriggerWaveform triggerShape
angle_t eventAngles[2 *PWM_PHASE_MAX_COUNT]
Trigger shape has all the fields needed to describe and decode trigger signal.
uint16_t findAngleIndex(TriggerFormDetails *details, angle_t angle) const
size_t getLength() const
TriggerCentral * getTriggerCentral()
Definition engine.cpp:592
EngineState * getEngineState()
Definition engine.cpp:579
One header which acts as gateway to current engine state.
bool printTriggerDebug
UNUSED(samplingTimeSeconds)
@ CUSTOM_ERR_TRIGGER_ANGLE_RANGE
@ CUSTOM_ERR_6561
@ OBD_PCM_Processor_Fault
instantRpm("sync: instant RPM", SensorCategory.SENSOR_INPUTS, FieldType.INT16, 326, 1.0, 0.0, 0.0, "rpm")
bool printTriggerDebug
void wrapAngle(angle_t &angle, const char *msg, ObdCode code)
printf("\n")