Impl. faster engine spin-up mode (alpha-version) (#567)
* Impl. faster engine spin-up mode (alpha-version) * A comment for RPM_LOW_THRESHOLD * Faster engine stop detection * Safety check for instant RPM on spinning-up * rusefi.xml * unit-tests & relevant fixes
This commit is contained in:
parent
29159e90a3
commit
ac0189270e
|
@ -106,7 +106,8 @@
|
|||
#undef EFI_CJ125_DIRECTLY_CONNECTED_UR
|
||||
#define EFI_CJ125_DIRECTLY_CONNECTED_UR TRUE
|
||||
|
||||
#define RPM_LOW_THRESHOLD 60
|
||||
#define RPM_LOW_THRESHOLD 8 // RPM=8 is an empirical lower sensitivity threshold of MAX9926 for 60-2
|
||||
#define NO_RPM_EVENTS_TIMEOUT_SECS 5 // (RPM < 12)
|
||||
|
||||
#define EFI_PRINT_ERRORS_AS_WARNINGS TRUE
|
||||
|
||||
|
|
|
@ -376,9 +376,6 @@ void Engine::watchdog() {
|
|||
return;
|
||||
}
|
||||
efitick_t nowNt = getTimeNowNt();
|
||||
#ifndef RPM_LOW_THRESHOLD
|
||||
#define RPM_LOW_THRESHOLD 240
|
||||
#endif
|
||||
// note that we are ignoring the number of tooth here - we
|
||||
// check for duration between tooth as if we only have one tooth per revolution which is not the case
|
||||
#define REVOLUTION_TIME_HIGH_THRESHOLD (60 * 1000000LL / RPM_LOW_THRESHOLD)
|
||||
|
|
|
@ -35,6 +35,9 @@ EXTERN_ENGINE
|
|||
|
||||
extern EnginePins enginePins;
|
||||
|
||||
// Store current ignition mode for prepareIgnitionPinIndices()
|
||||
static ignition_mode_e ignitionModeForPinIndices;
|
||||
|
||||
floatms_t getEngineCycleDuration(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||
return getCrankshaftRevolutionTimeMs(rpm) * (engineConfiguration->operationMode == TWO_STROKE ? 1 : 2);
|
||||
}
|
||||
|
@ -461,7 +464,7 @@ int getCylinderId(int index DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|||
}
|
||||
|
||||
static int getIgnitionPinForIndex(int i DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||
switch (CONFIG(ignitionMode)) {
|
||||
switch (getIgnitionMode(PASS_ENGINE_PARAMETER_SIGNATURE)) {
|
||||
case IM_ONE_COIL:
|
||||
return 0;
|
||||
break;
|
||||
|
@ -479,6 +482,25 @@ static int getIgnitionPinForIndex(int i DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|||
}
|
||||
}
|
||||
|
||||
void prepareIgnitionPinIndices(ignition_mode_e ignitionMode DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||
if (ignitionMode != ignitionModeForPinIndices) {
|
||||
#if EFI_ENGINE_CONTROL || defined(__DOXYGEN__)
|
||||
for (int i = 0; i < CONFIG(specs.cylindersCount); i++) {
|
||||
ENGINE(ignitionPin[i]) = getIgnitionPinForIndex(i PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
}
|
||||
#endif /* EFI_ENGINE_CONTROL */
|
||||
ignitionModeForPinIndices = ignitionMode;
|
||||
}
|
||||
}
|
||||
|
||||
ignition_mode_e getIgnitionMode(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||
ignition_mode_e ignitionMode = CONFIG(ignitionMode);
|
||||
// In spin-up cranking mode we don't have full phase sync. info yet, so wasted spark mode is better
|
||||
if (ignitionMode == IM_INDIVIDUAL_COILS && ENGINE(rpmCalculator.isSpinningUp(PASS_ENGINE_PARAMETER_SIGNATURE)))
|
||||
ignitionMode = IM_WASTED_SPARK;
|
||||
return ignitionMode;
|
||||
}
|
||||
|
||||
void TriggerShape::prepareShape(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||
int engineCycleInt = (int) getEngineCycle(CONFIG(operationMode));
|
||||
for (int angle = 0; angle < engineCycleInt; angle++) {
|
||||
|
@ -515,9 +537,10 @@ void prepareOutputSignals(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|||
|
||||
for (int i = 0; i < CONFIG(specs.cylindersCount); i++) {
|
||||
ENGINE(angleExtra[i])= ENGINE(engineCycle) * i / CONFIG(specs.cylindersCount);
|
||||
ENGINE(ignitionPin[i]) = getIgnitionPinForIndex(i PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
}
|
||||
|
||||
prepareIgnitionPinIndices(CONFIG(ignitionMode) PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
|
||||
TRIGGER_SHAPE(prepareShape(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,14 @@ float getEngineLoadT(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
|||
|
||||
floatms_t getSparkDwell(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
|
||||
ignition_mode_e getIgnitionMode(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||
|
||||
/**
|
||||
* This lightweight method is invoked in case of a configuration change or initialization.
|
||||
* But also it's used for "Spinning-up to Cranking" transition.
|
||||
*/
|
||||
void prepareIgnitionPinIndices(ignition_mode_e ignitionMode DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
|
||||
int getCylinderId(int index DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
|
||||
void setFuelRpmBin(float from, float to DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
|
|
|
@ -478,8 +478,9 @@ void mainTriggerCallback(trigger_event_e ckpSignalType, uint32_t trgEventIndex D
|
|||
if (checkIfTriggerConfigChanged()) {
|
||||
engine->ignitionEvents.isReady = false; // we need to rebuild ignition schedule
|
||||
engine->injectionEvents.isReady = false;
|
||||
// todo: move 'triggerIndexByAngle' change into trigger initialization, why is it invoked from here if it's only about trigger shape & optimization?
|
||||
prepareOutputSignals(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
// moved 'triggerIndexByAngle' into trigger initialization (why was it invoked from here if it's only about trigger shape & optimization?)
|
||||
// see initializeTriggerShape() -> prepareOutputSignals(PASS_ENGINE_PARAMETER_SIGNATURE)
|
||||
|
||||
// we need this to apply new 'triggerIndexByAngle' values
|
||||
engine->periodicFastCallback(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ RpmCalculator::RpmCalculator() {
|
|||
previousRpmValue = rpmValue = 0;
|
||||
oneDegreeUs = NAN;
|
||||
state = STOPPED;
|
||||
isSpinning = false;
|
||||
|
||||
// we need this initial to have not_running at first invocation
|
||||
lastRpmEventTimeNt = (efitime_t) -10 * US2NT(US_PER_SECOND_LL);
|
||||
|
@ -69,11 +70,17 @@ RpmCalculator::RpmCalculator() {
|
|||
}
|
||||
|
||||
bool RpmCalculator::isStopped(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||
return state == STOPPED;
|
||||
// Spinning-up with zero RPM means that the engine is not ready yet, and is treated as 'stopped'.
|
||||
return state == STOPPED || (state == SPINNING_UP && rpmValue == 0);
|
||||
}
|
||||
|
||||
bool RpmCalculator::isSpinningUp(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||
return state == SPINNING_UP;
|
||||
}
|
||||
|
||||
bool RpmCalculator::isCranking(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||
return state == CRANKING;
|
||||
// Spinning-up with non-zero RPM is suitable for all engine math, as good as cranking
|
||||
return state == CRANKING || (state == SPINNING_UP && rpmValue > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,8 +110,12 @@ bool RpmCalculator::checkIfSpinning(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|||
* we have a trigger event between the time we've invoked 'getTimeNow' and here
|
||||
*/
|
||||
bool noRpmEventsForTooLong = nowNt - lastRpmEventTimeNt >= US2NT(NO_RPM_EVENTS_TIMEOUT_SECS * US_PER_SECOND_LL); // Anything below 60 rpm is not running
|
||||
if (noRpmEventsForTooLong) {
|
||||
setStopped(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
/**
|
||||
* Also check if there were no trigger events
|
||||
*/
|
||||
bool noTriggerEventsForTooLong = nowNt - engine->triggerCentral.previousShaftEventTimeNt >= US2NT(US_PER_SECOND_LL);
|
||||
if (noRpmEventsForTooLong || noTriggerEventsForTooLong) {
|
||||
setStopSpinning(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -118,29 +129,42 @@ void RpmCalculator::assignRpmValue(int value DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|||
oneDegreeUs = NAN;
|
||||
} else {
|
||||
oneDegreeUs = getOneDegreeTimeUs(rpmValue);
|
||||
if (previousRpmValue == 0) {
|
||||
/**
|
||||
* this would make sure that we have good numbers for first cranking revolution
|
||||
* #275 cranking could be improved
|
||||
*/
|
||||
ENGINE(periodicFastCallback(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RpmCalculator::setRpmValue(int value DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||
assignRpmValue(value PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
if (previousRpmValue == 0 && rpmValue > 0) {
|
||||
/**
|
||||
* this would make sure that we have good numbers for first cranking revolution
|
||||
* #275 cranking could be improved
|
||||
*/
|
||||
ENGINE(periodicFastCallback(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
}
|
||||
spinning_state_e oldState = state;
|
||||
// Change state
|
||||
if (rpmValue == 0) {
|
||||
state = STOPPED;
|
||||
} else if (rpmValue >= CONFIG(cranking.rpm)) {
|
||||
state = RUNNING;
|
||||
} else if (state == STOPPED) {
|
||||
} else if (state == STOPPED || state == SPINNING_UP) {
|
||||
/**
|
||||
* We are here if RPM is above zero but we have not seen running RPM yet.
|
||||
* This gives us cranking hysteresis - a drop of RPM during running is still running, not cranking.
|
||||
*/
|
||||
state = CRANKING;
|
||||
}
|
||||
#if EFI_ENGINE_CONTROL || defined(__DOXYGEN__)
|
||||
// This presumably fixes injection mode change for cranking-to-running transition.
|
||||
// 'isSimultanious' flag should be updated for events if injection modes differ for cranking and running.
|
||||
if (state != oldState) {
|
||||
engine->injectionEvents.addFuelEvents(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
spinning_state_e RpmCalculator::getState(void) {
|
||||
return state;
|
||||
}
|
||||
|
||||
void RpmCalculator::onNewEngineCycle() {
|
||||
|
@ -172,6 +196,27 @@ void RpmCalculator::setStopped(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|||
state = STOPPED;
|
||||
}
|
||||
|
||||
void RpmCalculator::setStopSpinning(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||
isSpinning = false;
|
||||
setStopped(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
}
|
||||
|
||||
void RpmCalculator::setSpinningUp(efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||
if (!boardConfiguration->isFasterEngineSpinUpEnabled)
|
||||
return;
|
||||
// Only a completely stopped and non-spinning engine can enter the spinning-up state.
|
||||
if (isStopped(PASS_ENGINE_PARAMETER_SIGNATURE) && !isSpinning) {
|
||||
state = SPINNING_UP;
|
||||
isSpinning = true;
|
||||
}
|
||||
// update variables needed by early instant RPM calc.
|
||||
if (isSpinningUp(PASS_ENGINE_PARAMETER_SIGNATURE)) {
|
||||
engine->triggerCentral.triggerState.setLastEventTimeForInstantRpm(nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
}
|
||||
// Update ignition pin indices if needed
|
||||
prepareIgnitionPinIndices(getIgnitionMode(PASS_ENGINE_PARAMETER_SIGNATURE) PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: this is a heavy method because 'getRpm()' is relatively heavy
|
||||
*
|
||||
|
@ -202,9 +247,10 @@ void rpmShaftPositionCallback(trigger_event_e ckpSignalType,
|
|||
efiAssertVoid(getRemainingStack(chThdGetSelfX()) > 256, "lowstckRCL");
|
||||
#endif
|
||||
|
||||
RpmCalculator *rpmState = &engine->rpmCalculator;
|
||||
|
||||
if (index == 0) {
|
||||
ENGINE(m.beforeRpmCb) = GET_TIMESTAMP();
|
||||
RpmCalculator *rpmState = &engine->rpmCalculator;
|
||||
|
||||
bool hadRpmRecently = rpmState->checkIfSpinning(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
|
||||
|
@ -241,6 +287,17 @@ void rpmShaftPositionCallback(trigger_event_e ckpSignalType,
|
|||
}
|
||||
#endif
|
||||
|
||||
// Replace 'normal' RPM with instant RPM for the initial spin-up period
|
||||
if (rpmState->isSpinningUp(PASS_ENGINE_PARAMETER_SIGNATURE)) {
|
||||
int prevIndex;
|
||||
int iRpm = engine->triggerCentral.triggerState.calculateInstantRpm(&prevIndex, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
// validate instant RPM - we shouldn't skip the cranking state
|
||||
iRpm = minI(iRpm, CONFIG(cranking.rpm) - 1);
|
||||
rpmState->assignRpmValue(iRpm PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
#if 0
|
||||
scheduleMsg(logger, "** RPM: idx=%d sig=%d iRPM=%d", index, ckpSignalType, iRpm);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static scheduling_s tdcScheduler[2];
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
#define NOISY_RPM -1
|
||||
#define UNREALISTIC_RPM 30000
|
||||
|
||||
#ifndef RPM_LOW_THRESHOLD
|
||||
#define RPM_LOW_THRESHOLD 240
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
typedef enum {
|
||||
|
@ -66,7 +70,11 @@ public:
|
|||
*/
|
||||
bool isStopped(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||
/**
|
||||
* Returns true if the engine is cranking
|
||||
* Returns true if the engine is spinning up
|
||||
*/
|
||||
bool isSpinningUp(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||
/**
|
||||
* Returns true if the engine is cranking OR spinning up
|
||||
*/
|
||||
bool isCranking(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||
/**
|
||||
|
@ -76,6 +84,20 @@ public:
|
|||
|
||||
bool checkIfSpinning(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||
|
||||
/**
|
||||
* This accessor is used in unit-tests.
|
||||
*/
|
||||
spinning_state_e getState(void);
|
||||
|
||||
/**
|
||||
* Should be called on every trigger event when the engine is just starting to spin up.
|
||||
*/
|
||||
void setSpinningUp(efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
/**
|
||||
* Called if the synchronization is lost due to a trigger timeout.
|
||||
*/
|
||||
void setStopSpinning(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||
|
||||
int getRpm(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||
/**
|
||||
* This method is invoked once per engine cycle right after we calculate new RPM value
|
||||
|
@ -83,6 +105,11 @@ public:
|
|||
void onNewEngineCycle();
|
||||
uint32_t getRevolutionCounter(void);
|
||||
void setRpmValue(int value DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
/**
|
||||
* The same as setRpmValue() but without state change.
|
||||
* We need this to be public because of calling rpmState->assignRpmValue() from rpmShaftPositionCallback()
|
||||
*/
|
||||
void assignRpmValue(int value DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
uint32_t getRevolutionCounterSinceStart(void);
|
||||
/**
|
||||
* RPM rate of change between current RPM and RPM measured during previous engine cycle
|
||||
|
@ -110,10 +137,6 @@ private:
|
|||
*/
|
||||
void setStopped(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||
|
||||
/**
|
||||
* The same as setRpmValue() but without state change
|
||||
*/
|
||||
void assignRpmValue(int value DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
/**
|
||||
* This counter is incremented with each revolution of one of the shafts. Could be
|
||||
* crankshaft could be camshaft.
|
||||
|
@ -125,6 +148,12 @@ private:
|
|||
volatile uint32_t revolutionCounterSinceStart;
|
||||
|
||||
spinning_state_e state;
|
||||
|
||||
/**
|
||||
* True if the engine is spinning (regardless of its state), i.e. if shaft position changes.
|
||||
* Needed by spinning-up logic.
|
||||
*/
|
||||
bool isSpinning;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -81,7 +81,7 @@ static void turnSparkPinHigh2(IgnitionEvent *event, IgnitionOutputPin *output) {
|
|||
#if ! EFI_UNIT_TEST || defined(__DOXYGEN__)
|
||||
if (GET_RPM() > 2 * engineConfiguration->cranking.rpm) {
|
||||
const char *outputName = output->name;
|
||||
if (prevSparkName == outputName && engineConfiguration->ignitionMode != IM_ONE_COIL) {
|
||||
if (prevSparkName == outputName && getIgnitionMode(PASS_ENGINE_PARAMETER_SIGNATURE) != IM_ONE_COIL) {
|
||||
warning(CUSTOM_OBD_SKIPPED_SPARK, "looks like skipped spark event %d %s", getRevolutionCounter(), outputName);
|
||||
}
|
||||
prevSparkName = outputName;
|
||||
|
@ -230,7 +230,7 @@ void prepareIgnitionSchedule(IgnitionEvent *event DECLARE_ENGINE_PARAMETER_SUFFI
|
|||
IgnitionOutputPin *output = &enginePins.coils[coilIndex];
|
||||
|
||||
IgnitionOutputPin *secondOutput;
|
||||
if (CONFIG(ignitionMode) == IM_WASTED_SPARK && CONFIG(twoWireBatchIgnition)) {
|
||||
if (getIgnitionMode(PASS_ENGINE_PARAMETER_SIGNATURE) == IM_WASTED_SPARK && CONFIG(twoWireBatchIgnition)) {
|
||||
int secondIndex = index + CONFIG(specs.cylindersCount) / 2;
|
||||
int secondCoilIndex = ID2INDEX(getCylinderId(secondIndex PASS_ENGINE_PARAMETER_SUFFIX));
|
||||
secondOutput = &enginePins.coils[secondCoilIndex];
|
||||
|
@ -288,7 +288,7 @@ static ALWAYS_INLINE void prepareIgnitionSchedule(DECLARE_ENGINE_PARAMETER_SIGNA
|
|||
*/
|
||||
float maxAllowedDwellAngle = (int) (getEngineCycle(engineConfiguration->operationMode) / 2); // the cast is about making Coverity happy
|
||||
|
||||
if (engineConfiguration->ignitionMode == IM_ONE_COIL) {
|
||||
if (getIgnitionMode(PASS_ENGINE_PARAMETER_SIGNATURE) == IM_ONE_COIL) {
|
||||
maxAllowedDwellAngle = getEngineCycle(engineConfiguration->operationMode) / engineConfiguration->specs.cylindersCount / 1.1;
|
||||
}
|
||||
|
||||
|
@ -381,7 +381,7 @@ int getNumberOfSparks(ignition_mode_e mode DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|||
* @see getInjectorDutyCycle
|
||||
*/
|
||||
percent_t getCoilDutyCycle(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||
floatms_t totalPerCycle = 1/**getInjectionDuration(rpm PASS_ENGINE_PARAMETER_SUFFIX)*/ * getNumberOfSparks(engineConfiguration->ignitionMode PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
floatms_t totalPerCycle = 1/**getInjectionDuration(rpm PASS_ENGINE_PARAMETER_SUFFIX)*/ * getNumberOfSparks(getIgnitionMode(PASS_ENGINE_PARAMETER_SIGNATURE) PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
floatms_t engineCycleDuration = getCrankshaftRevolutionTimeMs(rpm) * (engineConfiguration->operationMode == TWO_STROKE ? 1 : 2);
|
||||
return 100 * totalPerCycle / engineCycleDuration;
|
||||
}
|
||||
|
|
|
@ -602,6 +602,10 @@ bool readIfTriggerConfigChangedForUnitTest(void) {
|
|||
return isTriggerConfigChanged;
|
||||
}
|
||||
|
||||
void resetTriggerConfigChangedForUnitTest(void) {
|
||||
isTriggerConfigChanged = false;
|
||||
}
|
||||
|
||||
void initTriggerCentral(Logging *sharedLogger) {
|
||||
logger = sharedLogger;
|
||||
strcpy((char*) shaft_signal_msg_index, "x_");
|
||||
|
|
|
@ -66,5 +66,6 @@ void resetMaxValues();
|
|||
void onConfigurationChangeTriggerCallback(engine_configuration_s *previousConfiguration DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
bool checkIfTriggerConfigChanged(void);
|
||||
bool readIfTriggerConfigChangedForUnitTest(void);
|
||||
void resetTriggerConfigChangedForUnitTest(void);
|
||||
|
||||
#endif /* TRIGGER_CENTRAL_H_ */
|
||||
|
|
|
@ -169,6 +169,8 @@ void TriggerState::resetCurrentCycleState() {
|
|||
|
||||
void TriggerState::onSynchronizationLost(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||
shaft_is_synchronized = false;
|
||||
// Needed for early instant-RPM detection
|
||||
engine->rpmCalculator.setStopSpinning(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -436,6 +438,10 @@ void TriggerState::decodeTriggerEvent(trigger_event_e const signal, efitime_t no
|
|||
|
||||
runtimeStatistics(nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
|
||||
// Needed for early instant-RPM detection
|
||||
if (!isInitializingTrigger) {
|
||||
engine->rpmCalculator.setSpinningUp(nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -644,6 +650,9 @@ void TriggerShape::initializeTriggerShape(Logging *logger DECLARE_ENGINE_PARAMET
|
|||
unlockAnyContext();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Moved here from mainTriggerCallback()
|
||||
prepareOutputSignals(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
}
|
||||
|
||||
static void onFindIndexCallback(TriggerState *state) {
|
||||
|
|
|
@ -134,8 +134,17 @@ public:
|
|||
* instant RPM calculated at this trigger wheel tooth
|
||||
*/
|
||||
float instantRpmValue[PWM_PHASE_MAX_COUNT];
|
||||
/**
|
||||
* Stores last non-zero instant RPM value to fix early instability
|
||||
*/
|
||||
float prevInstantRpmValue;
|
||||
float calculateInstantRpm(int *prevIndex, efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
virtual void runtimeStatistics(efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
/**
|
||||
* Update timeOfLastEvent[] on every trigger event - even without synchronization
|
||||
* Needed for early spin-up RPM detection.
|
||||
*/
|
||||
void setLastEventTimeForInstantRpm(efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
};
|
||||
|
||||
angle_t getEngineCycle(operation_mode_e operationMode);
|
||||
|
|
|
@ -182,6 +182,12 @@ void TriggerState::runtimeStatistics(efitime_t nowNt DECLARE_ENGINE_PARAMETER_SU
|
|||
|
||||
TriggerStateWithRunningStatistics::TriggerStateWithRunningStatistics() {
|
||||
instantRpm = 0;
|
||||
prevInstantRpmValue = 0;
|
||||
// avoid ill-defined instant RPM when the data is not gathered yet
|
||||
efitime_t nowNt = getTimeNowNt();
|
||||
for (int i = 0; i < PWM_PHASE_MAX_COUNT; i++) {
|
||||
timeOfLastEvent[i] = nowNt;
|
||||
}
|
||||
}
|
||||
|
||||
float TriggerStateWithRunningStatistics::calculateInstantRpm(int *prevIndex, efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||
|
@ -203,13 +209,26 @@ float TriggerStateWithRunningStatistics::calculateInstantRpm(int *prevIndex, efi
|
|||
// todo: angle diff should be pre-calculated
|
||||
fixAngle(angleDiff, "angleDiff");
|
||||
|
||||
// just for safety
|
||||
if (time == 0)
|
||||
return prevInstantRpmValue;
|
||||
|
||||
float instantRpm = (60000000.0 / 360 * US_TO_NT_MULTIPLIER) * angleDiff / time;
|
||||
instantRpmValue[current_index] = instantRpm;
|
||||
timeOfLastEvent[current_index] = nowNt;
|
||||
|
||||
// This fixes early RPM instability based on incomplete data
|
||||
if (instantRpm < RPM_LOW_THRESHOLD)
|
||||
return prevInstantRpmValue;
|
||||
prevInstantRpmValue = instantRpm;
|
||||
|
||||
return instantRpm;
|
||||
}
|
||||
|
||||
void TriggerStateWithRunningStatistics::setLastEventTimeForInstantRpm(efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||
timeOfLastEvent[currentCycle.current_index] = nowNt;
|
||||
}
|
||||
|
||||
void TriggerStateWithRunningStatistics::runtimeStatistics(efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||
if (engineConfiguration->debugMode == DBG_INSTANT_RPM) {
|
||||
int prevIndex;
|
||||
|
|
|
@ -70,6 +70,7 @@ EngineTestHelper::EngineTestHelper(engine_type_e engineType) : engine (&persiste
|
|||
engine->triggerCentral.triggerShape.initializeTriggerShape(NULL PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
engine->triggerCentral.addEventListener(rpmShaftPositionCallback, "rpm reporter", engine);
|
||||
engine->triggerCentral.addEventListener(mainTriggerCallback, "main loop", engine);
|
||||
resetTriggerConfigChangedForUnitTest();
|
||||
}
|
||||
|
||||
void EngineTestHelper::firePrimaryTriggerRise() {
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "test_signal_executor.h"
|
||||
#include "trigger_central.h"
|
||||
#include "test_startOfCrankingPrimingPulse.h"
|
||||
#include "test_fasterEngineSpinningUp.h"
|
||||
#include "test_util.h"
|
||||
#include "map_resize.h"
|
||||
#include "engine_math.h"
|
||||
|
@ -74,6 +75,7 @@ int main(void) {
|
|||
testFindIndex();
|
||||
testPlainCrankingWithoutAdvancedFeatures();
|
||||
testStartOfCrankingPrimingPulse();
|
||||
testFasterEngineSpinningUp();
|
||||
testInterpolate2d();
|
||||
testGpsParser();
|
||||
testMisc();
|
||||
|
|
|
@ -5,6 +5,7 @@ TEST_SRC_CPP = test_util.cpp \
|
|||
test_basic_math/test_interpolation_3d.cpp \
|
||||
test_data_structures/test_engine_math.cpp \
|
||||
test_startOfCrankingPrimingPulse.cpp \
|
||||
test_fasterEngineSpinningUp.cpp \
|
||||
test_idle_controller.cpp \
|
||||
test_trigger_decoder.cpp \
|
||||
test_fuel_map.cpp \
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* test_fasterEngineSpinningUp.cpp
|
||||
*
|
||||
* Created on: Mar 6, 2018
|
||||
*/
|
||||
|
||||
#include "engine_math.h"
|
||||
#include "test_fasterEngineSpinningUp.h"
|
||||
#include "test_trigger_decoder.h"
|
||||
#include "event_queue.h"
|
||||
#include "unit_test_framework.h"
|
||||
|
||||
extern EventQueue schedulingQueue;
|
||||
extern int timeNowUs;
|
||||
extern EnginePins enginePins;
|
||||
|
||||
void testFasterEngineSpinningUp() {
|
||||
// this is just a reference unit test implementation
|
||||
printf("*************************************************** testFasterEngineSpinningUp\r\n");
|
||||
|
||||
EngineTestHelper eth(TEST_ENGINE);
|
||||
EXPAND_EngineTestHelper
|
||||
|
||||
// turn on FasterEngineSpinUp mode
|
||||
engineConfiguration->bc.isFasterEngineSpinUpEnabled = true;
|
||||
// set ignition mode
|
||||
engineConfiguration->ignitionMode = IM_INDIVIDUAL_COILS;
|
||||
// set cranking threshold (used below)
|
||||
engineConfiguration->cranking.rpm = 999;
|
||||
// set sequential injection mode to test auto-change to simultaneous when spinning-up
|
||||
setupSimpleTestEngineWithMafAndTT_ONE_trigger(ð, IM_SEQUENTIAL);
|
||||
|
||||
// check if it's true
|
||||
assertEquals(IM_SEQUENTIAL, engine->getCurrentInjectionMode(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
assertEquals(IM_INDIVIDUAL_COILS, getIgnitionMode(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
// check if the engine has the right state
|
||||
assertEquals(STOPPED, engine->rpmCalculator.getState());
|
||||
// check RPM
|
||||
assertEqualsM("RPM=0", 0, engine->rpmCalculator.getRpm(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
// the queue should be empty, no trigger events yet
|
||||
assertEqualsM("plain#1", 0, schedulingQueue.size());
|
||||
|
||||
// check all events starting from now
|
||||
int timeStartUs = timeNowUs;
|
||||
// advance 1 revolution
|
||||
timeNowUs += MS2US(200);
|
||||
eth.firePrimaryTriggerRise();
|
||||
|
||||
// check if the mode is changed
|
||||
assertEquals(SPINNING_UP, engine->rpmCalculator.getState());
|
||||
// due to isFasterEngineSpinUp=true, we should have already detected RPM!
|
||||
assertEqualsM("RPM#1", 300, engine->rpmCalculator.getRpm(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
// two simultaneous injections
|
||||
assertEqualsM("plain#1", 4, schedulingQueue.size());
|
||||
// test if they are simultaneous
|
||||
assertEquals(IM_SIMULTANEOUS, engine->getCurrentInjectionMode(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
// test if ignition mode is temporary changed to wasted spark, if set to ind.coils
|
||||
assertEquals(IM_WASTED_SPARK, getIgnitionMode(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
// check real events
|
||||
assertEvent5("inj start#1", 0, (void*)startSimultaniousInjection, timeStartUs, MS2US(200) + 97975);
|
||||
assertEvent5("inj end#1", 1, (void*)endSimultaniousInjection, timeStartUs, MS2US(200) + 100000);
|
||||
|
||||
// skip the rest of the cycle
|
||||
timeNowUs += MS2US(200);
|
||||
eth.firePrimaryTriggerFall();
|
||||
|
||||
// now clear and advance more
|
||||
eth.clearQueue();
|
||||
timeNowUs += MS2US(200);
|
||||
eth.firePrimaryTriggerRise();
|
||||
|
||||
// check if the mode is changed when fully synched
|
||||
assertEquals(CRANKING, engine->rpmCalculator.getState());
|
||||
// check RPM
|
||||
assertEqualsM("RPM#2", 300, engine->rpmCalculator.getRpm(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
// test if they are simultaneous in cranking mode too
|
||||
assertEquals(IM_SIMULTANEOUS, engine->getCurrentInjectionMode(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
// test if ignition mode is restored to ind.coils
|
||||
assertEquals(IM_INDIVIDUAL_COILS, getIgnitionMode(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
// two simultaneous injections
|
||||
assertEqualsM("plain#2", 4, schedulingQueue.size());
|
||||
// check real events
|
||||
assertEvent5("inj start#2", 0, (void*)startSimultaniousInjection, timeNowUs, 97975);
|
||||
assertEvent5("inj end#2", 1, (void*)endSimultaniousInjection, timeNowUs, 100000);
|
||||
|
||||
// skip, clear & advance 1 more revolution at higher RPM
|
||||
timeNowUs += MS2US(60);
|
||||
eth.firePrimaryTriggerFall();
|
||||
|
||||
eth.clearQueue();
|
||||
timeStartUs = timeNowUs;
|
||||
eth.fireTriggerEvents2(1, MS2US(60));
|
||||
|
||||
// check if the mode is now changed to 'running' at higher RPM
|
||||
assertEquals(RUNNING, engine->rpmCalculator.getState());
|
||||
// check RPM
|
||||
assertEqualsM("RPM#3", 1000, engine->rpmCalculator.getRpm(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
// check if the injection mode is back to sequential now
|
||||
assertEquals(IM_SEQUENTIAL, engine->getCurrentInjectionMode(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
// 4 sequential injections for the full cycle
|
||||
assertEqualsM("plain#3", 8, schedulingQueue.size());
|
||||
|
||||
// check real events for sequential injection
|
||||
// Note: See addFuelEvents() fix inside setRpmValue()!
|
||||
assertEvent5("inj start#3", 0, (void*)seTurnPinHigh, timeStartUs, MS2US(60) + 27974);
|
||||
assertEvent5("inj end#3", 1, (void*)seTurnPinLow, timeStartUs, MS2US(60) + 27974 + 3000);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* test_fasterEngineSpinningUp.h
|
||||
*
|
||||
* Created on: Mar 6, 2018
|
||||
*/
|
||||
|
||||
#ifndef TEST_FASTERENGINESPINNINGUP_H_
|
||||
#define TEST_FASTERENGINESPINNINGUP_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
void testFasterEngineSpinningUp();
|
||||
|
||||
#endif /* TEST_FASTERENGINESPINNINGUP_H_ */
|
|
@ -315,8 +315,9 @@ void testRpmCalculator(void) {
|
|||
timeNowUs = 0;
|
||||
assertEquals(0, eth.engine.rpmCalculator.getRpm(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
|
||||
assertEquals(4, TRIGGER_SHAPE(triggerIndexByAngle[240]));
|
||||
assertEquals(4, TRIGGER_SHAPE(triggerIndexByAngle[241]));
|
||||
// triggerIndexByAngle update is now fixed! prepareOutputSignals() wasn't reliably called
|
||||
assertEquals(5, TRIGGER_SHAPE(triggerIndexByAngle[240]));
|
||||
assertEquals(5, TRIGGER_SHAPE(triggerIndexByAngle[241]));
|
||||
|
||||
eth.fireTriggerEvents(48);
|
||||
|
||||
|
@ -619,7 +620,7 @@ static void assertInjectionEvent(const char *msg, InjectionEvent *ev, int inject
|
|||
assertEqualsM4(msg, " event offset", angleOffset, ev->injectionStart.angleOffset);
|
||||
}
|
||||
|
||||
void setupSimpleTestEngineWithMafAndTT_ONE_trigger(EngineTestHelper *eth) {
|
||||
void setupSimpleTestEngineWithMafAndTT_ONE_trigger(EngineTestHelper *eth, injection_mode_e injMode) {
|
||||
Engine *engine = ð->engine;
|
||||
EXPAND_Engine
|
||||
|
||||
|
@ -629,7 +630,10 @@ void setupSimpleTestEngineWithMafAndTT_ONE_trigger(EngineTestHelper *eth) {
|
|||
assertEquals(LM_PLAIN_MAF, engineConfiguration->fuelAlgorithm);
|
||||
engineConfiguration->isIgnitionEnabled = false; // let's focus on injection
|
||||
engineConfiguration->specs.cylindersCount = 4;
|
||||
engineConfiguration->injectionMode = IM_BATCH;
|
||||
// a bit of flexibility - the mode may be changed by some tests
|
||||
engineConfiguration->injectionMode = injMode;
|
||||
// set cranking mode (it's used by getCurrentInjectionMode())
|
||||
engineConfiguration->crankingInjectionMode = IM_SIMULTANEOUS;
|
||||
|
||||
setArrayValues(config->cltFuelCorrBins, CLT_CURVE_SIZE, 1);
|
||||
setArrayValues(engineConfiguration->injector.battLagCorr, VBAT_INJECTOR_CURVE_SIZE, 0);
|
||||
|
|
|
@ -20,6 +20,6 @@ void testRpmCalculator(void);
|
|||
void testStartupFuelPumping(void);
|
||||
void test1995FordInline6TriggerDecoder(void);
|
||||
void testTriggerDecoder2(const char *msg, engine_type_e type, int synchPointIndex, float channel1duty, float channel2duty);
|
||||
void setupSimpleTestEngineWithMafAndTT_ONE_trigger(EngineTestHelper *eth);
|
||||
void setupSimpleTestEngineWithMafAndTT_ONE_trigger(EngineTestHelper *eth, injection_mode_e injMode = IM_BATCH);
|
||||
|
||||
#endif /* TEST_TRIGGER_DECODER_H_ */
|
||||
|
|
Loading…
Reference in New Issue