foxBMS  1.1.1
The foxBMS Battery Management System API Documentation
soe_counting.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 soe_counting.c
44  * @author foxBMS Team
45  * @date 2020-10-07 (date of creation)
46  * @updated 2021-05-20 (date of last update)
47  * @ingroup APPLICATION
48  * @prefix SOE
49  *
50  * @brief SOE module responsible for calculation of SOE
51  *
52  */
53 
54 /*========== Includes =======================================================*/
55 #include "soe_counting.h"
56 
57 #include "battery_cell_cfg.h"
58 #include "battery_system_cfg.h"
59 #include "soe_counting_cfg.h"
60 
61 #include "bms.h"
62 #include "database.h"
63 #include "foxmath.h"
64 #include "fram.h"
65 
66 /*========== Macros and Definitions =========================================*/
67 /**
68  * This structure contains all the variables relevant for the SOX.
69  */
70 typedef struct SOE_STATE {
71  bool soeInitialized; /*!< true if the initialization has passed, false otherwise */
72  bool sensorEcUsed[BS_NR_OF_STRINGS]; /*!< true if energy counting functionality of current sensor is used */
73  float ecScalingAverage[BS_NR_OF_STRINGS]; /*!< current sensor offset scaling for average SOE */
74  float ecScalingMinimum[BS_NR_OF_STRINGS]; /*!< current sensor offset scaling for minimum SOE */
75  float ecScalingMaximum[BS_NR_OF_STRINGS]; /*!< current sensor offset scaling for maximum SOE */
77  [BS_NR_OF_STRINGS]; /*!< last used timestamp of current or energy counting value for SOE estimation */
79 
80 /** defines for maximum and minimum SOE */
81 #define MAXIMUM_SOE_PERC (100.0f)
82 #define MINIMUM_SOE_PERC (0.0f)
83 
84 /*========== Static Constant and Variable Definitions =======================*/
85 
86 /**
87  * contains the state of the SOE estimation
88  */
90  .soeInitialized = false,
91  .sensorEcUsed = {REPEAT_U(false, STRIP(BS_NR_OF_STRINGS))},
92  .ecScalingAverage = {REPEAT_U(0.0f, STRIP(BS_NR_OF_STRINGS))},
93  .ecScalingMinimum = {REPEAT_U(0.0f, STRIP(BS_NR_OF_STRINGS))},
94  .ecScalingMaximum = {REPEAT_U(0.0f, STRIP(BS_NR_OF_STRINGS))},
95  .previousTimestamp = {REPEAT_U(0u, STRIP(BS_NR_OF_STRINGS))},
96 };
97 
98 /** local copies of database tables */
99 /**@{*/
101 /**@}*/
102 
103 /*========== Extern Constant and Variable Definitions =======================*/
104 
105 /*========== Static Function Prototypes =====================================*/
106 
107 /**
108  * @brief calculates string energy in Wh from passed SOE in percentage
109  *
110  * @param[in] stringSoe_perc string SOE in percentage [0.0, 100.0]
111  *
112  * @return returns corresponding string energy in Wh
113  */
114 static uint32_t SOE_GetStringEnergyFromSoePercentage(float stringSoe_perc);
115 
116 /**
117  * @brief calculates string SOE in percentage from passed string energy in Wh
118  *
119  * @param[in] energy_Wh string energy in Wh
120  *
121  * @return returns corresponding string SOE in percentage [0.0, 100.0]
122  */
123 static float SOE_GetStringSoePercentageFromEnergy(uint32_t energy_Wh);
124 
125 /**
126  * @brief initializes database and FRAM SOE values via lookup table (average, min and max).
127  * @param[out] pSoeValues pointer to SOE database entry
128  */
129 static void SOE_RecalibrateViaLookupTable(DATA_BLOCK_SOX_s *pSoeValues);
130 
131 /**
132  * @brief look-up table for SOE initialization
133  *
134  * @param[in] voltage_mV cell voltage of battery cell
135  *
136  * @return SOE value in percentage [0.0 - 100.0]
137  */
138 static float SOE_GetFromVoltage(int16_t voltage_mV);
139 
140 /**
141  * @brief sets SOE value with a parameter between 0.0 and 100.0.
142  * @details limits the SOE value to 0.0 respectively 100.0 if a value outside
143  * of the allowed SOE range is passed. Updates local fram and database
144  * struct but does *NOT* write them
145  * @param[out] pSoeValues pointer to SOE database enty
146  * @param[in] soeMinimumValue_perc SOE min value to set
147  * @param[in] soeMaximumValue_perc SOE max value to set
148  * @param[in] soeAverageValue_perc SOE average value to set
149  * @param[in] stringNumber string addressed
150  */
151 static void SOE_SetValue(
152  DATA_BLOCK_SOX_s *pSoeValues,
153  float soeMinimumValue_perc,
154  float soeMaximumValue_perc,
155  float soeAverageValue_perc,
156  uint8_t stringNumber);
157 
158 /**
159  * @brief Check if all database SOE percentage values are within [0.0, 100.0]
160  * Limits SOE values to limit values if outside of this range.
161  *
162  * @param[in,out] pTableSoe pointer to database struct with SOE values
163  * @param[in] stringNumber string that is checked
164  */
165 static void SOE_CheckDatabaseSoePercentageLimits(DATA_BLOCK_SOX_s *pTableSoe, uint8_t stringNumber);
166 
167 /*========== Static Function Implementations ================================*/
168 static float SOE_GetStringSoePercentageFromEnergy(uint32_t energy_Wh) {
169  float stringSoe_perc = 0.0f;
170  const float stringEnergy_Wh = (float)energy_Wh;
171  if (stringEnergy_Wh >= SOE_STRING_ENERGY_Wh) {
172  stringSoe_perc = MAXIMUM_SOE_PERC;
173  } else {
174  stringSoe_perc = UNIT_CONVERSION_FACTOR_100_FLOAT * (stringEnergy_Wh / SOE_STRING_ENERGY_Wh);
175  }
176  return stringSoe_perc;
177 }
178 
179 static uint32_t SOE_GetStringEnergyFromSoePercentage(float stringSoe_perc) {
180  float energy_Wh = 0.0f;
181  if (stringSoe_perc >= MAXIMUM_SOE_PERC) {
182  energy_Wh = SOE_STRING_ENERGY_Wh;
183  } else if (stringSoe_perc <= MINIMUM_SOE_PERC) {
184  energy_Wh = MINIMUM_SOE_PERC;
185  } else {
186  energy_Wh = SOE_STRING_ENERGY_Wh * (stringSoe_perc / UNIT_CONVERSION_FACTOR_100_FLOAT);
187  }
188  return (uint32_t)energy_Wh;
189 }
190 
192  FAS_ASSERT(pSoeValues != NULL_PTR);
193  DATA_BLOCK_MIN_MAX_s tableMinimumMaximumAverage = {.header.uniqueId = DATA_BLOCK_ID_MIN_MAX};
194 
195  DATA_READ_DATA(&tableMinimumMaximumAverage);
196 
197  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
198  SOE_SetValue(
199  pSoeValues,
200  SOE_GetFromVoltage(tableMinimumMaximumAverage.minimumCellVoltage_mV[stringNumber]),
201  SOE_GetFromVoltage(tableMinimumMaximumAverage.maximumCellVoltage_mV[stringNumber]),
202  SOE_GetFromVoltage(tableMinimumMaximumAverage.averageCellVoltage_mV[stringNumber]),
203  stringNumber);
204  }
206 }
207 
208 static float SOE_GetFromVoltage(int16_t voltage_mV) {
209  float soe_perc = 50.0f;
210  /* Variables for interpolating LUT value */
211  uint16_t between_high = 0;
212  uint16_t between_low = 0;
213 
214  /* Cell voltages are inserted in LUT in descending order -> start with 1 as we do not want to extrapolate. */
215  for (uint16_t i = 1u; i < bc_stateOfEnergyLookupTableLength; i++) {
216  if (voltage_mV < bc_stateOfEnergyLookupTable[i].voltage_mV) {
217  between_low = i + 1u;
218  between_high = i;
219  }
220  }
221 
222  /* Interpolate between LUT values, but do not extrapolate LUT! */
223  if (!(((0u == between_high) && (0u == between_low)) || /* cell voltage > maximum LUT voltage */
224  (between_low >= bc_stateOfEnergyLookupTableLength))) { /* cell voltage < minimum LUT voltage */
225  soe_perc = MATH_linearInterpolation(
226  (float)bc_stateOfEnergyLookupTable[between_low].voltage_mV,
227  bc_stateOfEnergyLookupTable[between_low].value,
228  (float)bc_stateOfEnergyLookupTable[between_high].voltage_mV,
229  bc_stateOfEnergyLookupTable[between_high].value,
230  (float)voltage_mV);
231  } else if ((between_low >= bc_stateOfEnergyLookupTableLength)) {
232  /* LUT SOE values are in descending order: cell voltage < minimum LUT voltage */
233  soe_perc = MINIMUM_SOE_PERC;
234  } else {
235  /* cell voltage > maximum LUT voltage */
236  soe_perc = MAXIMUM_SOE_PERC;
237  }
238  return soe_perc;
239 }
240 
241 static void SOE_SetValue(
242  DATA_BLOCK_SOX_s *pSoeValues,
243  float soeMinimumValue_perc,
244  float soeMaximumValue_perc,
245  float soeAverageValue_perc,
246  uint8_t stringNumber) {
247  FAS_ASSERT(pSoeValues != NULL_PTR);
248 
249  /* Update FRAM value */
250  fram_soe.averageSoe_perc[stringNumber] = soeAverageValue_perc;
251  fram_soe.minimumSoe_perc[stringNumber] = soeMinimumValue_perc;
252  fram_soe.maximumSoe_perc[stringNumber] = soeMaximumValue_perc;
253 
254  /* Update database values */
255  pSoeValues->averageSoe_perc[stringNumber] = soeAverageValue_perc;
256  pSoeValues->minimumSoe_perc[stringNumber] = soeMinimumValue_perc;
257  pSoeValues->maximumSoe_perc[stringNumber] = soeMaximumValue_perc;
258 
259  pSoeValues->maximumSoe_Wh[stringNumber] = SOE_GetStringEnergyFromSoePercentage(soeMaximumValue_perc);
260  pSoeValues->averageSoe_Wh[stringNumber] = SOE_GetStringEnergyFromSoePercentage(soeAverageValue_perc);
261  pSoeValues->minimumSoe_Wh[stringNumber] = SOE_GetStringEnergyFromSoePercentage(soeMinimumValue_perc);
262 
263  /* Calculate scaling values depending on EC counting value and current SOE */
264  if (soe_state.sensorEcUsed[stringNumber] == true) {
266 
267  float ecOffset =
269 
270  if (soe_tableCurrentSensor.energyCounter_Wh[stringNumber] < 0) {
271  ecOffset *= (-1.0f);
272  }
273 
274 #if POSITIVE_DISCHARGE_CURRENT == false
275  ecOffset *= (-1.0f); /* negate calculated delta SOE in perc */
276 
277 #endif /* POSITIVE_DISCHARGE_CURRENT == false */
278 
279  soe_state.ecScalingAverage[stringNumber] = fram_soe.averageSoe_perc[stringNumber] + ecOffset;
280  soe_state.ecScalingMinimum[stringNumber] = fram_soe.minimumSoe_perc[stringNumber] + ecOffset;
281  soe_state.ecScalingMaximum[stringNumber] = fram_soe.maximumSoe_perc[stringNumber] + ecOffset;
282  }
283 }
284 
285 static void SOE_CheckDatabaseSoePercentageLimits(DATA_BLOCK_SOX_s *pTableSoe, uint8_t stringNumber) {
286  FAS_ASSERT(pTableSoe != NULL_PTR);
287  FAS_ASSERT(stringNumber < BS_NR_OF_STRINGS);
288 
289  if (pTableSoe->averageSoe_perc[stringNumber] > MAXIMUM_SOE_PERC) {
290  pTableSoe->averageSoe_perc[stringNumber] = MAXIMUM_SOE_PERC;
291  }
292  if (pTableSoe->averageSoe_perc[stringNumber] < MINIMUM_SOE_PERC) {
293  pTableSoe->averageSoe_perc[stringNumber] = MINIMUM_SOE_PERC;
294  }
295  if (pTableSoe->minimumSoe_perc[stringNumber] > MAXIMUM_SOE_PERC) {
296  pTableSoe->minimumSoe_perc[stringNumber] = MAXIMUM_SOE_PERC;
297  }
298  if (pTableSoe->minimumSoe_perc[stringNumber] < MINIMUM_SOE_PERC) {
299  pTableSoe->minimumSoe_perc[stringNumber] = MINIMUM_SOE_PERC;
300  }
301  if (pTableSoe->maximumSoe_perc[stringNumber] > MAXIMUM_SOE_PERC) {
302  pTableSoe->maximumSoe_perc[stringNumber] = MAXIMUM_SOE_PERC;
303  }
304  if (pTableSoe->maximumSoe_perc[stringNumber] < MINIMUM_SOE_PERC) {
305  pTableSoe->maximumSoe_perc[stringNumber] = MINIMUM_SOE_PERC;
306  }
307 }
308 
309 /*========== Extern Function Implementations ================================*/
310 
311 extern void SOE_Init(DATA_BLOCK_SOX_s *pSoeValues, bool ec_present, uint8_t stringNumber) {
312  FAS_ASSERT(pSoeValues != NULL_PTR);
313  FAS_ASSERT(stringNumber < BS_NR_OF_STRINGS);
315 
316  pSoeValues->averageSoe_perc[stringNumber] = fram_soe.averageSoe_perc[stringNumber];
317  pSoeValues->minimumSoe_perc[stringNumber] = fram_soe.minimumSoe_perc[stringNumber];
318  pSoeValues->maximumSoe_perc[stringNumber] = fram_soe.maximumSoe_perc[stringNumber];
319 
320  /* Limit SOE values [0.0f, 100.0f] */
321  SOE_CheckDatabaseSoePercentageLimits(pSoeValues, stringNumber);
322 
323  /* Calculate string energy in Wh */
324  pSoeValues->maximumSoe_Wh[stringNumber] =
325  SOE_GetStringEnergyFromSoePercentage(pSoeValues->maximumSoe_perc[stringNumber]);
326  pSoeValues->minimumSoe_Wh[stringNumber] =
327  SOE_GetStringEnergyFromSoePercentage(pSoeValues->minimumSoe_perc[stringNumber]);
328  pSoeValues->averageSoe_Wh[stringNumber] =
329  SOE_GetStringEnergyFromSoePercentage(pSoeValues->averageSoe_perc[stringNumber]);
330 
331  if (true == ec_present) {
333  soe_state.sensorEcUsed[stringNumber] = true;
334 
335  /* Set scaling values */
336  float ecOffset =
338 
339  if (soe_tableCurrentSensor.energyCounter_Wh[stringNumber] < 0) {
340  ecOffset *= (-1.0f);
341  }
342 
343 #if POSITIVE_DISCHARGE_CURRENT == false
344  ecOffset *= (-1.0f); /* negate calculated delta SOE in perc */
345 
346 #endif /* POSITIVE_DISCHARGE_CURRENT == false */
347 
348  soe_state.ecScalingMinimum[stringNumber] = fram_soe.minimumSoe_perc[stringNumber] + ecOffset;
349  soe_state.ecScalingMaximum[stringNumber] = fram_soe.maximumSoe_perc[stringNumber] + ecOffset;
350  soe_state.ecScalingAverage[stringNumber] = fram_soe.averageSoe_perc[stringNumber] + ecOffset;
351  }
352  soe_state.soeInitialized = true;
353 }
354 
356  FAS_ASSERT(pSoeValues != NULL_PTR);
357  bool continueFunction = true;
358  if (false == soe_state.soeInitialized) {
359  /* Exit if SOE not initialized yet */
360  continueFunction = false;
361  }
362 
363  if (true == continueFunction) {
364  /* Use energy counting/integrate */
366 
368  /* Recalibrate SOE via LUT */
369  SOE_RecalibrateViaLookupTable(pSoeValues);
370  } else {
371  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
372  if (false == soe_state.sensorEcUsed[stringNumber]) {
373  /* no energy counting activated -> manually integrate energy */
374  uint32_t timestamp = soe_tableCurrentSensor.timestampCurrent[stringNumber];
375  uint32_t previous_timestamp = soe_tableCurrentSensor.previousTimestampCurrent[stringNumber];
376 
377  /* check if current measurement has been updated */
378  if (soe_state.previousTimestamp[stringNumber] != timestamp) {
379  float timestep_s = (((float)timestamp - (float)previous_timestamp)) / 1000.0f;
380  if (timestep_s > 0.0f) {
381  /* Current in charge direction negative means SOE increasing --> BAT naming, not ROB */
382  float deltaSOE_Wh = ((((float)soe_tableCurrentSensor.current_mA[stringNumber] /
383  1000.0f) * /* convert to A */
384  ((float)soe_tableCurrentSensor.highVoltage_mV[stringNumber][0] /
385  1000.0f)) / /* convert to V */
386  timestep_s) / /* unit: s */
387  3600.0f; /* convert Ws -> Wh */
388 
389 #if POSITIVE_DISCHARGE_CURRENT == false
390  /* negate calculated delta SOE_Wh */
391  deltaSOE_Wh *= (-1.0f);
392 #endif /* POSITIVE_DISCHARGE_CURRENT == false */
393 
394  pSoeValues->averageSoe_Wh[stringNumber] -= (uint32_t)deltaSOE_Wh;
395  pSoeValues->minimumSoe_Wh[stringNumber] -= (uint32_t)deltaSOE_Wh;
396  pSoeValues->maximumSoe_Wh[stringNumber] -= (uint32_t)deltaSOE_Wh;
397 
398  pSoeValues->averageSoe_perc[stringNumber] =
399  SOE_GetStringSoePercentageFromEnergy(pSoeValues->averageSoe_Wh[stringNumber]);
400  pSoeValues->minimumSoe_perc[stringNumber] =
401  SOE_GetStringSoePercentageFromEnergy(pSoeValues->minimumSoe_Wh[stringNumber]);
402  pSoeValues->maximumSoe_perc[stringNumber] =
403  SOE_GetStringSoePercentageFromEnergy(pSoeValues->maximumSoe_Wh[stringNumber]);
404 
405  /* update timestamp SOE state variable for next iteration */
406  soe_state.previousTimestamp[stringNumber] = timestamp;
407  }
408  } /* end check if current measurement has been updated */
409  } else {
410  /* check if ec measurement has been updated */
411  if (soe_state.previousTimestamp[stringNumber] !=
413  /* Calculate SOE value with current sensor EC value */
414  float deltaSoe_perc =
417 
418 #if POSITIVE_DISCHARGE_CURRENT == false
419  /* negate calculated delta SOE_perc */
420  deltaSoe_perc *= (-1.0f);
421 #endif
422  /* Apply EC scaling offset to get actual string energy */
423  pSoeValues->averageSoe_perc[stringNumber] = soe_state.ecScalingAverage[stringNumber] -
424  deltaSoe_perc;
425  pSoeValues->minimumSoe_perc[stringNumber] = soe_state.ecScalingMinimum[stringNumber] -
426  deltaSoe_perc;
427  pSoeValues->maximumSoe_perc[stringNumber] = soe_state.ecScalingMaximum[stringNumber] -
428  deltaSoe_perc;
429 
430  /* Limit SOE values to [0.0, 100.0] */
431  SOE_CheckDatabaseSoePercentageLimits(pSoeValues, stringNumber);
432 
433  /* Calculate new Wh values */
434  pSoeValues->maximumSoe_Wh[stringNumber] =
435  SOE_GetStringEnergyFromSoePercentage(pSoeValues->maximumSoe_perc[stringNumber]);
436  pSoeValues->averageSoe_Wh[stringNumber] =
437  SOE_GetStringEnergyFromSoePercentage(pSoeValues->averageSoe_perc[stringNumber]);
438  pSoeValues->minimumSoe_Wh[stringNumber] =
439  SOE_GetStringEnergyFromSoePercentage(pSoeValues->minimumSoe_perc[stringNumber]);
440 
441  /* Update timestamp for next iteration */
442  soe_state.previousTimestamp[stringNumber] =
444  }
445  }
446 
447  fram_soe.averageSoe_perc[stringNumber] = pSoeValues->averageSoe_perc[stringNumber];
448  fram_soe.minimumSoe_perc[stringNumber] = pSoeValues->minimumSoe_perc[stringNumber];
449  fram_soe.maximumSoe_perc[stringNumber] = pSoeValues->maximumSoe_perc[stringNumber];
450  }
451 
452  /* Update database and FRAM value */
454  }
455  }
456 }
457 
458 /*========== Externalized Static Function Implementations (Unit Test) =======*/
uint16_t bc_stateOfEnergyLookupTableLength
const BC_LUT_s bc_stateOfEnergyLookupTable[]
Configuration of the battery cell (e.g., minimum and maximum cell voltage)
Configuration of the battery system (e.g., number of battery modules, battery cells,...
#define BS_NR_OF_STRINGS
BMS_CURRENT_FLOW_STATE_e BMS_GetBatterySystemState(void)
Returns current battery system state (charging/discharging, resting or in relaxation phase)
Definition: bms.c:1272
bms driver header
@ BMS_AT_REST
Definition: bms.h:69
Database module header.
#define DATA_READ_DATA(...)
Definition: database.h:76
@ DATA_BLOCK_ID_MIN_MAX
Definition: database_cfg.h:75
@ DATA_BLOCK_ID_CURRENT_SENSOR
Definition: database_cfg.h:76
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:237
float MATH_linearInterpolation(float x1, float y1, float x2, float y2, float x_interpolate)
Linear inter-/extrapolates a third point according to two given points.
Definition: foxmath.c:69
math library for often used math functions
#define UNIT_CONVERSION_FACTOR_100_FLOAT
Definition: foxmath.h:74
STD_RETURN_TYPE_e FRAM_Read(FRAM_BLOCK_ID_e blockId)
Reads a variable from the FRAM.
Definition: fram.c:160
STD_RETURN_TYPE_e FRAM_Write(FRAM_BLOCK_ID_e blockId)
Writes a variable to the FRAM.
Definition: fram.c:101
Header for the driver for the FRAM module.
FRAM_SOE_s fram_soe
Definition: fram_cfg.c:71
@ FRAM_BLOCK_ID_SOE
Definition: fram_cfg.h:92
#define NULL_PTR
Null pointer.
Definition: fstd_types.h:66
#define STRIP(x)
Definition: general.h:268
#define REPEAT_U(x, n)
Macro that helps to generate a series of literals (for array initializers).
Definition: general.h:256
#define MINIMUM_SOE_PERC
Definition: soe_counting.c:82
#define MAXIMUM_SOE_PERC
Definition: soe_counting.c:81
static void SOE_RecalibrateViaLookupTable(DATA_BLOCK_SOX_s *pSoeValues)
initializes database and FRAM SOE values via lookup table (average, min and max).
Definition: soe_counting.c:191
static float SOE_GetFromVoltage(int16_t voltage_mV)
look-up table for SOE initialization
Definition: soe_counting.c:208
void SOE_Init(DATA_BLOCK_SOX_s *pSoeValues, bool ec_present, uint8_t stringNumber)
initializes startup state-of-energy (SOE) related values
Definition: soe_counting.c:311
struct SOE_STATE SOE_STATE_s
static DATA_BLOCK_CURRENT_SENSOR_s soe_tableCurrentSensor
Definition: soe_counting.c:100
static SOE_STATE_s soe_state
Definition: soe_counting.c:89
static uint32_t SOE_GetStringEnergyFromSoePercentage(float stringSoe_perc)
calculates string energy in Wh from passed SOE in percentage
Definition: soe_counting.c:179
static void SOE_SetValue(DATA_BLOCK_SOX_s *pSoeValues, float soeMinimumValue_perc, float soeMaximumValue_perc, float soeAverageValue_perc, uint8_t stringNumber)
sets SOE value with a parameter between 0.0 and 100.0.
Definition: soe_counting.c:241
void SOE_Calculation(DATA_BLOCK_SOX_s *pSoeValues)
periodically called algorithm to calculate state-of-energy (SOE)
Definition: soe_counting.c:355
static float SOE_GetStringSoePercentageFromEnergy(uint32_t energy_Wh)
calculates string SOE in percentage from passed string energy in Wh
Definition: soe_counting.c:168
static void SOE_CheckDatabaseSoePercentageLimits(DATA_BLOCK_SOX_s *pTableSoe, uint8_t stringNumber)
Check if all database SOE percentage values are within [0.0, 100.0] Limits SOE values to limit values...
Definition: soe_counting.c:285
Header for SOE module, responsible for calculation of SOE.
Header for SOE configuration.
#define SOE_STRING_ENERGY_Wh
DATA_BLOCK_ID_e uniqueId
Definition: database_cfg.h:110
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:215
uint32_t timestampCurrent[BS_NR_OF_STRINGS]
Definition: database_cfg.h:220
int32_t current_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:216
uint32_t timestampEnergyCounting[BS_NR_OF_STRINGS]
Definition: database_cfg.h:235
int32_t highVoltage_mV[BS_NR_OF_STRINGS][BS_NR_OF_VOLTAGES_FROM_CURRENT_SENSOR]
Definition: database_cfg.h:238
int32_t energyCounter_Wh[BS_NR_OF_STRINGS]
Definition: database_cfg.h:232
uint32_t previousTimestampCurrent[BS_NR_OF_STRINGS]
Definition: database_cfg.h:219
int16_t maximumCellVoltage_mV[BS_NR_OF_STRINGS]
Definition: database_cfg.h:168
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:163
int16_t averageCellVoltage_mV[BS_NR_OF_STRINGS]
Definition: database_cfg.h:165
int16_t minimumCellVoltage_mV[BS_NR_OF_STRINGS]
Definition: database_cfg.h:166
float maximumSoe_perc[BS_NR_OF_STRINGS]
Definition: database_cfg.h:499
uint32_t averageSoe_Wh[BS_NR_OF_STRINGS]
Definition: database_cfg.h:501
uint32_t maximumSoe_Wh[BS_NR_OF_STRINGS]
Definition: database_cfg.h:500
float minimumSoe_perc[BS_NR_OF_STRINGS]
Definition: database_cfg.h:498
uint32_t minimumSoe_Wh[BS_NR_OF_STRINGS]
Definition: database_cfg.h:502
float averageSoe_perc[BS_NR_OF_STRINGS]
Definition: database_cfg.h:497
float maximumSoe_perc[BS_NR_OF_STRINGS]
Definition: fram_cfg.h:132
float averageSoe_perc[BS_NR_OF_STRINGS]
Definition: fram_cfg.h:133
float minimumSoe_perc[BS_NR_OF_STRINGS]
Definition: fram_cfg.h:131
float ecScalingAverage[BS_NR_OF_STRINGS]
Definition: soe_counting.c:73
float ecScalingMaximum[BS_NR_OF_STRINGS]
Definition: soe_counting.c:75
bool sensorEcUsed[BS_NR_OF_STRINGS]
Definition: soe_counting.c:72
bool soeInitialized
Definition: soe_counting.c:71
float ecScalingMinimum[BS_NR_OF_STRINGS]
Definition: soe_counting.c:74
uint32_t previousTimestamp[BS_NR_OF_STRINGS]
Definition: soe_counting.c:77