foxBMS  1.2.1
The foxBMS Battery Management System API Documentation
sof.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2021, Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V.
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice, this
12  * list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  * contributors may be used to endorse or promote products derived from
20  * this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * We kindly request you to use one or more of the following phrases to refer to
34  * foxBMS in your hardware, software, documentation or advertising materials:
35  *
36  * - ″This product uses parts of foxBMS®″
37  * - ″This product includes parts of foxBMS®″
38  * - ″This product is derived from foxBMS®″
39  *
40  */
41 
42 /**
43  * @file sof.c
44  * @author foxBMS Team
45  * @date 2020-10-07 (date of creation)
46  * @updated 2021-03-24 (date of last update)
47  * @ingroup APPLICATION_CONFIGURATION
48  * @prefix SOX
49  *
50  * @brief SOX module responsible for current derating calculation
51  *
52  */
53 
54 /*========== Includes =======================================================*/
55 #include "sof.h"
56 
57 #include "battery_cell_cfg.h"
58 #include "battery_system_cfg.h"
59 
60 #include "bms.h"
61 #include "database.h"
62 #include "foxmath.h"
63 
64 #include <float.h>
65 
66 /*========== Macros and Definitions =========================================*/
67 
68 /*========== Static Constant and Variable Definitions =======================*/
69 /** @{
70  * module-local static Variables that are calculated at startup and used later to avoid divisions at runtime
71  */
76 /** @} */
77 
78 /** local copies of database tables */
79 /**@{*/
82 /**@}*/
83 
84 /*========== Extern Constant and Variable Definitions =======================*/
85 
86 /*========== Static Function Prototypes =====================================*/
87 
88 /**
89  * @brief calculate SOF curve depending on configured configuration values
90  *
91  * @param[in] pConfigurationValues SOF curve configuration values
92  * @param[out] pCalculatedSofCurveValues calculate SOF curve
93  */
94 static void SOF_CalculateCurves(const SOF_CONFIG_s *pConfigurationValues, SOF_CURVE_s *pCalculatedSofCurveValues);
95 
96 /**
97  * @brief calculates the SoF from voltage data (i.e., minimum and maximum voltage)
98  *
99  * @param[in] minimumCellVoltage_mV minimum cell voltage
100  * @param[in] maximumCellVoltage_mV maximum cell voltage
101  * @param[out] pAllowedVoltageBasedCurrent Voltage-based SOF
102  * @param[in] pConfigLimitValues pointer to the SOF configuration structure
103  * @param[in] pCalculatedSofCurves pointer to the SOF curve structure
104  */
106  int16_t minimumCellVoltage_mV,
107  int16_t maximumCellVoltage_mV,
108  SOF_CURRENT_LIMITS_s *pAllowedVoltageBasedCurrent,
109  const SOF_CONFIG_s *pConfigLimitValues,
110  SOF_CURVE_s *pCalculatedSofCurves);
111 
112 /**
113  * @brief calculates the SoF from temperature data (i.e., minimum and maximum temperature of cells)
114  *
115  * @param[in] minimumCellTemperature_ddegC minimum temperature of cells
116  * @param[in] maximumCellTemperature_ddegC maximum temperature of cells
117  * @param[out] pAllowedTemperatureBasedCurrent pointer where to store the results
118  * @param[in] pConfigLimitValues pointer to the structure used for SOF calculation
119  * @param[in] pCalculatedSofCurves pointer to the structure containing limit values
120  */
122  int16_t minimumCellTemperature_ddegC,
123  int16_t maximumCellTemperature_ddegC,
124  SOF_CURRENT_LIMITS_s *pAllowedTemperatureBasedCurrent,
125  const SOF_CONFIG_s *pConfigLimitValues,
126  SOF_CURVE_s *pCalculatedSofCurves);
127 
128 /**
129  * @brief get the minimum current values of all variants of SoF calculation
130  *
131  * @param[in] voltageBasedLimits voltage constrained current derating values
132  * @param[in] temperatureBasedLimits temperature constrained current derating values
133  *
134  * @return minimum SoF current values
135  */
137  SOF_CURRENT_LIMITS_s voltageBasedLimits,
138  SOF_CURRENT_LIMITS_s temperatureBasedLimits);
139 
140 /*========== Static Function Implementations ================================*/
141 static void SOF_CalculateCurves(const SOF_CONFIG_s *pConfigurationValues, SOF_CURVE_s *pCalculatedSofCurveValues) {
142  FAS_ASSERT(pConfigurationValues != NULL_PTR);
143  FAS_ASSERT(pCalculatedSofCurveValues != NULL_PTR);
144 
145  /* Calculating SOF curve for the maximum allowed current for MOL/RSL/MSL */
146  pCalculatedSofCurveValues->slopeLowTemperatureDischarge =
147  (pConfigurationValues->maximumDischargeCurrent_mA - pConfigurationValues->limpHomeCurrent_mA) /
148  (pConfigurationValues->cutoffLowTemperatureDischarge_ddegC -
149  pConfigurationValues->limitLowTemperatureDischarge_ddegC);
150  pCalculatedSofCurveValues->offsetLowTemperatureDischarge =
151  pConfigurationValues->limpHomeCurrent_mA - (pCalculatedSofCurveValues->slopeLowTemperatureDischarge *
152  pConfigurationValues->limitLowTemperatureDischarge_ddegC);
153 
154  pCalculatedSofCurveValues->slopeHighTemperatureDischarge =
155  (0.0f - pConfigurationValues->maximumDischargeCurrent_mA) /
156  (pConfigurationValues->limitHighTemperatureDischarge_ddegC -
157  pConfigurationValues->cutoffHighTemperatureDischarge_ddegC);
158  pCalculatedSofCurveValues->offsetHighTemperatureDischarge =
159  0.0f - (pCalculatedSofCurveValues->slopeHighTemperatureDischarge *
160  pConfigurationValues->limitHighTemperatureDischarge_ddegC);
161 
162  pCalculatedSofCurveValues->slopeLowTemperatureCharge = (pConfigurationValues->maximumChargeCurrent_mA - 0.0f) /
163  (pConfigurationValues->cutoffLowTemperatureCharge_ddegC -
164  pConfigurationValues->limitLowTemperatureCharge_ddegC);
165  pCalculatedSofCurveValues->offsetLowTemperatureCharge =
166  0.0f -
167  (pCalculatedSofCurveValues->slopeLowTemperatureCharge * pConfigurationValues->limitLowTemperatureCharge_ddegC);
168 
169  pCalculatedSofCurveValues->slopeHighTemperatureCharge = (0.0f - pConfigurationValues->maximumChargeCurrent_mA) /
170  (pConfigurationValues->limitHighTemperatureCharge_ddegC -
171  pConfigurationValues->cutoffHighTemperatureCharge_ddegC);
172  pCalculatedSofCurveValues->offsetHighTemperatureCharge = 0.0f -
173  (pCalculatedSofCurveValues->slopeHighTemperatureCharge *
174  pConfigurationValues->limitHighTemperatureCharge_ddegC);
175 
176  pCalculatedSofCurveValues->slopeUpperCellVoltage =
177  (pConfigurationValues->maximumDischargeCurrent_mA - 0.0f) /
178  (pConfigurationValues->cutoffLowerCellVoltage_mV - pConfigurationValues->limitLowerCellVoltage_mV);
179  pCalculatedSofCurveValues->offsetUpperCellVoltage =
180  0.0f - (pCalculatedSofCurveValues->slopeUpperCellVoltage * pConfigurationValues->limitLowerCellVoltage_mV);
181 
182  pCalculatedSofCurveValues->slopeLowerCellVoltage =
183  (pConfigurationValues->maximumChargeCurrent_mA - 0.0f) /
184  (pConfigurationValues->cutoffUpperCellVoltage_mV - pConfigurationValues->limitUpperCellVoltage_mV);
185  pCalculatedSofCurveValues->offsetLowerCellVoltage =
186  0.0f - (pCalculatedSofCurveValues->slopeLowerCellVoltage * pConfigurationValues->limitLowerCellVoltage_mV);
187 }
188 
190  int16_t minimumCellVoltage_mV,
191  int16_t maximumCellVoltage_mV,
192  SOF_CURRENT_LIMITS_s *pAllowedVoltageBasedCurrent,
193  const SOF_CONFIG_s *pConfigLimitValues,
194  SOF_CURVE_s *pCalculatedSofCurves) {
195  FAS_ASSERT(pAllowedVoltageBasedCurrent != NULL_PTR);
196  FAS_ASSERT(pConfigLimitValues != NULL_PTR);
197  FAS_ASSERT(pCalculatedSofCurves != NULL_PTR);
198 
199  /* minimum cell voltage calculation */
200  if (minimumCellVoltage_mV <= pConfigLimitValues->limitLowerCellVoltage_mV) {
201  pAllowedVoltageBasedCurrent->continuousDischargeCurrent_mA = 0.0f;
202  pAllowedVoltageBasedCurrent->peakDischargeCurrent_mA = 0.0f;
203  } else {
204  if (minimumCellVoltage_mV <= pConfigLimitValues->cutoffLowerCellVoltage_mV) {
205  pAllowedVoltageBasedCurrent->continuousDischargeCurrent_mA =
206  (pCalculatedSofCurves->slopeUpperCellVoltage *
207  (minimumCellVoltage_mV - pConfigLimitValues->limitLowerCellVoltage_mV));
208  pAllowedVoltageBasedCurrent->peakDischargeCurrent_mA =
209  pAllowedVoltageBasedCurrent->continuousDischargeCurrent_mA;
210  } else {
211  pAllowedVoltageBasedCurrent->continuousDischargeCurrent_mA = pConfigLimitValues->maximumDischargeCurrent_mA;
212  pAllowedVoltageBasedCurrent->peakDischargeCurrent_mA = pConfigLimitValues->maximumDischargeCurrent_mA;
213  }
214  }
215  /* maximum cell voltage calculation */
216  if (maximumCellVoltage_mV >= pConfigLimitValues->limitUpperCellVoltage_mV) {
217  pAllowedVoltageBasedCurrent->continuousChargeCurrent_mA = 0.0f;
218  pAllowedVoltageBasedCurrent->peakChargeCurrent_mA = 0.0f;
219  } else {
220  if (maximumCellVoltage_mV >= pConfigLimitValues->cutoffUpperCellVoltage_mV) {
221  pAllowedVoltageBasedCurrent->continuousChargeCurrent_mA =
222  (pCalculatedSofCurves->slopeLowerCellVoltage *
223  (maximumCellVoltage_mV - pConfigLimitValues->limitUpperCellVoltage_mV));
224  pAllowedVoltageBasedCurrent->peakChargeCurrent_mA = pAllowedVoltageBasedCurrent->continuousChargeCurrent_mA;
225  } else {
226  pAllowedVoltageBasedCurrent->continuousChargeCurrent_mA = pConfigLimitValues->maximumChargeCurrent_mA;
227  pAllowedVoltageBasedCurrent->peakChargeCurrent_mA = pConfigLimitValues->maximumChargeCurrent_mA;
228  }
229  }
230 }
231 
233  int16_t minimumCellTemperature_ddegC,
234  int16_t maximumCellTemperature_ddegC,
235  SOF_CURRENT_LIMITS_s *pAllowedTemperatureBasedCurrent,
236  const SOF_CONFIG_s *pConfigLimitValues,
237  SOF_CURVE_s *pCalculatedSofCurves) {
238  FAS_ASSERT(pAllowedTemperatureBasedCurrent != NULL_PTR);
239  FAS_ASSERT(pConfigLimitValues != NULL_PTR);
240  FAS_ASSERT(pCalculatedSofCurves != NULL_PTR);
241 
242  SOF_CURRENT_LIMITS_s temporaryCurrentLimits = {0.0f, 0.0f, 0.0f, 0.0f};
243  /* Temperature low Discharge */
244  if (minimumCellTemperature_ddegC <= pConfigLimitValues->limitLowTemperatureDischarge_ddegC) {
245  pAllowedTemperatureBasedCurrent->continuousDischargeCurrent_mA = pConfigLimitValues->limpHomeCurrent_mA;
246  pAllowedTemperatureBasedCurrent->peakDischargeCurrent_mA = pConfigLimitValues->limpHomeCurrent_mA;
247  } else {
248  if (minimumCellTemperature_ddegC <= pConfigLimitValues->cutoffLowTemperatureDischarge_ddegC) {
249  pAllowedTemperatureBasedCurrent->continuousDischargeCurrent_mA =
250  (pCalculatedSofCurves->slopeLowTemperatureDischarge * minimumCellTemperature_ddegC) +
251  pCalculatedSofCurves->offsetLowTemperatureDischarge;
252  pAllowedTemperatureBasedCurrent->peakDischargeCurrent_mA =
253  pAllowedTemperatureBasedCurrent->continuousDischargeCurrent_mA;
254  } else {
255  pAllowedTemperatureBasedCurrent->continuousDischargeCurrent_mA =
256  pConfigLimitValues->maximumDischargeCurrent_mA;
257  pAllowedTemperatureBasedCurrent->peakDischargeCurrent_mA = pConfigLimitValues->maximumDischargeCurrent_mA;
258  }
259  }
260  /* Temperature low charge */
261  if (minimumCellTemperature_ddegC <= pConfigLimitValues->limitLowTemperatureCharge_ddegC) {
262  pAllowedTemperatureBasedCurrent->continuousChargeCurrent_mA = 0;
263  pAllowedTemperatureBasedCurrent->peakChargeCurrent_mA = 0;
264  } else {
265  if (minimumCellTemperature_ddegC <= pConfigLimitValues->cutoffLowTemperatureCharge_ddegC) {
266  pAllowedTemperatureBasedCurrent->continuousChargeCurrent_mA =
267  (pCalculatedSofCurves->slopeLowTemperatureCharge * minimumCellTemperature_ddegC) +
268  pCalculatedSofCurves->offsetLowTemperatureCharge;
269  pAllowedTemperatureBasedCurrent->peakChargeCurrent_mA =
270  pAllowedTemperatureBasedCurrent->continuousChargeCurrent_mA;
271  } else {
272  pAllowedTemperatureBasedCurrent->continuousChargeCurrent_mA = pConfigLimitValues->maximumChargeCurrent_mA;
273  pAllowedTemperatureBasedCurrent->peakChargeCurrent_mA = pConfigLimitValues->maximumChargeCurrent_mA;
274  }
275  }
276  /* Temperature high discharge */
277  if (maximumCellTemperature_ddegC >= pConfigLimitValues->limitHighTemperatureDischarge_ddegC) {
278  pAllowedTemperatureBasedCurrent->continuousDischargeCurrent_mA = 0.0f;
279  pAllowedTemperatureBasedCurrent->peakDischargeCurrent_mA = 0.0f;
280  } else {
281  if (maximumCellTemperature_ddegC >= pConfigLimitValues->cutoffHighTemperatureDischarge_ddegC) {
282  temporaryCurrentLimits.continuousDischargeCurrent_mA =
283  (pCalculatedSofCurves->slopeHighTemperatureDischarge * maximumCellTemperature_ddegC) +
284  pCalculatedSofCurves->offsetHighTemperatureDischarge;
285  temporaryCurrentLimits.peakDischargeCurrent_mA = temporaryCurrentLimits.continuousDischargeCurrent_mA;
286  } else {
287  /* do nothing because this situation is handled with minimumCellTemperature_ddegC */
288  temporaryCurrentLimits.continuousDischargeCurrent_mA = pConfigLimitValues->maximumDischargeCurrent_mA;
289  temporaryCurrentLimits.peakDischargeCurrent_mA = pConfigLimitValues->maximumDischargeCurrent_mA;
290  }
291  /* Derating value for minimum cell temperature has already been calculated and result is saved in
292  pAllowedTemperatureBasedCurrentCheck. Check now if newly calculated derating value for maximum
293  cell temperatures is smaller than the previously calculated value */
294  pAllowedTemperatureBasedCurrent->continuousDischargeCurrent_mA = MATH_MinimumOfTwoFloats(
295  pAllowedTemperatureBasedCurrent->continuousDischargeCurrent_mA,
296  temporaryCurrentLimits.continuousDischargeCurrent_mA);
297  pAllowedTemperatureBasedCurrent->peakDischargeCurrent_mA = MATH_MinimumOfTwoFloats(
298  pAllowedTemperatureBasedCurrent->peakDischargeCurrent_mA, temporaryCurrentLimits.peakDischargeCurrent_mA);
299  }
300  /* Temperature high Charge */
301  if (maximumCellTemperature_ddegC >= pConfigLimitValues->limitHighTemperatureCharge_ddegC) {
302  pAllowedTemperatureBasedCurrent->continuousChargeCurrent_mA = 0.0f;
303  pAllowedTemperatureBasedCurrent->peakChargeCurrent_mA = 0.0f;
304  } else {
305  if (maximumCellTemperature_ddegC >= pConfigLimitValues->cutoffHighTemperatureCharge_ddegC) {
306  temporaryCurrentLimits.continuousChargeCurrent_mA =
307  (pCalculatedSofCurves->slopeHighTemperatureCharge * maximumCellTemperature_ddegC) +
308  pCalculatedSofCurves->offsetHighTemperatureCharge;
309  temporaryCurrentLimits.peakChargeCurrent_mA = temporaryCurrentLimits.continuousChargeCurrent_mA;
310  } else {
311  /* do nothing because this situation is handled with minimumCellTemperature_ddegC */
312  temporaryCurrentLimits.continuousChargeCurrent_mA = pConfigLimitValues->maximumChargeCurrent_mA;
313  temporaryCurrentLimits.peakChargeCurrent_mA = pConfigLimitValues->maximumChargeCurrent_mA;
314  }
315  /* Derating value for minimum cell temperature has already been calculated and result is saved in
316  pAllowedTemperatureBasedCurrentCheck. Check now if newly calculated derating value for maximum
317  cell temperatures is smaller than the previously calculated value */
318  pAllowedTemperatureBasedCurrent->continuousChargeCurrent_mA = MATH_MinimumOfTwoFloats(
319  pAllowedTemperatureBasedCurrent->continuousChargeCurrent_mA,
320  temporaryCurrentLimits.continuousChargeCurrent_mA);
321  pAllowedTemperatureBasedCurrent->peakChargeCurrent_mA = MATH_MinimumOfTwoFloats(
322  pAllowedTemperatureBasedCurrent->peakChargeCurrent_mA, temporaryCurrentLimits.peakChargeCurrent_mA);
323  }
324 }
325 
327  SOF_CURRENT_LIMITS_s voltageBasedLimits,
328  SOF_CURRENT_LIMITS_s temperatureBasedLimits) {
329  SOF_CURRENT_LIMITS_s retval = {0};
331  voltageBasedLimits.continuousChargeCurrent_mA, temperatureBasedLimits.continuousChargeCurrent_mA);
332  retval.peakChargeCurrent_mA =
333  MATH_MinimumOfTwoFloats(voltageBasedLimits.peakChargeCurrent_mA, temperatureBasedLimits.peakChargeCurrent_mA);
335  voltageBasedLimits.continuousDischargeCurrent_mA, temperatureBasedLimits.continuousDischargeCurrent_mA);
337  voltageBasedLimits.peakDischargeCurrent_mA, temperatureBasedLimits.peakDischargeCurrent_mA);
338  return retval;
339 }
340 
341 /*========== Extern Function Implementations ================================*/
342 extern void SOF_Init(void) {
343  /* Calculating SOF curve for the recommended operating current */
345 
346 #if BMS_CHECK_SOF_CURRENT_LIMITS == true
347  /* Calculating SOF curve for maximum operating limit */
349 
350  /* Calculating SOF curve for recommended safety limit */
352 
353  /* Calculating SOF curve for maximum safety limit */
355 #endif
356 }
357 
358 extern void SOF_Calculation(void) {
359  SOF_CURRENT_LIMITS_s allowedCurrent = {0};
360 
362 
363  /* Reset allowed current values */
368 
369  uint8_t nrClosedStrings = 0;
370  float minDischarge_mA = FLT_MAX;
371  float minCharge_mA = FLT_MAX;
372 
373  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
374  SOF_CURRENT_LIMITS_s voltageBasedSof = {0};
375  SOF_CURRENT_LIMITS_s temperatureBasedSof = {0};
376  /* Calculate allowed current if string is connected */
377  if (true == BMS_IsStringClosed(stringNumber)) {
381  &voltageBasedSof,
387  &temperatureBasedSof,
390  allowedCurrent = SOF_MinimumOfTwoSofValues(voltageBasedSof, temperatureBasedSof);
391 
393  allowedCurrent.continuousChargeCurrent_mA;
395  allowedCurrent.continuousDischargeCurrent_mA;
398  allowedCurrent.peakDischargeCurrent_mA;
399 
400  nrClosedStrings++;
401  if (minCharge_mA > sof_tableSofValues.recommendedContinuousChargeCurrent_mA[stringNumber]) {
402  minCharge_mA = sof_tableSofValues.recommendedContinuousChargeCurrent_mA[stringNumber];
403  }
404  if (minDischarge_mA > sof_tableSofValues.recommendedContinuousDischargeCurrent_mA[stringNumber]) {
405  minDischarge_mA = sof_tableSofValues.recommendedContinuousDischargeCurrent_mA[stringNumber];
406  }
407  } else {
412  }
413 
414 #if BMS_CHECK_SOF_CURRENT_LIMITS == true
415  /* Calculate maximum allowed current MOL level */
419  &voltageBasedSof,
421  &sof_curveMol);
425  &temperatureBasedSof,
427  &sof_curveMol);
428  allowedCurrent = SOF_MinimumOfTwoSofValues(voltageBasedSof, temperatureBasedSof);
431  allowedCurrent.continuousDischargeCurrent_mA;
432  sof_tableSofValues.peakMolChargeCurrent_mA[stringNumber] = allowedCurrent.peakChargeCurrent_mA;
434 
435  /* Calculate maximum allowed current RSL level */
439  &voltageBasedSof,
441  &sof_curveRsl);
445  &temperatureBasedSof,
447  &sof_curveRsl);
448  allowedCurrent = SOF_MinimumOfTwoSofValues(voltageBasedSof, temperatureBasedSof);
451  allowedCurrent.continuousDischargeCurrent_mA;
452  sof_tableSofValues.peakRslChargeCurrent_mA[stringNumber] = allowedCurrent.peakChargeCurrent_mA;
454 
455  /* Calculate maximum allowed current MSL level */
459  &voltageBasedSof,
461  &sof_curveMsl);
465  &temperatureBasedSof,
467  &sof_curveMsl);
468  allowedCurrent = SOF_MinimumOfTwoSofValues(voltageBasedSof, temperatureBasedSof);
471  allowedCurrent.continuousDischargeCurrent_mA;
472  sof_tableSofValues.peakMslChargeCurrent_mA[stringNumber] = allowedCurrent.peakChargeCurrent_mA;
474 #else /* BMS_CHECK_SOF_CURRENT_LIMITS == false */
479 
484 
489 #endif /* BMS_CHECK_SOF_CURRENT_LIMITS == true */
490  }
491 
492  if (minCharge_mA > (float)BS_MAXIMUM_STRING_CURRENT_mA) {
493  minCharge_mA = (float)BS_MAXIMUM_STRING_CURRENT_mA;
494  }
495  if (minDischarge_mA > (float)BS_MAXIMUM_STRING_CURRENT_mA) {
496  minDischarge_mA = (float)BS_MAXIMUM_STRING_CURRENT_mA;
497  }
498 
499  /* Compute recommended pack values */
500  sof_tableSofValues.recommendedContinuousPackChargeCurrent_mA = (float)nrClosedStrings * minCharge_mA;
501  sof_tableSofValues.recommendedContinuousPackDischargeCurrent_mA = (float)nrClosedStrings * minDischarge_mA;
502  sof_tableSofValues.recommendedPeakPackChargeCurrent_mA = (float)nrClosedStrings * minCharge_mA;
503  sof_tableSofValues.recommendedPeakPackDischargeCurrent_mA = (float)nrClosedStrings * minDischarge_mA;
504 
506 }
507 
508 /*========== Externalized Static Function Implementations (Unit Test) =======*/
509 #ifdef UNITY_UNIT_TEST
510 extern void TEST_SOF_CalculateCurves(const SOF_CONFIG_s *pConfigurationValues, SOF_CURVE_s *pCalculatedSofCurveValues) {
511  SOF_CalculateCurves(pConfigurationValues, pCalculatedSofCurveValues);
512 }
513 extern void TEST_SOF_CalculateVoltageBasedCurrentLimit(
514  int16_t minimumCellVoltage_mV,
515  int16_t maximumCellVoltage_mV,
516  SOF_CURRENT_LIMITS_s *pAllowedVoltageBasedCurrent,
517  const SOF_CONFIG_s *pConfigLimitValues,
518  SOF_CURVE_s *pCalculatedSofCurves) {
520  minimumCellVoltage_mV,
521  maximumCellVoltage_mV,
522  pAllowedVoltageBasedCurrent,
523  pConfigLimitValues,
524  pCalculatedSofCurves);
525 }
526 extern void TEST_SOF_CalculateTemperatureBasedCurrentLimit(
527  int16_t minimumCellTemperature_ddegC,
528  int16_t maximumCellTemperature_ddegC,
529  SOF_CURRENT_LIMITS_s *pAllowedTemperatureBasedCurrent,
530  const SOF_CONFIG_s *pConfigLimitValues,
531  SOF_CURVE_s *pCalculatedSofCurves) {
533  minimumCellTemperature_ddegC,
534  maximumCellTemperature_ddegC,
535  pAllowedTemperatureBasedCurrent,
536  pConfigLimitValues,
537  pCalculatedSofCurves);
538 }
539 extern SOF_CURRENT_LIMITS_s TEST_SOF_MinimumOfTwoSofValues(
540  SOF_CURRENT_LIMITS_s voltageBasedLimits,
541  SOF_CURRENT_LIMITS_s temperatureBasedLimits) {
542  return SOF_MinimumOfTwoSofValues(voltageBasedLimits, temperatureBasedLimits);
543 }
544 #endif
Configuration of the battery cell (e.g., minimum and maximum cell voltage)
#define BC_CURRENT_MAX_CHARGE_RSL_mA
Maximum charge current limit.
#define BC_CURRENT_MAX_DISCHARGE_MOL_mA
Maximum discharge current limit.
#define BC_CURRENT_MAX_DISCHARGE_MSL_mA
Maximum discharge current limit.
#define BC_CURRENT_MAX_DISCHARGE_RSL_mA
Maximum discharge current limit.
#define BC_CURRENT_MAX_CHARGE_MSL_mA
Maximum charge current limit.
#define BC_CURRENT_MAX_CHARGE_MOL_mA
Maximum charge current limit.
Configuration of the battery system (e.g., number of battery modules, battery cells,...
#define BS_NR_OF_STRINGS
#define BS_MAXIMUM_STRING_CURRENT_mA
Maximum string current limit in mA that is used in the SOA module to check for string overcurrent.
bool BMS_IsStringClosed(uint8_t stringNumber)
Returns string state (closed or open)
Definition: bms.c:1288
bms driver header
Database module header.
#define DATA_READ_DATA(...)
Definition: database.h:76
#define DATA_WRITE_DATA(...)
Definition: database.h:86
@ DATA_BLOCK_ID_MIN_MAX
Definition: database_cfg.h:75
@ DATA_BLOCK_ID_SOF
Definition: database_cfg.h:86
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:239
float MATH_MinimumOfTwoFloats(const float value1, const float value2)
Returns the minimum of the passed float values.
Definition: foxmath.c:132
math library for often used math functions
#define NULL_PTR
Null pointer.
Definition: fstd_types.h:75
static SOF_CURVE_s sof_curveMol
Definition: sof.c:73
static void SOF_CalculateTemperatureBasedCurrentLimit(int16_t minimumCellTemperature_ddegC, int16_t maximumCellTemperature_ddegC, SOF_CURRENT_LIMITS_s *pAllowedTemperatureBasedCurrent, const SOF_CONFIG_s *pConfigLimitValues, SOF_CURVE_s *pCalculatedSofCurves)
calculates the SoF from temperature data (i.e., minimum and maximum temperature of cells)
Definition: sof.c:232
void SOF_Calculation(void)
triggers SOF calculation
Definition: sof.c:358
static DATA_BLOCK_SOF_s sof_tableSofValues
Definition: sof.c:81
static SOF_CURVE_s sof_curveRsl
Definition: sof.c:74
static DATA_BLOCK_MIN_MAX_s sof_tableMinimumMaximumValues
Definition: sof.c:80
static void SOF_CalculateVoltageBasedCurrentLimit(int16_t minimumCellVoltage_mV, int16_t maximumCellVoltage_mV, SOF_CURRENT_LIMITS_s *pAllowedVoltageBasedCurrent, const SOF_CONFIG_s *pConfigLimitValues, SOF_CURVE_s *pCalculatedSofCurves)
calculates the SoF from voltage data (i.e., minimum and maximum voltage)
Definition: sof.c:189
static void SOF_CalculateCurves(const SOF_CONFIG_s *pConfigurationValues, SOF_CURVE_s *pCalculatedSofCurveValues)
calculate SOF curve depending on configured configuration values
Definition: sof.c:141
static SOF_CURVE_s sof_curveMsl
Definition: sof.c:75
static SOF_CURRENT_LIMITS_s SOF_MinimumOfTwoSofValues(SOF_CURRENT_LIMITS_s voltageBasedLimits, SOF_CURRENT_LIMITS_s temperatureBasedLimits)
get the minimum current values of all variants of SoF calculation
Definition: sof.c:326
static SOF_CURVE_s sof_curveRecommendedOperatingCurrent
Definition: sof.c:72
void SOF_Init(void)
initializes the area for SOF (where derating starts and is fully active).
Definition: sof.c:342
Header for SOX module, responsible for current derating calculation.
const SOF_CONFIG_s sof_recommendedCurrent
Definition: sof_cfg.c:63
const SOF_CONFIG_s sof_recommendedSafetyLimit
Definition: sof_cfg.c:97
const SOF_CONFIG_s sof_configMaximumSafetyLimit
Definition: sof_cfg.c:114
const SOF_CONFIG_s sof_maximumOperatingLimit
Definition: sof_cfg.c:80
DATA_BLOCK_ID_e uniqueId
Definition: database_cfg.h:111
int16_t maximumTemperature_ddegC[BS_NR_OF_STRINGS]
Definition: database_cfg.h:166
int16_t minimumTemperature_ddegC[BS_NR_OF_STRINGS]
Definition: database_cfg.h:163
int16_t maximumCellVoltage_mV[BS_NR_OF_STRINGS]
Definition: database_cfg.h:155
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:150
int16_t minimumCellVoltage_mV[BS_NR_OF_STRINGS]
Definition: database_cfg.h:153
float peakMslChargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:405
float peakRslChargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:401
float recommendedContinuousPackDischargeCurrent_mA
Definition: database_cfg.h:386
float peakMolChargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:397
float recommendedPeakDischargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:394
float recommendedContinuousChargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:390
float peakMolDischargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:398
float recommendedPeakPackDischargeCurrent_mA
Definition: database_cfg.h:388
float peakRslDischargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:402
float continuousRslChargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:399
float peakMslDischargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:406
float recommendedContinuousPackChargeCurrent_mA
Definition: database_cfg.h:385
float continuousMslDischargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:404
float continuousRslDischargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:400
float continuousMolChargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:395
float continuousMolDischargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:396
float continuousMslChargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:403
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:384
float recommendedContinuousDischargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:392
float recommendedPeakChargeCurrent_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:393
float recommendedPeakPackChargeCurrent_mA
Definition: database_cfg.h:387
float limpHomeCurrent_mA
Definition: sof_cfg.h:325
int16_t limitUpperCellVoltage_mV
Definition: sof_cfg.h:344
int16_t cutoffUpperCellVoltage_mV
Definition: sof_cfg.h:343
int16_t limitHighTemperatureDischarge_ddegC
Definition: sof_cfg.h:337
float maximumDischargeCurrent_mA
Definition: sof_cfg.h:323
int16_t limitLowerCellVoltage_mV
Definition: sof_cfg.h:346
int16_t cutoffLowTemperatureCharge_ddegC
Definition: sof_cfg.h:331
int16_t limitLowTemperatureDischarge_ddegC
Definition: sof_cfg.h:330
int16_t limitLowTemperatureCharge_ddegC
Definition: sof_cfg.h:332
int16_t cutoffHighTemperatureDischarge_ddegC
Definition: sof_cfg.h:336
float maximumChargeCurrent_mA
Definition: sof_cfg.h:324
int16_t cutoffLowerCellVoltage_mV
Definition: sof_cfg.h:345
int16_t limitHighTemperatureCharge_ddegC
Definition: sof_cfg.h:339
int16_t cutoffLowTemperatureDischarge_ddegC
Definition: sof_cfg.h:329
int16_t cutoffHighTemperatureCharge_ddegC
Definition: sof_cfg.h:338
float peakDischargeCurrent_mA
Definition: sof.h:69
float peakChargeCurrent_mA
Definition: sof.h:67
float continuousDischargeCurrent_mA
Definition: sof.h:68
float continuousChargeCurrent_mA
Definition: sof.h:66
Definition: sof.h:76
float slopeHighTemperatureDischarge
Definition: sof.h:79
float offsetLowerCellVoltage
Definition: sof.h:90
float offsetLowTemperatureCharge
Definition: sof.h:83
float offsetHighTemperatureDischarge
Definition: sof.h:80
float slopeUpperCellVoltage
Definition: sof.h:87
float slopeLowerCellVoltage
Definition: sof.h:89
float offsetUpperCellVoltage
Definition: sof.h:88
float slopeLowTemperatureCharge
Definition: sof.h:82
float slopeLowTemperatureDischarge
Definition: sof.h:77
float slopeHighTemperatureCharge
Definition: sof.h:84
float offsetLowTemperatureDischarge
Definition: sof.h:78
float offsetHighTemperatureCharge
Definition: sof.h:85