Ford redundant ETB tps (#2519)
* ford tps * configurable maximum * initialization * check consistency when in the low range * print info * default * config field * config parameter * test Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
parent
db85ce95e9
commit
7782ebd7b4
|
@ -0,0 +1,53 @@
|
|||
#include "redundant_ford_tps.h"
|
||||
|
||||
#include "efilib.h"
|
||||
|
||||
RedundantFordTps::RedundantFordTps(SensorType outputType, SensorType first, SensorType second)
|
||||
: Sensor(outputType)
|
||||
, m_first(first)
|
||||
, m_second(second)
|
||||
{
|
||||
}
|
||||
|
||||
void RedundantFordTps::configure(float maxDifference, float secondaryMaximum) {
|
||||
m_maxDifference = maxDifference;
|
||||
m_secondaryMaximum = secondaryMaximum;
|
||||
}
|
||||
|
||||
SensorResult RedundantFordTps::get() const {
|
||||
// Sensor 1 is "plain linear" and has the full range
|
||||
auto tps1 = Sensor::get(m_first);
|
||||
|
||||
// Sensor 2 is compressed in to 0 -> 50%
|
||||
auto tps2 = Sensor::get(m_second);
|
||||
|
||||
// If either result is invalid, return invalid.
|
||||
if (!tps1 || !tps2) {
|
||||
return unexpected;
|
||||
}
|
||||
|
||||
// The "actual" position resolved by the second throttle - this tops out at m_secondaryMaximum instead of 100%
|
||||
float tps2Actual = tps2.Value * m_secondaryMaximum / 100;
|
||||
|
||||
// Switch modes slightly below the maximum of the secondary, to avoid misbehavior near 100%
|
||||
float avgThreshold = m_secondaryMaximum * 0.9f;
|
||||
|
||||
// Case 1: both sensors show low position, average result
|
||||
if (tps1.Value < avgThreshold && tps2Actual < avgThreshold) {
|
||||
// Check that the resolved positions are close
|
||||
float delta = absF(tps1.Value - tps2Actual);
|
||||
if (delta > m_maxDifference) {
|
||||
return unexpected;
|
||||
}
|
||||
|
||||
return (tps1.Value + tps2Actual) / 2;
|
||||
}
|
||||
|
||||
// Case 2: both sensors show high position, return "full scale" sensor's position
|
||||
if (tps1.Value > avgThreshold && tps2Actual > (avgThreshold - 3)) {
|
||||
return tps1;
|
||||
}
|
||||
|
||||
// Any other condition indicates an mismatch, and therefore an error
|
||||
return unexpected;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include "sensor.h"
|
||||
|
||||
class RedundantFordTps final : public Sensor
|
||||
{
|
||||
public:
|
||||
RedundantFordTps(
|
||||
SensorType outputType,
|
||||
SensorType firstSensor,
|
||||
SensorType secondSensor
|
||||
);
|
||||
|
||||
void configure(float maxDifference, float secondaryMaximum);
|
||||
|
||||
SensorResult get() const override;
|
||||
|
||||
bool isRedundant() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
void showInfo(Logging* logger, const char* sensorName) const override;
|
||||
|
||||
private:
|
||||
// The two sensors we interpret to form one redundant sensor
|
||||
const SensorType m_first;
|
||||
const SensorType m_second;
|
||||
|
||||
// How far apart do we allow the sensors to be before reporting an issue?
|
||||
float m_maxDifference = 0;
|
||||
|
||||
// At what primary % does the secondary hit 100%?
|
||||
float m_secondaryMaximum = 0;
|
||||
};
|
|
@ -2,6 +2,7 @@
|
|||
#include "proxy_sensor.h"
|
||||
#include "functional_sensor.h"
|
||||
#include "redundant_sensor.h"
|
||||
#include "redundant_ford_tps.h"
|
||||
#include "rpm_calculator.h"
|
||||
#include "Lps25Sensor.h"
|
||||
#include "linear_func.h"
|
||||
|
@ -37,6 +38,10 @@ void RedundantSensor::showInfo(Logging* logger, const char* sensorName) const {
|
|||
scheduleMsg(logger, "Sensor \"%s\" is redundant combining \"%s\" and \"%s\"", sensorName, getSensorName(m_first), getSensorName(m_second));
|
||||
}
|
||||
|
||||
void RedundantFordTps::showInfo(Logging* logger, const char* sensorName) const {
|
||||
scheduleMsg(logger, "Sensor \"%s\" is Ford-type redundant TPS combining \"%s\" and \"%s\"", sensorName, getSensorName(m_first), getSensorName(m_second));
|
||||
}
|
||||
|
||||
void RpmCalculator::showInfo(Logging* logger, const char* /*sensorName*/) const {
|
||||
scheduleMsg(logger, "RPM sensor: stopped: %d spinning up: %d cranking: %d running: %d rpm: %f",
|
||||
isStopped(),
|
||||
|
|
|
@ -11,6 +11,7 @@ CONTROLLERS_SENSORS_SRC_CPP = $(PROJECT_DIR)/controllers/sensors/thermistors.cp
|
|||
$(PROJECT_DIR)/controllers/sensors/sensor_info_printing.cpp \
|
||||
$(PROJECT_DIR)/controllers/sensors/functional_sensor.cpp \
|
||||
$(PROJECT_DIR)/controllers/sensors/redundant_sensor.cpp \
|
||||
$(PROJECT_DIR)/controllers/sensors/redundant_ford_tps.cpp \
|
||||
$(PROJECT_DIR)/controllers/sensors/AemXSeriesLambda.cpp \
|
||||
$(PROJECT_DIR)/cotnrollers/sensors/flex_sensor.cpp \
|
||||
$(PROJECT_DIR)/controllers/sensors/software_knock.cpp \
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "error_handling.h"
|
||||
#include "functional_sensor.h"
|
||||
#include "redundant_sensor.h"
|
||||
#include "redundant_ford_tps.h"
|
||||
#include "proxy_sensor.h"
|
||||
#include "linear_func.h"
|
||||
#include "tps.h"
|
||||
|
@ -21,9 +22,14 @@ FunctionalSensor tpsSens1s(SensorType::Tps1Secondary, MS2NT(10));
|
|||
FunctionalSensor tpsSens2p(SensorType::Tps2Primary, MS2NT(10));
|
||||
FunctionalSensor tpsSens2s(SensorType::Tps2Secondary, MS2NT(10));
|
||||
|
||||
// Used in case of "normal", non-Ford ETB TPS
|
||||
RedundantSensor tps1(SensorType::Tps1, SensorType::Tps1Primary, SensorType::Tps1Secondary);
|
||||
RedundantSensor tps2(SensorType::Tps2, SensorType::Tps2Primary, SensorType::Tps2Secondary);
|
||||
|
||||
// Used only in case of weird Ford-style ETB TPS
|
||||
RedundantFordTps fordTps1(SensorType::Tps1, SensorType::Tps1Primary, SensorType::Tps1Secondary);
|
||||
RedundantFordTps fordTps2(SensorType::Tps2, SensorType::Tps2Primary, SensorType::Tps2Secondary);
|
||||
|
||||
LinearFunc pedalFuncPrimary;
|
||||
LinearFunc pedalFuncSecondary;
|
||||
FunctionalSensor pedalSensorPrimary(SensorType::AcceleratorPedalPrimary, MS2NT(10));
|
||||
|
@ -81,12 +87,16 @@ static bool initTpsFunc(LinearFunc& func, FunctionalSensor& sensor, adc_channel_
|
|||
return sensor.Register();
|
||||
}
|
||||
|
||||
static void initTpsFuncAndRedund(RedundantSensor& redund, LinearFunc& func, FunctionalSensor& sensor, adc_channel_e channel, float closed, float open, float min, float max) {
|
||||
static void initTpsFuncAndRedund(RedundantSensor& redund, RedundantFordTps* fordTps, bool isFordTps, LinearFunc& func, FunctionalSensor& sensor, adc_channel_e channel, float closed, float open, float min, float max) {
|
||||
bool hasSecond = initTpsFunc(func, sensor, channel, closed, open, min, max);
|
||||
|
||||
redund.configure(5.0f, !hasSecond);
|
||||
|
||||
redund.Register();
|
||||
if (isFordTps && fordTps) {
|
||||
fordTps->configure(5.0f, 52.6f);
|
||||
fordTps->Register();
|
||||
} else {
|
||||
redund.configure(5.0f, !hasSecond);
|
||||
redund.Register();
|
||||
}
|
||||
}
|
||||
|
||||
void initTps(DECLARE_CONFIG_PARAMETER_SIGNATURE) {
|
||||
|
@ -94,12 +104,18 @@ void initTps(DECLARE_CONFIG_PARAMETER_SIGNATURE) {
|
|||
percent_t max = CONFIG(tpsErrorDetectionTooHigh);
|
||||
|
||||
if (!CONFIG(consumeObdSensors)) {
|
||||
// primary TPS sensors
|
||||
initTpsFunc(tpsFunc1p, tpsSens1p, CONFIG(tps1_1AdcChannel), CONFIG(tpsMin), CONFIG(tpsMax), min, max);
|
||||
initTpsFuncAndRedund(tps1, tpsFunc1s, tpsSens1s, CONFIG(tps1_2AdcChannel), CONFIG(tps1SecondaryMin), CONFIG(tps1SecondaryMax), min, max);
|
||||
initTpsFunc(tpsFunc2p, tpsSens2p, CONFIG(tps2_1AdcChannel), CONFIG(tps2Min), CONFIG(tps2Max), min, max);
|
||||
initTpsFuncAndRedund(tps2, tpsFunc2s, tpsSens2s, CONFIG(tps2_2AdcChannel), CONFIG(tps2SecondaryMin), CONFIG(tps2SecondaryMax), min, max);
|
||||
|
||||
// Secondary TPS sensors (and redundant combining)
|
||||
bool isFordTps = CONFIG(useFordRedundantTps);
|
||||
initTpsFuncAndRedund(tps1, &fordTps1, isFordTps, tpsFunc1s, tpsSens1s, CONFIG(tps1_2AdcChannel), CONFIG(tps1SecondaryMin), CONFIG(tps1SecondaryMax), min, max);
|
||||
initTpsFuncAndRedund(tps2, &fordTps2, isFordTps, tpsFunc2s, tpsSens2s, CONFIG(tps2_2AdcChannel), CONFIG(tps2SecondaryMin), CONFIG(tps2SecondaryMax), min, max);
|
||||
|
||||
// Pedal sensors
|
||||
initTpsFunc(pedalFuncPrimary, pedalSensorPrimary, CONFIG(throttlePedalPositionAdcChannel), CONFIG(throttlePedalUpVoltage), CONFIG(throttlePedalWOTVoltage), min, max);
|
||||
initTpsFuncAndRedund(pedal, pedalFuncSecondary, pedalSensorSecondary, CONFIG(throttlePedalPositionSecondAdcChannel), CONFIG(throttlePedalSecondaryUpVoltage), CONFIG(throttlePedalSecondaryWOTVoltage), min, max);
|
||||
initTpsFuncAndRedund(pedal, nullptr, false, pedalFuncSecondary, pedalSensorSecondary, CONFIG(throttlePedalPositionSecondAdcChannel), CONFIG(throttlePedalSecondaryUpVoltage), CONFIG(throttlePedalSecondaryWOTVoltage), min, max);
|
||||
|
||||
// TPS-like stuff that isn't actually a TPS
|
||||
initTpsFunc(wastegateFunc, wastegateSens, CONFIG(wastegatePositionSensor), CONFIG(wastegatePositionMin), CONFIG(wastegatePositionMax), min, max);
|
||||
|
|
|
@ -506,7 +506,7 @@ end_struct
|
|||
injector_s injector
|
||||
|
||||
bit isForcedInduction;
|
||||
bit unused_294_1;
|
||||
bit useFordRedundantTps;
|
||||
bit isVerboseAuxPid1;
|
||||
bit unused_294_3;
|
||||
bit unused_294_4;
|
||||
|
|
|
@ -3491,6 +3491,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00"
|
|||
field = "Ignition Math Logic @", ignMathCalculateAtIndex
|
||||
field = "MAP Averaging Logic @", mapAveragingSchedulingAtIndex
|
||||
field = "showHumanReadableWarning (affects Burn)", showHumanReadableWarning
|
||||
field = "Ford redundant TPS mode", useFordRedundantTps
|
||||
|
||||
|
||||
help = helpGeneral, "rusEFI General Help"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "redundant_sensor.h"
|
||||
#include "redundant_ford_tps.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
@ -220,3 +221,143 @@ TEST_F(SensorRedundantIgnoreSecond, SetBothIgnoreSecond)
|
|||
EXPECT_FLOAT_EQ(result.Value, 74.0f);
|
||||
}
|
||||
}
|
||||
|
||||
class SensorFordRedundantTps : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
RedundantFordTps dut;
|
||||
MockSensor m1, m2;
|
||||
|
||||
SensorFordRedundantTps()
|
||||
: dut(SensorType::Tps1, SensorType::Tps1Primary, SensorType::Tps1Secondary)
|
||||
, m1(SensorType::Tps1Primary)
|
||||
, m2(SensorType::Tps1Secondary)
|
||||
{
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
Sensor::resetRegistry();
|
||||
|
||||
// Other tests verify registry function - don't re-test it here
|
||||
ASSERT_TRUE(dut.Register());
|
||||
ASSERT_TRUE(m1.Register());
|
||||
ASSERT_TRUE(m2.Register());
|
||||
|
||||
dut.configure(5.0f, 50);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
Sensor::resetRegistry();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(SensorFordRedundantTps, SetOnlyOneSensor)
|
||||
{
|
||||
// Don't set any sensors - expect invalid
|
||||
{
|
||||
auto result = dut.get();
|
||||
EXPECT_FALSE(result.Valid);
|
||||
}
|
||||
|
||||
// Set one sensor
|
||||
m1.set(24.0f);
|
||||
|
||||
// Should still be invalid - only one is set!
|
||||
{
|
||||
auto result = dut.get();
|
||||
EXPECT_FALSE(result.Valid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SensorFordRedundantTps, SetTwoSensors)
|
||||
{
|
||||
// Don't set any sensors - expect invalid
|
||||
{
|
||||
auto result = dut.get();
|
||||
EXPECT_FALSE(result.Valid);
|
||||
}
|
||||
|
||||
// Set one sensor
|
||||
m1.set(12.0f);
|
||||
// Set the other sensor at double the first
|
||||
m2.set(28.0f);
|
||||
|
||||
// Should now be valid - and the average of the two input
|
||||
{
|
||||
auto result = dut.get();
|
||||
EXPECT_TRUE(result.Valid);
|
||||
EXPECT_FLOAT_EQ(result.Value, 13.0f);
|
||||
|
||||
EXPECT_TRUE(dut.isRedundant());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SensorFordRedundantTps, DifferenceNone)
|
||||
{
|
||||
// Set both sensors to the same value
|
||||
m1.set(10);
|
||||
m2.set(20);
|
||||
|
||||
// Expect valid, and 10 output
|
||||
{
|
||||
auto result = dut.get();
|
||||
EXPECT_TRUE(result.Valid);
|
||||
EXPECT_FLOAT_EQ(result.Value, 10.0f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SensorFordRedundantTps, DifferenceNearLimit)
|
||||
{
|
||||
// Set both sensors to nearly the limit (4.998 apart)
|
||||
m1.set(7.501f);
|
||||
m2.set(2 * 12.499f);
|
||||
|
||||
// Expect valid, and 10 output
|
||||
{
|
||||
auto result = dut.get();
|
||||
EXPECT_TRUE(result.Valid);
|
||||
EXPECT_FLOAT_EQ(result.Value, 10.0f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SensorFordRedundantTps, DifferenceOverLimit)
|
||||
{
|
||||
// Set both sensors barely over the limit (5.002 apart)
|
||||
m1.set(7.499f);
|
||||
m2.set(2 * 12.501f);
|
||||
|
||||
// Expect invalid
|
||||
{
|
||||
auto result = dut.get();
|
||||
EXPECT_FALSE(result.Valid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SensorFordRedundantTps, DifferenceOverLimitSwapped)
|
||||
{
|
||||
// Now try it the other way (m1 > m2)
|
||||
m1.set(12.501f);
|
||||
m2.set(2 * 7.499f);
|
||||
|
||||
// Expect invalid
|
||||
{
|
||||
auto result = dut.get();
|
||||
EXPECT_FALSE(result.Valid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SensorFordRedundantTps, HighRange)
|
||||
{
|
||||
// Set the throttle like it's at 75%
|
||||
m1.set(75);
|
||||
m2.set(100);
|
||||
|
||||
// expect valid, at 75%
|
||||
{
|
||||
auto result = dut.get();
|
||||
EXPECT_TRUE(result.Valid);
|
||||
EXPECT_FLOAT_EQ(result.Value, 75.0f);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue