throttle model tests

(cherry picked from commit d14d442157)
This commit is contained in:
Matthew Kennedy 2023-03-13 15:43:39 -07:00 committed by rusefi
parent 8b25c9e0f3
commit 1a1372ffe9
3 changed files with 100 additions and 17 deletions

View File

@ -9,6 +9,10 @@ static float pressureRatioFlowCorrection(float pr) {
return 1.0;
}
if (pr > 0.95) {
return 0.449f;
}
// float x = pr;
// float x2 = x * x;
// float x3 = x2 * x;
@ -66,11 +70,14 @@ private:
};
// Find the throttle position that gives the specified flow
float ThrottleModelBase::inversePartThrottleFlow(float maxEngineFlow, float flow, float pressureRatio, float p_up, float iat) const {
// TODO: handle near-WOT flow gracefully
float ThrottleModelBase::throttlePositionForFlow(float flow, float pressureRatio, float p_up, float iat) const {
// What does the bare throttle flow at wide open?
float wideOpenFlow = partThrottleFlow(100, pressureRatio, p_up, iat);
// If over 95% of the wide open flow, return wide open
if (flow > 0.95f * maxEngineFlow) {
// If the target flow is more than the throttle can flow, return 100% since the throttle
// can't open any further
// If we don't do this, trying to solve using the solver may diverge
if (flow > wideOpenFlow) {
return 100;
}
@ -79,19 +86,20 @@ float ThrottleModelBase::inversePartThrottleFlow(float maxEngineFlow, float flow
}
float ThrottleModelBase::estimateThrottleFlow(float tip, float tps, float map, float iat) {
// What output flow do we get at 0.95 PR?
// How much flow would the engine pull at 0.95 PR?
// The throttle won't flow much more than this in any scenario, even if the throttle could move more flow.
constexpr float crossoverPr = 0.95f;
float p95Flow = maxEngineFlow(tip * crossoverPr);
// Maximum flow if the throttle was removed
float maximumPossibleFlow = maxEngineFlow(tip);
// What throttle position gives us that flow at 0.95 PR?
float throttleAngle95Pr = inversePartThrottleFlow(maximumPossibleFlow, p95Flow, crossoverPr, tip, iat);
float throttleAngle95Pr = throttlePositionForFlow(p95Flow, crossoverPr, tip, iat);
if (tps > throttleAngle95Pr) {
// "WOT" model
// Maximum flow if the throttle was removed
float maximumPossibleFlow = maxEngineFlow(tip);
// Linearly interpolate between the P95 point and wide open, where the engine flows its max
return interpolateClamped(throttleAngle95Pr, p95Flow, 100, maximumPossibleFlow, tps);
} else {

View File

@ -8,6 +8,8 @@ public:
float partThrottleFlow(float tps, float flowCorrection) const;
float partThrottleFlow(float tps, float pressureRatio, float p_up, float iat) const;
float throttlePositionForFlow(float flow, float pressureRatio, float p_up, float iat) const;
protected:
// Given some TPS, what is the normalized choked flow in kg/s?
virtual float effectiveArea(float tps) const = 0;
@ -15,8 +17,6 @@ protected:
// Given some MAP, what is the most the engine can pull through a wide open throttle, in kg/s?
virtual float maxEngineFlow(float map) const = 0;
private:
float inversePartThrottleFlow(float maxEngineFlow, float flow, float pressureRatio, float p_up, float iat) const;
};
struct ThrottleModel : public ThrottleModelBase {

View File

@ -33,11 +33,86 @@ TEST(ThrottleModel, PartThrottle) {
EXPECT_NEAR(1.5 * 0.04441, model.estimateThrottleFlow(150, 20, 45, 0), 1e-4);
}
// TEST(ThrottleModel, WideOpen) {
// MockThrottleModel model;
TEST(ThrottleModel, InverseFlowLowPressureRatio) {
MockThrottleModel model;
// // Engine can only flow 0.5kg/s at 100kPa
// EXPECT_CALL(model, maxEngineFlow(::testing::_)).WillRepeatedly([](float map) { return map / 100 * 0.5f; });
EXPECT_NEAR( 2.329, model.throttlePositionForFlow(0.0003, 0.3, 100, 0), 1e-2);
EXPECT_NEAR( 3.446, model.throttlePositionForFlow(0.001, 0.3, 100, 0), 1e-2);
EXPECT_NEAR( 9.674, model.throttlePositionForFlow(0.010, 0.3, 100, 0), 1e-2);
EXPECT_NEAR(29.711, model.throttlePositionForFlow(0.100, 0.3, 100, 0), 1e-2);
EXPECT_NEAR(41.395, model.throttlePositionForFlow(0.200, 0.3, 100, 0), 1e-2);
EXPECT_NEAR(57.415, model.throttlePositionForFlow(0.400, 0.3, 100, 0), 1e-2);
EXPECT_NEAR(71.255, model.throttlePositionForFlow(0.600, 0.3, 100, 0), 1e-2);
EXPECT_NEAR(77.965, model.throttlePositionForFlow(0.700, 0.3, 100, 0), 1e-2);
EXPECT_NEAR(83.323, model.throttlePositionForFlow(0.750, 0.3, 100, 0), 1e-2);
EXPECT_NEAR(85.070, model.throttlePositionForFlow(0.760, 0.3, 100, 0), 1e-2);
// EXPECT_NEAR(0.5f, model.estimateThrottleFlow(95, 90, 98, 0), 1e-4);
// }
// Throttle is maxed out here!
EXPECT_NEAR(100.00, model.throttlePositionForFlow(0.770, 0.3, 100, 0), 1e-2);
EXPECT_NEAR(100.00, model.throttlePositionForFlow(0.800, 0.3, 100, 0), 1e-2);
EXPECT_NEAR(100.00, model.throttlePositionForFlow(0.900, 0.3, 100, 0), 1e-2);
}
TEST(ThrottleModel, InverseFlowHighPressureRatio) {
MockThrottleModel model;
EXPECT_NEAR( 2.626, model.throttlePositionForFlow(0.0003, 0.9, 100, 0), 1e-2);
EXPECT_NEAR( 4.437, model.throttlePositionForFlow(0.001, 0.9, 100, 0), 1e-2);
EXPECT_NEAR( 5.738, model.throttlePositionForFlow(0.002, 0.9, 100, 0), 1e-2);
EXPECT_NEAR( 8.571, model.throttlePositionForFlow(0.005, 0.9, 100, 0), 1e-2);
EXPECT_NEAR(11.670, model.throttlePositionForFlow(0.010, 0.9, 100, 0), 1e-2);
EXPECT_NEAR(37.473, model.throttlePositionForFlow(0.100, 0.9, 100, 0), 1e-2);
EXPECT_NEAR(51.348, model.throttlePositionForFlow(0.200, 0.9, 100, 0), 1e-2);
EXPECT_NEAR(74.510, model.throttlePositionForFlow(0.400, 0.9, 100, 0), 1e-2);
EXPECT_NEAR(87.093, model.throttlePositionForFlow(0.470, 0.9, 100, 0), 1e-2);
EXPECT_NEAR(88.737, model.throttlePositionForFlow(0.471, 0.9, 100, 0), 1e-2);
// Throttle is maxed out here!
EXPECT_NEAR(100.00, model.throttlePositionForFlow(0.473, 0.9, 100, 0), 1e-2);
EXPECT_NEAR(100.00, model.throttlePositionForFlow(0.500, 0.9, 100, 0), 1e-2);
EXPECT_NEAR(100.00, model.throttlePositionForFlow(0.600, 0.9, 100, 0), 1e-2);
EXPECT_NEAR(100.00, model.throttlePositionForFlow(0.700, 0.9, 100, 0), 1e-2);
}
TEST(ThrottleModel, SmallEngineBigThrottle) {
MockThrottleModel model;
// Engine can only flow 0.2kg/s at 100kPa, much less than wide open throttle
EXPECT_CALL(model, maxEngineFlow(::testing::_)).WillRepeatedly([](float map) { return map / 100 * 0.2f; });
// v part throttle model v
EXPECT_NEAR(0.082f, model.estimateThrottleFlow(100, 40, 95, 0), 1e-3);
EXPECT_NEAR(0.138f, model.estimateThrottleFlow(100, 50, 95, 0), 1e-3);
// ^ part throttle model ^
// this engine does 0.95PR at 59% throttle, as the throttle is very big for the engine
// v blend from part throttle to WOT v
EXPECT_NEAR(0.190f, model.estimateThrottleFlow(100, 60, 95, 0), 1e-3);
EXPECT_NEAR(0.193f, model.estimateThrottleFlow(100, 70, 95, 0), 1e-3);
EXPECT_NEAR(0.195f, model.estimateThrottleFlow(100, 80, 95, 0), 1e-3);
EXPECT_NEAR(0.198f, model.estimateThrottleFlow(100, 90, 95, 0), 1e-3);
// ^ blend from part throttle to WOT ^
// v WOT v
EXPECT_NEAR(0.20f, model.estimateThrottleFlow(100, 100, 95, 0), 1e-3);
}
TEST(ThrottleModel, BigEngineSmallThrottle) {
MockThrottleModel model;
// Big engine can flow 2g/s, much more than wide open throttle will support
EXPECT_CALL(model, maxEngineFlow(::testing::_)).WillRepeatedly([](float map) { return map / 100 * 2; });
// v part throttle model v
EXPECT_NEAR(0.082f, model.estimateThrottleFlow(100, 40, 95, 0), 1e-3);
EXPECT_NEAR(0.138f, model.estimateThrottleFlow(100, 50, 95, 0), 1e-3);
EXPECT_NEAR(0.194f, model.estimateThrottleFlow(100, 60, 95, 0), 1e-3);
EXPECT_NEAR(0.261f, model.estimateThrottleFlow(100, 70, 95, 0), 1e-3);
EXPECT_NEAR(0.327f, model.estimateThrottleFlow(100, 80, 95, 0), 1e-3);
EXPECT_NEAR(0.343f, model.estimateThrottleFlow(100, 90, 95, 0), 1e-3);
EXPECT_NEAR(0.343f, model.estimateThrottleFlow(100, 100, 95, 0), 1e-3);
// ^ part throttle model ^
}