more flexible GPPWM (#5032)

* gppwm improvements!

* test

* ui

* autoscale
This commit is contained in:
Matthew Kennedy 2023-02-06 04:53:31 -08:00 committed by GitHub
parent 4665e67eb4
commit 6e89e71d0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 65 additions and 44 deletions

View File

@ -321,6 +321,8 @@ uint16_t rpmAcceleration;dRPM;"RPM/s",1, 0, 0, 5, 2
int16_t[LUA_DIGITAL_INPUT_COUNT iterate] autoscale rawAnalogInput;;"V",{1/@@PACK_MULT_VOLTAGE@@}, 0, 0, 5, 3
uint8_t[4 iterate] autoscale gppwmOutput;GPPWM Output;"%", 0.5, 0, 0, 100, 2
int16_t[4 iterate] autoscale gppwmXAxis;;"", 1, 0, -30000, 30000, 0
int16_t[4 iterate] autoscale gppwmYAxis;;"", 0.1, 0, -1000, 1000, 1
int16_t autoscale rawBattery;;"V",{1/@@PACK_MULT_VOLTAGE@@}, 0, 0, 5, 3

View File

@ -58,8 +58,10 @@ void updateGppwm() {
static_assert(efi::size(channels) <= 8);
for (size_t i = 0; i < efi::size(channels); i++) {
float result = channels[i].update();
auto result = channels[i].update();
engine->outputChannels.gppwmOutput[i] = result;
engine->outputChannels.gppwmOutput[i] = result.Result;
engine->outputChannels.gppwmXAxis[i] = result.X;
engine->outputChannels.gppwmYAxis[i] = result.X;
}
}

View File

@ -10,6 +10,8 @@ expected<float> readGppwmChannel(gppwm_channel_e channel) {
switch (channel) {
case GPPWM_Zero:
return 0;
case GPPWM_Rpm:
return Sensor::get(SensorType::Rpm);
case GPPWM_Tps:
return Sensor::get(SensorType::Tps1);
case GPPWM_Map:
@ -109,31 +111,35 @@ void GppwmChannel::init(bool usePwm, IPwm* pwm, OutputPin* outputPin, const Valu
m_config = config;
}
percent_t GppwmChannel::getOutput() const {
expected<float> loadAxisValue = readGppwmChannel(m_config->loadAxis);
GppwmResult GppwmChannel::getOutput() const {
expected<float> xAxisValue = readGppwmChannel(m_config->rpmAxis);
expected<float> yAxisValue = readGppwmChannel(m_config->loadAxis);
GppwmResult result { (float)m_config->dutyIfError, xAxisValue.value_or(0), yAxisValue.value_or(0) };
// If we couldn't get load axis value, fall back on error value
if (!loadAxisValue) {
return m_config->dutyIfError;
if (!xAxisValue || !yAxisValue) {
return result;
}
float rpm = Sensor::getOrZero(SensorType::Rpm);
float resultVal = m_table->getValue(xAxisValue.Value, yAxisValue.Value);
float result = m_table->getValue(rpm, loadAxisValue.Value);
if (cisnan(result)) {
return m_config->dutyIfError;
if (cisnan(result.Result)) {
return result;
}
result.Result = resultVal;
return result;
}
float GppwmChannel::update() {
GppwmResult GppwmChannel::update() {
// Without a config, nothing to do.
if (!m_config) {
return 0;
return {};
}
float output = getOutput();
return setOutput(output);
auto output = getOutput();
output.Result = setOutput(output.Result);
return output;
}

View File

@ -9,11 +9,17 @@ class OutputPin;
struct IPwm;
class ValueProvider3D;
struct GppwmResult {
percent_t Result;
float X;
float Y;
};
class GppwmChannel {
public:
void init(bool usePwm, IPwm* pwm, OutputPin* outputPin, const ValueProvider3D* table, const gppwm_channel* config);
float update();
percent_t getOutput() const;
GppwmResult update();
GppwmResult getOutput() const;
// Returns actual output duty, with hysteresis applied
float setOutput(float result);

View File

@ -333,6 +333,10 @@ void setDefaultGppwmParameters() {
auto& cfg = engineConfiguration->gppwm[i];
chsnprintf(engineConfiguration->gpPwmNote[i], sizeof(engineConfiguration->gpPwmNote[0]), "GPPWM%d", i);
// Set default axes
cfg.loadAxis = GPPWM_Zero;
cfg.rpmAxis = GPPWM_Rpm;
cfg.pin = Gpio::Unassigned;
cfg.dutyIfError = 0;
cfg.onAboveDuty = 60;

View File

@ -563,6 +563,7 @@ typedef enum __attribute__ ((__packed__)) {
GPPWM_GppwmOutput4 = 21,
GPPWM_LuaGauge1 = 22,
GPPWM_LuaGauge2 = 23,
GPPWM_Rpm = 24,
} gppwm_channel_e;
typedef enum __attribute__ ((__packed__)) {

View File

@ -93,7 +93,7 @@
! Any time an incompatible change is made to the configuration format stored in flash,
! update this string to the current date! It is required to also update TS_SIGNATURE above
! when this happens.
#define FLASH_DATA_VERSION 10018
#define FLASH_DATA_VERSION 10019
! this offset is part of console compatibility mechanism, please DO NOT change this offset
#define TS_FILE_VERSION_OFFSET 124
@ -349,7 +349,7 @@ struct spi_pins
end_struct
#define gppwm_channel_e_enum "Zero", "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "Aux Temp 1", "Aux Temp 2", "Accel Pedal", "Battery Voltage", "VVT 1 I", "VVT 1 E", "VVT 2 I", "VVT 2 E", "Ethanol (Flex) %", "Aux Linear 1", "Aux Linear 2", "GPPWM Output 1", "GPPWM Output 2", "GPPWM Output 3", "GPPWM Output 4", "Lua Gauge 1", "Lua Gauge 2"
#define gppwm_channel_e_enum "Zero", "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "Aux Temp 1", "Aux Temp 2", "Accel Pedal", "Battery Voltage", "VVT 1 I", "VVT 1 E", "VVT 2 I", "VVT 2 E", "Ethanol (Flex) %", "Aux Linear 1", "Aux Linear 2", "GPPWM Output 1", "GPPWM Output 2", "GPPWM Output 3", "GPPWM Output 4", "Lua Gauge 1", "Lua Gauge 2", "RPM"
custom gppwm_channel_e 1 bits, U08, @OFFSET@, [0:4], @@gppwm_channel_e_enum@@
struct gppwm_channel
@ -360,12 +360,12 @@ struct gppwm_channel
uint8_t onAboveDuty;Hysteresis: in on-off mode, turn the output on when the table value is above this duty.;"%", 1, 0, 0, 100, 0
uint8_t offBelowDuty;Hysteresis: in on-off mode, turn the output off when the table value is below this duty.;"%", 1, 0, 0, 100, 0
gppwm_channel_e loadAxis;Selects the load axis to use for the table.;
uint8_t alignmentFill_map;;"unit", 1, 0, 0, 100, 0
gppwm_channel_e loadAxis;Selects the Y axis to use for the table.;
gppwm_channel_e rpmAxis;Selects the X axis to use for the table.;
uint8_t[GPPWM_LOAD_COUNT] loadBins;;"load", 1, 0, 0, 250, 0
uint8_t[GPPWM_RPM_COUNT] autoscale rpmBins;;"RPM", 100, 0, 0, 25000, 0
uint8_t[GPPWM_RPM_COUNT x GPPWM_LOAD_COUNT] table;;"duty", 1, 0, 0, 100, 0
int16_t[GPPWM_LOAD_COUNT] autoscale loadBins;;"load", 0.1, 0, -1000, 1000, 1
int16_t[GPPWM_RPM_COUNT] autoscale rpmBins;;"RPM", 1, 0, -30000, 30000, 0
uint8_t[GPPWM_RPM_COUNT x GPPWM_LOAD_COUNT] autoscale table;;"duty", 0.5, 0, 0, 100, 1
end_struct
custom air_pressure_sensor_type_e 1 bits, U08, @OFFSET@, [0:4], "Custom", "DENSO183", "MPX4250", "HONDA3BAR", "NEON_2003", "22012AA090", "GM 3 Bar", "MPX4100", "Toyota 89420-02010", "MPX4250A", "Bosch 2.5", "Mazda1Bar", "GM 2 Bar", "GM 1 Bar", "MPXH6400"

View File

@ -194,11 +194,6 @@ enable2ndByteCanID = false
egoCorrectionForVeAnalyze = { 100 + fuelPidCorrection1 }
; These "synthetic" channels provide the Y-axis (load) value for gen purp PWM table's Y axes
gppwm1_load = {(gppwm1_loadAxis == 0) ? 0 : (gppwm1_loadAxis == 1) ? TPSValue : (gppwm1_loadAxis == 2) ? MAPValue : (gppwm1_loadAxis == 3) ? coolant : (gppwm1_loadAxis == 4) ? intake : (gppwm1_loadAxis == 5) ? fuelingLoad : (gppwm1_loadAxis == 6) ? ignitionLoad : (gppwm1_loadAxis == 7) ? auxTemp1 : (gppwm1_loadAxis == 8) ? auxTemp2 : (gppwm1_loadAxis == 9) ? throttlePedalPosition : (gppwm1_loadAxis == 10) ? VBatt : (gppwm1_loadAxis == 11) ? vvtPositionB1I : (gppwm1_loadAxis == 12) ? vvtPositionB1E : (gppwm1_loadAxis == 13) ? vvtPositionB2I : (gppwm1_loadAxis == 14) ? vvtPositionB2E : (gppwm1_loadAxis == 15) ? flexPercent : (gppwm1_loadAxis == 16) ? auxLinear1 : (gppwm1_loadAxis == 17) ? auxLinear2 : 0}
gppwm2_load = {(gppwm2_loadAxis == 0) ? 0 : (gppwm2_loadAxis == 1) ? TPSValue : (gppwm2_loadAxis == 2) ? MAPValue : (gppwm2_loadAxis == 3) ? coolant : (gppwm2_loadAxis == 4) ? intake : (gppwm2_loadAxis == 5) ? fuelingLoad : (gppwm2_loadAxis == 6) ? ignitionLoad : (gppwm2_loadAxis == 7) ? auxTemp1 : (gppwm2_loadAxis == 8) ? auxTemp2 : (gppwm2_loadAxis == 9) ? throttlePedalPosition : (gppwm2_loadAxis == 10) ? VBatt : (gppwm2_loadAxis == 11) ? vvtPositionB1I : (gppwm2_loadAxis == 12) ? vvtPositionB1E : (gppwm2_loadAxis == 13) ? vvtPositionB2I : (gppwm2_loadAxis == 14) ? vvtPositionB2E : (gppwm2_loadAxis == 15) ? flexPercent : (gppwm2_loadAxis == 16) ? auxLinear1 : (gppwm2_loadAxis == 17) ? auxLinear2 : 0}
gppwm3_load = {(gppwm3_loadAxis == 0) ? 0 : (gppwm3_loadAxis == 1) ? TPSValue : (gppwm3_loadAxis == 2) ? MAPValue : (gppwm3_loadAxis == 3) ? coolant : (gppwm3_loadAxis == 4) ? intake : (gppwm3_loadAxis == 5) ? fuelingLoad : (gppwm3_loadAxis == 6) ? ignitionLoad : (gppwm3_loadAxis == 7) ? auxTemp1 : (gppwm3_loadAxis == 8) ? auxTemp2 : (gppwm3_loadAxis == 9) ? throttlePedalPosition : (gppwm3_loadAxis == 10) ? VBatt : (gppwm3_loadAxis == 11) ? vvtPositionB1I : (gppwm3_loadAxis == 12) ? vvtPositionB1E : (gppwm3_loadAxis == 13) ? vvtPositionB2I : (gppwm3_loadAxis == 14) ? vvtPositionB2E : (gppwm3_loadAxis == 15) ? flexPercent : (gppwm3_loadAxis == 16) ? auxLinear1 : (gppwm3_loadAxis == 17) ? auxLinear2 : 0}
gppwm4_load = {(gppwm4_loadAxis == 0) ? 0 : (gppwm4_loadAxis == 1) ? TPSValue : (gppwm4_loadAxis == 2) ? MAPValue : (gppwm4_loadAxis == 3) ? coolant : (gppwm4_loadAxis == 4) ? intake : (gppwm4_loadAxis == 5) ? fuelingLoad : (gppwm4_loadAxis == 6) ? ignitionLoad : (gppwm4_loadAxis == 7) ? auxTemp1 : (gppwm4_loadAxis == 8) ? auxTemp2 : (gppwm4_loadAxis == 9) ? throttlePedalPosition : (gppwm4_loadAxis == 10) ? VBatt : (gppwm4_loadAxis == 11) ? vvtPositionB1I : (gppwm4_loadAxis == 12) ? vvtPositionB1E : (gppwm4_loadAxis == 13) ? vvtPositionB2I : (gppwm4_loadAxis == 14) ? vvtPositionB2E : (gppwm4_loadAxis == 15) ? flexPercent : (gppwm4_loadAxis == 16) ? auxLinear1 : (gppwm4_loadAxis == 17) ? auxLinear2 : 0}
ignBlends1_blendVal = {(ignBlends1_blendParameter == 0) ? 0 : (ignBlends1_blendParameter == 1) ? TPSValue : (ignBlends1_blendParameter == 2) ? MAPValue : (ignBlends1_blendParameter == 3) ? coolant : (ignBlends1_blendParameter == 4) ? intake : (ignBlends1_blendParameter == 5) ? fuelingLoad : (ignBlends1_blendParameter == 6) ? ignitionLoad : (ignBlends1_blendParameter == 7) ? auxTemp1 : (ignBlends1_blendParameter == 8) ? auxTemp2 : (ignBlends1_blendParameter == 9) ? throttlePedalPosition : (ignBlends1_blendParameter == 10) ? VBatt : (ignBlends1_blendParameter == 11) ? vvtPositionB1I : (ignBlends1_blendParameter == 12) ? vvtPositionB1E : (ignBlends1_blendParameter == 13) ? vvtPositionB2I : (ignBlends1_blendParameter == 14) ? vvtPositionB2E : (ignBlends1_blendParameter == 15) ? flexPercent : (ignBlends1_blendParameter == 16) ? auxLinear1 : (ignBlends1_blendParameter == 17) ? auxLinear2 : 0}
ignBlends2_blendVal = {(ignBlends2_blendParameter == 0) ? 0 : (ignBlends2_blendParameter == 1) ? TPSValue : (ignBlends2_blendParameter == 2) ? MAPValue : (ignBlends2_blendParameter == 3) ? coolant : (ignBlends2_blendParameter == 4) ? intake : (ignBlends2_blendParameter == 5) ? fuelingLoad : (ignBlends2_blendParameter == 6) ? ignitionLoad : (ignBlends2_blendParameter == 7) ? auxTemp1 : (ignBlends2_blendParameter == 8) ? auxTemp2 : (ignBlends2_blendParameter == 9) ? throttlePedalPosition : (ignBlends2_blendParameter == 10) ? VBatt : (ignBlends2_blendParameter == 11) ? vvtPositionB1I : (ignBlends2_blendParameter == 12) ? vvtPositionB1E : (ignBlends2_blendParameter == 13) ? vvtPositionB2I : (ignBlends2_blendParameter == 14) ? vvtPositionB2E : (ignBlends2_blendParameter == 15) ? flexPercent : (ignBlends2_blendParameter == 16) ? auxLinear1 : (ignBlends2_blendParameter == 17) ? auxLinear2 : 0}
ignBlends3_blendVal = {(ignBlends3_blendParameter == 0) ? 0 : (ignBlends3_blendParameter == 1) ? TPSValue : (ignBlends3_blendParameter == 2) ? MAPValue : (ignBlends3_blendParameter == 3) ? coolant : (ignBlends3_blendParameter == 4) ? intake : (ignBlends3_blendParameter == 5) ? fuelingLoad : (ignBlends3_blendParameter == 6) ? ignitionLoad : (ignBlends3_blendParameter == 7) ? auxTemp1 : (ignBlends3_blendParameter == 8) ? auxTemp2 : (ignBlends3_blendParameter == 9) ? throttlePedalPosition : (ignBlends3_blendParameter == 10) ? VBatt : (ignBlends3_blendParameter == 11) ? vvtPositionB1I : (ignBlends3_blendParameter == 12) ? vvtPositionB1E : (ignBlends3_blendParameter == 13) ? vvtPositionB2I : (ignBlends3_blendParameter == 14) ? vvtPositionB2E : (ignBlends3_blendParameter == 15) ? flexPercent : (ignBlends3_blendParameter == 16) ? auxLinear1 : (ignBlends3_blendParameter == 17) ? auxLinear2 : 0}
@ -1144,26 +1139,26 @@ curve = 32Curve, "3-2 Shift Solenoid Percent by Speed"
table = gppwm1Tbl, gppwm1Map, "GP#1", 1
xyLabels = "RPM", ""
xBins = gppwm1_rpmBins, RPMValue
yBins = gppwm1_loadBins, gppwm1_load
xBins = gppwm1_rpmBins, gppwmXAxis1
yBins = gppwm1_loadBins, gppwmYAxis1
zBins = gppwm1_table
table = gppwm2Tbl, gppwm2Map, "GP#2", 1
xyLabels = "RPM", ""
xBins = gppwm2_rpmBins, RPMValue
yBins = gppwm2_loadBins, gppwm2_load
xBins = gppwm2_rpmBins, gppwmXAxis2
yBins = gppwm2_loadBins, gppwmYAxis2
zBins = gppwm2_table
table = gppwm3Tbl, gppwm3Map, "GP#3", 1
xyLabels = "RPM", ""
xBins = gppwm3_rpmBins, RPMValue
yBins = gppwm3_loadBins, gppwm3_load
xBins = gppwm3_rpmBins, gppwmXAxis3
yBins = gppwm3_loadBins, gppwmYAxis3
zBins = gppwm3_table
table = gppwm4Tbl, gppwm4Map, "GP#4", 1
xyLabels = "RPM", ""
xBins = gppwm4_rpmBins, RPMValue
yBins = gppwm4_loadBins, gppwm4_load
xBins = gppwm4_rpmBins, gppwmXAxis4
yBins = gppwm4_loadBins, gppwmYAxis4
zBins = gppwm4_table
table = tcuSolenoidTableTbl, tcuSolenoidTableMap, "Solenoids Active By Gear", 1
@ -4349,7 +4344,8 @@ dialog = tcuControls, "Transmission Settings"
field = "Off below duty", gppwm1_offBelowDuty, {gppwm1_pin != 0 && gppwm1_pwmFrequency == 0}
field = "Duty if error", gppwm1_dutyIfError, {gppwm1_pin != 0}
field = ""
field = "Load Axis", gppwm1_loadAxis, {gppwm1_pin != 0}
field = "X Axis", gppwm1_rpmAxis, {gppwm1_pin != 0}
field = "Y Axis", gppwm1_loadAxis, {gppwm1_pin != 0}
field = "Note", gpPwmNote1
field = ""
field = ""
@ -4371,7 +4367,8 @@ dialog = tcuControls, "Transmission Settings"
field = "Off below duty", gppwm2_offBelowDuty, {gppwm2_pin != 0 && gppwm2_pwmFrequency == 0}
field = "Duty if error", gppwm2_dutyIfError, {gppwm2_pin != 0}
field = ""
field = "Load Axis", gppwm2_loadAxis, {gppwm2_pin != 0}
field = "X Axis", gppwm2_rpmAxis, {gppwm2_pin != 0}
field = "Y Axis", gppwm2_loadAxis, {gppwm2_pin != 0}
field = "Note", gpPwmNote2
field = ""
field = ""
@ -4393,7 +4390,8 @@ dialog = tcuControls, "Transmission Settings"
field = "Off below duty", gppwm3_offBelowDuty, {gppwm3_pin != 0 && gppwm3_pwmFrequency == 0}
field = "Duty if error", gppwm3_dutyIfError, {gppwm3_pin != 0}
field = ""
field = "Load Axis", gppwm3_loadAxis, {gppwm3_pin != 0}
field = "X Axis", gppwm3_rpmAxis, {gppwm3_pin != 0}
field = "Y Axis", gppwm3_loadAxis, {gppwm3_pin != 0}
field = "Note", gpPwmNote3
field = ""
field = ""
@ -4415,7 +4413,8 @@ dialog = tcuControls, "Transmission Settings"
field = "Off below duty", gppwm4_offBelowDuty, {gppwm4_pin != 0 && gppwm4_pwmFrequency == 0}
field = "Duty if error", gppwm4_dutyIfError, {gppwm4_pin != 0}
field = ""
field = "Load Axis", gppwm4_loadAxis, {gppwm4_pin != 0}
field = "X Axis", gppwm4_rpmAxis, {gppwm4_pin != 0}
field = "Y Axis", gppwm4_loadAxis, {gppwm4_pin != 0}
field = "Note", gpPwmNote4
field = ""
field = ""

View File

@ -124,7 +124,7 @@ typedef Map3D<BARO_CORR_SIZE, BARO_CORR_SIZE, float, float, float> baroCorr_Map3
typedef Map3D<PEDAL_TO_TPS_SIZE, PEDAL_TO_TPS_SIZE, uint8_t, uint8_t, uint8_t> pedal2tps_t;
typedef Map3D<BOOST_RPM_COUNT, BOOST_LOAD_COUNT, uint8_t, uint8_t, uint8_t> boostOpenLoop_Map3D_t;
typedef Map3D<BOOST_RPM_COUNT, BOOST_LOAD_COUNT, uint8_t, uint8_t, uint8_t> boostClosedLoop_Map3D_t;
typedef Map3D<GPPWM_RPM_COUNT, GPPWM_LOAD_COUNT, uint8_t, uint8_t, uint8_t> gppwm_Map3D_t;
typedef Map3D<GPPWM_RPM_COUNT, GPPWM_LOAD_COUNT, uint8_t, int16_t, int16_t> gppwm_Map3D_t;
typedef Map3D<FUEL_RPM_COUNT, FUEL_LOAD_COUNT, uint16_t, uint16_t, uint16_t> mapEstimate_Map3D_t;
/**

View File

@ -79,6 +79,7 @@ TEST(GpPwm, TestGetOutput) {
gppwm_channel cfg;
cfg.loadAxis = GPPWM_Tps;
cfg.rpmAxis = GPPWM_Rpm;
cfg.dutyIfError = 21.0f;
MockVp3d table;
@ -93,10 +94,10 @@ TEST(GpPwm, TestGetOutput) {
Sensor::resetAllMocks();
// Should return dutyIfError
EXPECT_FLOAT_EQ(21.0f, ch.getOutput());
EXPECT_FLOAT_EQ(21.0f, ch.getOutput().Result);
// Set TPS, should return tps value
Sensor::setMockValue(SensorType::Tps1, 35.0f);
Sensor::setMockValue(SensorType::Rpm, 1200);
EXPECT_FLOAT_EQ(35.0f, ch.getOutput());
EXPECT_FLOAT_EQ(35.0f, ch.getOutput().Result);
}