2022-11-06 09:03:55 -08:00
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "instant_rpm_calculator.h"
|
|
|
|
|
|
|
|
#if EFI_SENSOR_CHART
|
|
|
|
#include "sensor_chart.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sensorChartMode
|
|
|
|
*/
|
|
|
|
#include "engine_state.h"
|
|
|
|
|
2024-04-17 08:51:29 -07:00
|
|
|
#if EFI_UNIT_TEST
|
|
|
|
extern bool printTriggerDebug;
|
|
|
|
#endif
|
|
|
|
|
2022-12-17 11:43:51 -08:00
|
|
|
#if EFI_SHAFT_POSITION_INPUT
|
|
|
|
|
2022-11-06 09:03:55 -08:00
|
|
|
InstantRpmCalculator::InstantRpmCalculator() :
|
|
|
|
//https://en.cppreference.com/w/cpp/language/zero_initialization
|
|
|
|
timeOfLastEvent()
|
|
|
|
, instantRpmValue()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void InstantRpmCalculator::movePreSynchTimestamps() {
|
|
|
|
// here we take timestamps of events which happened prior to synchronization and place them
|
|
|
|
// at appropriate locations
|
|
|
|
auto triggerSize = getTriggerCentral()->triggerShape.getLength();
|
|
|
|
|
|
|
|
size_t eventsToCopy = minI(spinningEventIndex, triggerSize);
|
|
|
|
|
|
|
|
size_t firstSrc;
|
|
|
|
size_t firstDst;
|
|
|
|
|
|
|
|
if (eventsToCopy >= triggerSize) {
|
|
|
|
// Only copy one trigger length worth of events, filling the whole buffer
|
|
|
|
firstSrc = spinningEventIndex - triggerSize;
|
|
|
|
firstDst = 0;
|
|
|
|
} else {
|
|
|
|
// There is less than one full cycle, copy to the end of the buffer
|
|
|
|
firstSrc = 0;
|
|
|
|
firstDst = triggerSize - spinningEventIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(timeOfLastEvent + firstDst, spinningEvents + firstSrc, eventsToCopy * sizeof(timeOfLastEvent[0]));
|
|
|
|
}
|
|
|
|
|
|
|
|
float InstantRpmCalculator::calculateInstantRpm(
|
|
|
|
TriggerWaveform const & triggerShape, TriggerFormDetails *triggerFormDetails,
|
|
|
|
uint32_t current_index, efitick_t nowNt) {
|
|
|
|
|
2024-04-25 16:50:35 -07:00
|
|
|
// It's OK to truncate from 64b to 32b, ARM with single precision FPU uses an expensive
|
|
|
|
// software function to convert 64b int -> float, while 32b int -> float is very cheap hardware conversion
|
|
|
|
// The difference is guaranteed to be short (it's 90 degrees of engine rotation!), so it won't overflow.
|
|
|
|
uint32_t nowNt32 = nowNt;
|
|
|
|
|
2022-11-06 09:03:55 -08:00
|
|
|
assertIsInBoundsWithResult(current_index, timeOfLastEvent, "calc timeOfLastEvent", 0);
|
|
|
|
|
|
|
|
// Record the time of this event so we can calculate RPM from it later
|
2024-04-25 16:50:35 -07:00
|
|
|
timeOfLastEvent[current_index] = nowNt32;
|
2022-11-06 09:03:55 -08:00
|
|
|
|
|
|
|
// Determine where we currently are in the revolution
|
|
|
|
angle_t currentAngle = triggerFormDetails->eventAngles[current_index];
|
2024-07-22 12:05:17 -07:00
|
|
|
efiAssert(ObdCode::OBD_PCM_Processor_Fault, !std::isnan(currentAngle), "eventAngles", 0);
|
2022-11-06 09:03:55 -08:00
|
|
|
|
|
|
|
// Hunt for a tooth ~90 degrees ago to compare to the current time
|
2023-02-21 18:43:05 -08:00
|
|
|
angle_t previousAngle = currentAngle - 90;
|
2023-10-19 14:34:29 -07:00
|
|
|
wrapAngle(previousAngle, "prevAngle", ObdCode::CUSTOM_ERR_TRIGGER_ANGLE_RANGE);
|
2022-11-06 09:03:55 -08:00
|
|
|
int prevIndex = triggerShape.findAngleIndex(triggerFormDetails, previousAngle);
|
|
|
|
|
|
|
|
// now let's get precise angle for that event
|
|
|
|
angle_t prevIndexAngle = triggerFormDetails->eventAngles[prevIndex];
|
2024-04-25 16:54:27 -07:00
|
|
|
auto time90ago = timeOfLastEvent[prevIndex];
|
2022-11-06 09:03:55 -08:00
|
|
|
|
|
|
|
// No previous timestamp, instant RPM isn't ready yet
|
|
|
|
if (time90ago == 0) {
|
|
|
|
return prevInstantRpmValue;
|
|
|
|
}
|
|
|
|
|
2024-04-25 16:50:35 -07:00
|
|
|
uint32_t time = nowNt32 - time90ago;
|
2022-11-06 09:03:55 -08:00
|
|
|
angle_t angleDiff = currentAngle - prevIndexAngle;
|
|
|
|
|
|
|
|
// Wrap the angle in to the correct range (ie, could be -630 when we want +90)
|
2023-10-19 14:34:29 -07:00
|
|
|
wrapAngle(angleDiff, "angleDiff", ObdCode::CUSTOM_ERR_6561);
|
2022-11-06 09:03:55 -08:00
|
|
|
|
|
|
|
// just for safety, avoid divide-by-0
|
|
|
|
if (time == 0) {
|
|
|
|
return prevInstantRpmValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
float instantRpm = (60000000.0 / 360 * US_TO_NT_MULTIPLIER) * angleDiff / time;
|
|
|
|
assertIsInBoundsWithResult(current_index, instantRpmValue, "instantRpmValue", 0);
|
|
|
|
instantRpmValue[current_index] = instantRpm;
|
|
|
|
|
|
|
|
// This fixes early RPM instability based on incomplete data
|
|
|
|
if (instantRpm < RPM_LOW_THRESHOLD) {
|
|
|
|
return prevInstantRpmValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
prevInstantRpmValue = instantRpm;
|
|
|
|
|
|
|
|
m_instantRpmRatio = instantRpm / instantRpmValue[prevIndex];
|
|
|
|
|
|
|
|
return instantRpm;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InstantRpmCalculator::setLastEventTimeForInstantRpm(efitick_t nowNt) {
|
|
|
|
// here we remember tooth timestamps which happen prior to synchronization
|
|
|
|
if (spinningEventIndex >= efi::size(spinningEvents)) {
|
|
|
|
// too many events while trying to find synchronization point
|
|
|
|
// todo: better implementation would be to shift here or use cyclic buffer so that we keep last
|
|
|
|
// 'PRE_SYNC_EVENTS' events
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-04-25 16:50:35 -07:00
|
|
|
uint32_t nowNt32 = nowNt;
|
|
|
|
spinningEvents[spinningEventIndex] = nowNt32;
|
2022-11-06 09:03:55 -08:00
|
|
|
|
|
|
|
// If we are using only rising edges, we never write in to the odd-index slots that
|
|
|
|
// would be used by falling edges
|
2022-11-08 18:48:39 -08:00
|
|
|
// TODO: don't reach across to trigger central to get this info
|
|
|
|
spinningEventIndex += getTriggerCentral()->triggerShape.useOnlyRisingEdges ? 2 : 1;
|
2022-11-06 09:03:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void InstantRpmCalculator::updateInstantRpm(
|
|
|
|
uint32_t current_index,
|
|
|
|
TriggerWaveform const & triggerShape, TriggerFormDetails *triggerFormDetails,
|
|
|
|
uint32_t index, efitick_t nowNt) {
|
|
|
|
|
|
|
|
m_instantRpm = calculateInstantRpm(triggerShape, triggerFormDetails, index,
|
|
|
|
nowNt);
|
2024-04-17 08:51:29 -07:00
|
|
|
#if EFI_UNIT_TEST
|
|
|
|
if (printTriggerDebug) {
|
|
|
|
printf("instantRpm = %f\n", m_instantRpm);
|
|
|
|
}
|
|
|
|
#endif
|
2022-11-06 09:03:55 -08:00
|
|
|
|
|
|
|
#if EFI_SENSOR_CHART
|
|
|
|
if (getEngineState()->sensorChartMode == SC_RPM_ACCEL || getEngineState()->sensorChartMode == SC_DETAILED_RPM) {
|
|
|
|
angle_t currentAngle = triggerFormDetails->eventAngles[current_index];
|
|
|
|
if (engineConfiguration->sensorChartMode == SC_DETAILED_RPM) {
|
|
|
|
scAddData(currentAngle, m_instantRpm);
|
|
|
|
} else {
|
|
|
|
scAddData(currentAngle, m_instantRpmRatio);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* EFI_SENSOR_CHART */
|
|
|
|
}
|
2022-12-17 11:43:51 -08:00
|
|
|
|
2023-04-28 21:13:13 -07:00
|
|
|
#endif // EFI_SHAFT_POSITION_INPUT
|