rusEFI
The most advanced open source ECU
injector_model.cpp
Go to the documentation of this file.
1 
2 // here am flirting with not using pch.h and not including at least Engine
3 #include <rusefi/interpolation.h>
4 #include <rusefi/arrays.h>
5 #include "engine_configuration.h"
6 #include "sensor.h"
7 #include "error_handling.h"
8 
9 #include "injector_model.h"
10 #include "fuel_computer.h"
11 
13  float flowRatio = getInjectorFlowRatio();
14 
15  // "large pulse" flow rate
16  m_massFlowRate = flowRatio * getBaseFlowRate();
18 
19  if (getNonlinearMode() == INJ_FordModel) {
22 
23  // amount added to small pulses to correct for the "kink" from low flow region
25  }
26 }
27 
28 constexpr float convertToGramsPerSecond(float ccPerMinute) {
29  return ccPerMinute * (fuelDensity / 60.f);
30 }
31 
34  return m_cfg->flow;
35  } else {
37  }
38 }
39 
42 }
43 
45  // convert milligrams -> grams
47 }
48 
51 }
52 
54  // not supported on second bank
55  return 0;
56 }
57 
59  // not supported on second bank
60  return 0;
61 }
62 
64  // nonlinear not supported on second bank
65  return InjectorNonlinearMode::INJ_None;
66 }
67 
69  auto map = Sensor::get(SensorType::Map);
71 
72  float baroKpa = baro.Value;
73  if (!baro || baro.Value > 120 || baro.Value < 50) {
74  baroKpa = 101.325f;
75  }
76 
78  case ICM_FixedRailPressure:
79  // Add barometric pressure, as "fixed" really means "fixed pressure above atmosphere"
80  return
82  + baroKpa
83  - map.value_or(101.325);
84  case ICM_SensedRailPressure: {
86  criticalError("Fuel pressure compensation is set to use a pressure sensor, but none is configured.");
87  return unexpected;
88  }
89 
91 
92  // TODO: what happens when the sensor fails?
93  if (!fps) {
94  return unexpected;
95  }
96 
98  case FPM_Differential:
99  // This sensor directly measures delta-P, no math needed!
100  return fps.Value;
101  case FPM_Gauge:
102  if (!map) {
103  return unexpected;
104  }
105 
106  return fps.Value + baroKpa - map.Value;
107  case FPM_Absolute:
108  default:
109  if (!map) {
110  return unexpected;
111  }
112 
113  return fps.Value - map.Value;
114  }
115  } default: return unexpected;
116  }
117 }
118 
120  // Compensation disabled, use reference flow.
122  return 1.0f;
123  }
124 
125  float referencePressure = engineConfiguration->fuelReferencePressure;
126 
127  if (referencePressure < 50) {
128  // impossibly low fuel ref pressure
129  criticalError("Impossible fuel reference pressure: %f", referencePressure);
130 
131  return 1.0f;
132  }
133 
134  expected<float> diffPressure = getFuelDifferentialPressure();
135 
136  // If sensor failed, best we can do is disable correction
137  if (!diffPressure) {
138  return 1.0f;
139  }
140 
141  pressureDelta = diffPressure.Value;
142 
143  // Somehow pressure delta is less than 0, assume failed sensor and return default flow
144  if (pressureDelta <= 0) {
145  return 1.0f;
146  }
147 
148  pressureRatio = pressureDelta / referencePressure;
149  // todo: live data model?
150  float flowRatio = sqrtf(pressureRatio);
151 
152  // TODO: should the flow ratio be clamped?
153  return flowRatio;
154 }
155 
157  return interpolate2d(
158  Sensor::get(SensorType::BatteryVoltage).value_or(VBAT_FALLBACK_VALUE),
161  );
162 }
163 
164 float InjectorModelBase::getInjectionDuration(float fuelMassGram) const {
165  if (fuelMassGram <= 0) {
166  // If 0 mass, don't do any math, just skip the injection.
167  return 0.0f;
168  }
169 
170  // Get the no-offset duration
171  float baseDuration = getBaseDurationImpl(fuelMassGram);
172 
173  // Add deadtime offset
174  return baseDuration + m_deadtime;
175 }
176 
178  // Convert from ms -> grams
179  return duration * m_massFlowRate * 0.001f;
180 }
181 
182 float InjectorModelBase::getBaseDurationImpl(float fuelMassGram) const {
183  floatms_t baseDuration = fuelMassGram / m_massFlowRate * 1000;
184 
185  switch (getNonlinearMode()) {
186  case INJ_FordModel:
187  if (fuelMassGram < m_smallPulseBreakPoint) {
188  // Small pulse uses a different slope, and adds the "zero fuel pulse" offset
189  return (fuelMassGram / m_smallPulseFlowRate * 1000) + m_smallPulseOffset;
190  } else {
191  // Large pulse
192  return baseDuration;
193  }
194  case INJ_PolynomialAdder:
195  return correctInjectionPolynomial(baseDuration);
196  case INJ_None:
197  default:
198  return baseDuration;
199  }
200 }
201 
202 float InjectorModelBase::correctInjectionPolynomial(float baseDuration) const {
203  if (baseDuration > engineConfiguration->applyNonlinearBelowPulse) {
204  // Large pulse, skip correction.
205  return baseDuration;
206  }
207 
209  float xi = 1;
210 
211  float adder = 0;
212 
213  // Add polynomial terms, starting with x^0
214  for (size_t i = 0; i < efi::size(is); i++) {
215  adder += is[i] * xi;
216  xi *= baseDuration;
217  }
218 
219  return baseDuration + adder;
220 }
221 
223  : m_cfg(cfg)
224 {
225 }
226 
229 {
230 }
231 
232 // TODO: actual separate config for second bank!
234  : InjectorModelWithConfig(&engineConfiguration->injectorSecondary)
235 {
236 }
float getFuelMassForDuration(floatms_t duration) const override
virtual float getInjectorFlowRatio()=0
virtual float correctInjectionPolynomial(float baseDuration) const
virtual float getBaseFlowRate() const =0
virtual float getSmallPulseFlowRate() const =0
float m_smallPulseBreakPoint
float getBaseDurationImpl(float baseDuration) const
virtual float getSmallPulseBreakPoint() const =0
floatms_t getInjectionDuration(float fuelMassGram) const override
void prepare() override
virtual InjectorNonlinearMode getNonlinearMode() const =0
InjectorModelWithConfig(const injector_s *const cfg)
const injector_s *const m_cfg
float getBaseFlowRate() const override
float getInjectorFlowRatio() override
expected< float > getFuelDifferentialPressure() const override
floatms_t getDeadtime() const override
virtual bool hasSensor() const
Definition: sensor.h:155
virtual SensorResult get() const =0
Main engine configuration data structure.
constexpr float fuelDensity
Definition: fuel_computer.h:39
constexpr float convertToGramsPerSecond(float ccPerMinute)
engine_configuration_s * engineConfiguration
InjectorNonlinearMode
Definition: rusefi_enums.h:687
float floatms_t
Definition: rusefi_types.h:67
Base class for sensors. Inherit this class to implement a new type of sensor.
@ FuelPressureInjector
@ BarometricPressure
virtual floatms_t getDeadtime() const =0
float getSmallPulseBreakPoint() const override
float getSmallPulseFlowRate() const override
InjectorNonlinearMode getNonlinearMode() const override
InjectorNonlinearMode getNonlinearMode() const override
float getSmallPulseFlowRate() const override
float getSmallPulseBreakPoint() const override
scaled_channel< uint16_t, 1000, 1 > fordInjectorSmallPulseSlope
scaled_channel< uint16_t, 1000, 1 > applyNonlinearBelowPulse
scaled_channel< uint16_t, 1000, 1 > fordInjectorSmallPulseBreakPoint
float battLagCorrBins[VBAT_INJECTOR_CURVE_SIZE]
float battLagCorr[VBAT_INJECTOR_CURVE_SIZE]
composite packet size