mirror of https://github.com/FOME-Tech/fome-fw.git
Toyota ETCS-i [02/02]: RedundantSensor: partial second (avoid average, etc.) (#431)
This commit is contained in:
parent
d37a5c1405
commit
50f7a653a7
|
@ -48,27 +48,28 @@ SensorResult RedundantSensor::get() const {
|
||||||
} else {
|
} else {
|
||||||
// Sensor is partially redundant; useful for some sensors: e.g. Ford and Toyota ETCS-i
|
// Sensor is partially redundant; useful for some sensors: e.g. Ford and Toyota ETCS-i
|
||||||
|
|
||||||
// The threshold at which to switch to partial redundancy, just below maximum to avoid misbehavior near 100%
|
// The partial redundancy threshold, slightly less than 100% to avoid issues near full-range
|
||||||
float threshold = m_secondMaximum * 0.95f;
|
float threshold = m_secondMaximum * 0.95f;
|
||||||
|
|
||||||
// The scaled second sensor, proportioning it to the first sensor
|
// Scale the second sensor value accordingly, proportioning to the first sensor
|
||||||
float scaledSecond = sensor2.Value * m_secondMaximum / 100;
|
float scaledSecond = sensor2.Value * m_secondMaximum / 100;
|
||||||
|
|
||||||
// Check second sensor is below partial redundancy switch-over threshold
|
// Check second sensor is below partial redundancy switch-over threshold
|
||||||
if (scaledSecond <= threshold) {
|
if (scaledSecond <= threshold) {
|
||||||
float delta = absF(sensor1.Value - scaledSecond);
|
float delta = absF(sensor1.Value - scaledSecond);
|
||||||
if (delta <= m_maxDifference) {
|
if (delta <= m_maxDifference) {
|
||||||
// All is well: sensors are valid and values check out, return the average value
|
// All is well: sensors are valid and values check out, return the primary value
|
||||||
return (sensor1.Value + scaledSecond) / 2;
|
return sensor1.Value;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check first sensor is at or above partial redundancy switch-over threshold
|
// Check first sensor is at or above partial redundancy switch-over threshold
|
||||||
if (sensor1.Value >= m_secondMaximum - m_maxDifference) {
|
if (sensor1.Value >= m_secondMaximum - m_maxDifference) {
|
||||||
|
// All is well: sensors are valid and values check out, return the primary value
|
||||||
return sensor1.Value;
|
return sensor1.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall-through and any other condition indicates an unexpected discrepancy, return inconsistency error
|
// Any other condition indicates an unexpected discrepancy, return inconsistency error
|
||||||
return UnexpectedCode::Inconsistent;
|
return UnexpectedCode::Inconsistent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ public:
|
||||||
SensorType secondSensor
|
SensorType secondSensor
|
||||||
);
|
);
|
||||||
|
|
||||||
void configure(float maxDifference, bool ignoreSecondSensor, float secondaryMaximum);
|
void configure(float maxDifference, bool ignoreSecondSensor, float secondaryMaximum = 100);
|
||||||
|
|
||||||
SensorResult get() const override;
|
SensorResult get() const override;
|
||||||
|
|
||||||
|
|
|
@ -401,7 +401,7 @@ injector_s injector
|
||||||
injector_s injectorSecondary
|
injector_s injectorSecondary
|
||||||
|
|
||||||
bit isForcedInduction;Does the vehicle have a turbo or supercharger?
|
bit isForcedInduction;Does the vehicle have a turbo or supercharger?
|
||||||
bit useFordRedundantTps;On some Ford and Toyota vehicles one of the throttle sensors is not linear on the full range, i.e. in the specific range of the positions we effectively have only one sensor.
|
bit unusedFordTps
|
||||||
bit lambdaProtectionEnable
|
bit lambdaProtectionEnable
|
||||||
bit overrideTriggerGaps
|
bit overrideTriggerGaps
|
||||||
bit enableFan1WithAc;Turn on this fan when AC is on.
|
bit enableFan1WithAc;Turn on this fan when AC is on.
|
||||||
|
@ -423,7 +423,7 @@ bit useTLE8888_stepper
|
||||||
bit usescriptTableForCanSniffingFiltering
|
bit usescriptTableForCanSniffingFiltering
|
||||||
bit verboseCan,"Print all","Do not print";Print incoming and outgoing first bus CAN messages in FOME console
|
bit verboseCan,"Print all","Do not print";Print incoming and outgoing first bus CAN messages in FOME console
|
||||||
bit artificialTestMisfire,"Danger Mode","No thank you";Experimental setting that will cause a misfire\nDO NOT ENABLE.
|
bit artificialTestMisfire,"Danger Mode","No thank you";Experimental setting that will cause a misfire\nDO NOT ENABLE.
|
||||||
bit useFordRedundantPps;On some Ford and Toyota vehicles one of the pedal sensors is not linear on the full range, i.e. in the specific range of the positions we effectively have only one sensor.
|
bit unusedFordPps
|
||||||
bit cltSensorPulldown
|
bit cltSensorPulldown
|
||||||
bit iatSensorPulldown
|
bit iatSensorPulldown
|
||||||
bit allowIdenticalPps
|
bit allowIdenticalPps
|
||||||
|
@ -1413,8 +1413,8 @@ uint8_t alsEtbPosition;;"", 1, 0, 0, 20000, 0
|
||||||
uint8_t ALSMaxDriverThrottleIntent;;"%", 1, 0, 0, 10, 0
|
uint8_t ALSMaxDriverThrottleIntent;;"%", 1, 0, 0, 10, 0
|
||||||
pin_input_mode_e ALSActivatePinMode;
|
pin_input_mode_e ALSActivatePinMode;
|
||||||
|
|
||||||
uint8_t autoscale tpsSecondaryMaximum;For Ford TPS, use 53%. For Toyota ETCS-i, use ~65%;"%", 0.5, 0, 0, 100, 1
|
uint8_t autoscale tpsSecondaryMaximum;For Ford TPS, use 53%. For Toyota ETCS-i, use ~65%. 0 and 100 disable, <20 invalid, rest will avoid sensor averaging.;"%", 0.5, 0, 0, 100, 1
|
||||||
uint8_t autoscale ppsSecondaryMaximum;For Toyota ETCS-i, use ~69%;"%", 0.5, 0, 0, 100, 1
|
uint8_t autoscale ppsSecondaryMaximum;For Toyota ETCS-i, use ~69%. 0 and 100 disable, <20 invalid, rest will avoid sensor averaging.;"%", 0.5, 0, 0, 100, 1
|
||||||
pin_input_mode_e[LUA_DIGITAL_INPUT_COUNT iterate] luaDigitalInputPinModes;
|
pin_input_mode_e[LUA_DIGITAL_INPUT_COUNT iterate] luaDigitalInputPinModes;
|
||||||
|
|
||||||
uint8_t autoscale rpmHardLimitHyst;If the hard limit is 7200rpm and hysteresis is 200rpm, then when the ECU sees 7200rpm, fuel/ign will cut, and stay cut until 7000rpm (7200-200) is reached;"RPM", 10, 0, 0, 2500, 0
|
uint8_t autoscale rpmHardLimitHyst;If the hard limit is 7200rpm and hysteresis is 200rpm, then when the ECU sees 7200rpm, fuel/ign will cut, and stay cut until 7000rpm (7200-200) is reached;"RPM", 10, 0, 0, 2500, 0
|
||||||
|
|
|
@ -4461,21 +4461,22 @@ dialog = tcuControls, "Transmission Settings"
|
||||||
field = "Disable after revolutions", acrRevolutions
|
field = "Disable after revolutions", acrRevolutions
|
||||||
field = "Disable after engine phase", acrDisablePhase
|
field = "Disable after engine phase", acrDisablePhase
|
||||||
|
|
||||||
|
dialog = parkingLotRedundantSensors, "Sensor Redundancy"
|
||||||
|
field = "Partial Secondary TPS Maximum", tpsSecondaryMaximum
|
||||||
|
field = "Partial Secondary PPS Maximum", ppsSecondaryMaximum
|
||||||
|
field = "BRZ/FRS/GT86 pedal", allowIdenticalPps
|
||||||
|
|
||||||
dialog = parkingLot, "Experimental/Broken"
|
dialog = parkingLot, "Experimental/Broken"
|
||||||
field = "I understand ECU Locking", yesUnderstandLocking
|
field = "I understand ECU Locking", yesUnderstandLocking
|
||||||
field = "Tune read/write password", tuneHidingKey, { yesUnderstandLocking == 1 }
|
field = "Tune read/write password", tuneHidingKey, { yesUnderstandLocking == 1 }
|
||||||
field = "#System hacks"
|
field = "#System hacks"
|
||||||
field = "Global fuel correction", globalFuelCorrection
|
field = "Global fuel correction", globalFuelCorrection
|
||||||
field = "MAP Averaging Logic @", mapAveragingSchedulingAtIndex
|
field = "MAP Averaging Logic @", mapAveragingSchedulingAtIndex
|
||||||
field = "Ford redundant TPS mode", useFordRedundantTps
|
|
||||||
field = "Secondary TPS maximum", tpsSecondaryMaximum, {useFordRedundantTps}
|
|
||||||
field = "Ford redundant PPS mode", useFordRedundantPps
|
|
||||||
field = "Secondary PPS maximum", ppsSecondaryMaximum, {useFordRedundantPps}
|
|
||||||
field = "ADC vRef voltage", adcVcc
|
field = "ADC vRef voltage", adcVcc
|
||||||
field = "CLT sensor is pulldown instead of pullup", cltSensorPulldown
|
field = "CLT sensor is pulldown instead of pullup", cltSensorPulldown
|
||||||
field = "IAT sensor is pulldown instead of pullup", iatSensorPulldown
|
field = "IAT sensor is pulldown instead of pullup", iatSensorPulldown
|
||||||
field = "Analog divider ratio", analogInputDividerCoefficient@@if_ts_show_analog_divider
|
field = "Analog divider ratio", analogInputDividerCoefficient@@if_ts_show_analog_divider
|
||||||
field = "BRZ/FRS/GT86 pedal", allowIdenticalPps
|
panel = parkingLotRedundantSensors
|
||||||
field = "Artificial Misfire", artificialTestMisfire
|
field = "Artificial Misfire", artificialTestMisfire
|
||||||
field = "Instant Rpm Range", instantRpmRange
|
field = "Instant Rpm Range", instantRpmRange
|
||||||
field = "Always use instant RPM", alwaysInstantRpm
|
field = "Always use instant RPM", alwaysInstantRpm
|
||||||
|
|
|
@ -24,7 +24,7 @@ protected:
|
||||||
ASSERT_TRUE(m1.Register());
|
ASSERT_TRUE(m1.Register());
|
||||||
ASSERT_TRUE(m2.Register());
|
ASSERT_TRUE(m2.Register());
|
||||||
|
|
||||||
dut.configure(5.0f, false, 100);
|
dut.configure(5.0f, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TearDown() override
|
void TearDown() override
|
||||||
|
@ -58,23 +58,11 @@ TEST_F(SensorRedundant, SetOnlyOneSensor)
|
||||||
auto result = dut.get();
|
auto result = dut.get();
|
||||||
EXPECT_FALSE(result.Valid);
|
EXPECT_FALSE(result.Valid);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SensorRedundant, SetTwoSensors)
|
|
||||||
{
|
|
||||||
// Don't set any sensors - expect invalid
|
|
||||||
{
|
|
||||||
auto result = dut.get();
|
|
||||||
EXPECT_FALSE(result.Valid);
|
|
||||||
EXPECT_EQ(result.Code, UnexpectedCode::Inconsistent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set one sensor
|
|
||||||
m1.set(24.0f);
|
|
||||||
// Set the other sensor
|
// Set the other sensor
|
||||||
m2.set(26.0f);
|
m2.set(26.0f);
|
||||||
|
|
||||||
// Should now be valid - and the average of the two input
|
// Should now be valid - and the average of both sensors
|
||||||
{
|
{
|
||||||
auto result = dut.get();
|
auto result = dut.get();
|
||||||
EXPECT_TRUE(result.Valid);
|
EXPECT_TRUE(result.Valid);
|
||||||
|
@ -82,6 +70,18 @@ TEST_F(SensorRedundant, SetTwoSensors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SensorRedundant, CheckOnlySecondInvalid)
|
||||||
|
{
|
||||||
|
// Set second sensor only
|
||||||
|
m2.set(66.0f);
|
||||||
|
|
||||||
|
// Should be invalid - only one is set!
|
||||||
|
{
|
||||||
|
auto result = dut.get();
|
||||||
|
EXPECT_FALSE(result.Valid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(SensorRedundant, DifferenceNone)
|
TEST_F(SensorRedundant, DifferenceNone)
|
||||||
{
|
{
|
||||||
// Set both sensors to the same value
|
// Set both sensors to the same value
|
||||||
|
@ -136,7 +136,6 @@ TEST_F(SensorRedundant, DifferenceOverLimitSwapped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SensorRedundantIgnoreSecond : public ::testing::Test
|
class SensorRedundantIgnoreSecond : public ::testing::Test
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
@ -159,7 +158,7 @@ protected:
|
||||||
ASSERT_TRUE(m1.Register());
|
ASSERT_TRUE(m1.Register());
|
||||||
ASSERT_TRUE(m2.Register());
|
ASSERT_TRUE(m2.Register());
|
||||||
|
|
||||||
dut.configure(5.0f, true, 100);
|
dut.configure(5.0f, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TearDown() override
|
void TearDown() override
|
||||||
|
@ -175,6 +174,7 @@ TEST_F(SensorRedundantIgnoreSecond, CheckIsRedundant)
|
||||||
EXPECT_FALSE(dut.isRedundant());
|
EXPECT_FALSE(dut.isRedundant());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SensorRedundantIgnoreSecond, OnlyFirst)
|
TEST_F(SensorRedundantIgnoreSecond, OnlyFirst)
|
||||||
{
|
{
|
||||||
// Don't set any sensors - expect invalid
|
// Don't set any sensors - expect invalid
|
||||||
|
@ -184,7 +184,7 @@ TEST_F(SensorRedundantIgnoreSecond, OnlyFirst)
|
||||||
EXPECT_EQ(result.Code, UnexpectedCode::Unknown);
|
EXPECT_EQ(result.Code, UnexpectedCode::Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set one sensor
|
// Set first sensor
|
||||||
m1.set(44.0f);
|
m1.set(44.0f);
|
||||||
|
|
||||||
// Should be valid - we don't care about second sensor
|
// Should be valid - we don't care about second sensor
|
||||||
|
@ -193,17 +193,20 @@ TEST_F(SensorRedundantIgnoreSecond, OnlyFirst)
|
||||||
EXPECT_TRUE(result.Valid);
|
EXPECT_TRUE(result.Valid);
|
||||||
EXPECT_FLOAT_EQ(result.Value, 44.0f);
|
EXPECT_FLOAT_EQ(result.Value, 44.0f);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SensorRedundantIgnoreSecond, OnlySecond)
|
// Set the second sensor too
|
||||||
{
|
m2.set(46.0f);
|
||||||
// Don't set any sensors - expect invalid
|
|
||||||
|
// Should be valid, but only get the value from m1
|
||||||
{
|
{
|
||||||
auto result = dut.get();
|
auto result = dut.get();
|
||||||
EXPECT_FALSE(result.Valid);
|
EXPECT_TRUE(result.Valid);
|
||||||
EXPECT_EQ(result.Code, UnexpectedCode::Unknown);
|
EXPECT_FLOAT_EQ(result.Value, 44.0f);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SensorRedundantIgnoreSecond, CheckOnlySecondInvalid)
|
||||||
|
{
|
||||||
// Set second sensor only
|
// Set second sensor only
|
||||||
m2.set(66.0f);
|
m2.set(66.0f);
|
||||||
|
|
||||||
|
@ -214,27 +217,6 @@ TEST_F(SensorRedundantIgnoreSecond, OnlySecond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SensorRedundantIgnoreSecond, SetBothIgnoreSecond)
|
|
||||||
{
|
|
||||||
// Don't set any sensors - expect invalid
|
|
||||||
{
|
|
||||||
auto result = dut.get();
|
|
||||||
EXPECT_FALSE(result.Valid);
|
|
||||||
EXPECT_EQ(result.Code, UnexpectedCode::Unknown);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set both sensors
|
|
||||||
m1.set(74.0f);
|
|
||||||
m2.set(76.0f);
|
|
||||||
|
|
||||||
// Should be valid, but only get the value from m1
|
|
||||||
{
|
|
||||||
auto result = dut.get();
|
|
||||||
EXPECT_TRUE(result.Valid);
|
|
||||||
EXPECT_FLOAT_EQ(result.Value, 74.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SensorRedundantPartialSecond : public ::testing::Test
|
class SensorRedundantPartialSecond : public ::testing::Test
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
@ -273,7 +255,7 @@ TEST_F(SensorRedundantPartialSecond, CheckIsRedundant)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SensorRedundantPartialSecond, SetOnlyOneSensor)
|
TEST_F(SensorRedundantPartialSecond, SetNone)
|
||||||
{
|
{
|
||||||
// Don't set any sensors - expect invalid
|
// Don't set any sensors - expect invalid
|
||||||
{
|
{
|
||||||
|
@ -281,7 +263,10 @@ TEST_F(SensorRedundantPartialSecond, SetOnlyOneSensor)
|
||||||
EXPECT_FALSE(result.Valid);
|
EXPECT_FALSE(result.Valid);
|
||||||
EXPECT_EQ(result.Code, UnexpectedCode::Inconsistent);
|
EXPECT_EQ(result.Code, UnexpectedCode::Inconsistent);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SensorRedundantPartialSecond, SetOnlyOneSensor)
|
||||||
|
{
|
||||||
// Set first sensor
|
// Set first sensor
|
||||||
m1.set(24.0f);
|
m1.set(24.0f);
|
||||||
|
|
||||||
|
@ -294,23 +279,28 @@ TEST_F(SensorRedundantPartialSecond, SetOnlyOneSensor)
|
||||||
|
|
||||||
TEST_F(SensorRedundantPartialSecond, SetTwoSensors)
|
TEST_F(SensorRedundantPartialSecond, SetTwoSensors)
|
||||||
{
|
{
|
||||||
// Don't set any sensors - expect invalid
|
|
||||||
{
|
|
||||||
auto result = dut.get();
|
|
||||||
EXPECT_FALSE(result.Valid);
|
|
||||||
EXPECT_EQ(result.Code, UnexpectedCode::Inconsistent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set first sensor
|
// Set first sensor
|
||||||
m1.set(12.0f);
|
m1.set(0.0f);
|
||||||
// Set second sensor at double the first
|
// Set second sensor
|
||||||
m2.set(28.0f);
|
m2.set(0.0f);
|
||||||
|
|
||||||
// Should now be valid - and the average of the two input
|
// Should now be valid, and output the primary
|
||||||
{
|
{
|
||||||
auto result = dut.get();
|
auto result = dut.get();
|
||||||
EXPECT_TRUE(result.Valid);
|
EXPECT_TRUE(result.Valid);
|
||||||
EXPECT_FLOAT_EQ(result.Value, 13.0f);
|
EXPECT_FLOAT_EQ(result.Value, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SensorRedundantPartialSecond, CheckOnlySecondInvalid)
|
||||||
|
{
|
||||||
|
// Set second sensor only
|
||||||
|
m2.set(66.0f);
|
||||||
|
|
||||||
|
// Should be invalid - only one is set!
|
||||||
|
{
|
||||||
|
auto result = dut.get();
|
||||||
|
EXPECT_FALSE(result.Valid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +310,7 @@ TEST_F(SensorRedundantPartialSecond, DifferenceNone)
|
||||||
m1.set(10);
|
m1.set(10);
|
||||||
m2.set(20);
|
m2.set(20);
|
||||||
|
|
||||||
// Expect valid, and 10 output
|
// Expect valid, and output the primary
|
||||||
{
|
{
|
||||||
auto result = dut.get();
|
auto result = dut.get();
|
||||||
EXPECT_TRUE(result.Valid);
|
EXPECT_TRUE(result.Valid);
|
||||||
|
@ -334,11 +324,11 @@ TEST_F(SensorRedundantPartialSecond, DifferenceNearLimit)
|
||||||
m1.set(7.501f);
|
m1.set(7.501f);
|
||||||
m2.set(2 * 12.499f);
|
m2.set(2 * 12.499f);
|
||||||
|
|
||||||
// Expect valid, and 10 output
|
// Expect valid, and output the primary
|
||||||
{
|
{
|
||||||
auto result = dut.get();
|
auto result = dut.get();
|
||||||
EXPECT_TRUE(result.Valid);
|
EXPECT_TRUE(result.Valid);
|
||||||
EXPECT_FLOAT_EQ(result.Value, 10.0f);
|
EXPECT_FLOAT_EQ(result.Value, 7.501f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +364,7 @@ TEST_F(SensorRedundantPartialSecond, PartialRedundancyRange)
|
||||||
m1.set(75);
|
m1.set(75);
|
||||||
m2.set(100);
|
m2.set(100);
|
||||||
|
|
||||||
// expect valid, at 75%
|
// Expect valid, and output the first
|
||||||
{
|
{
|
||||||
auto result = dut.get();
|
auto result = dut.get();
|
||||||
EXPECT_TRUE(result.Valid);
|
EXPECT_TRUE(result.Valid);
|
||||||
|
|
Loading…
Reference in New Issue