foxBMS  1.4.1
The foxBMS Battery Management System API Documentation
moving_average.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2022, 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 moving_average.c
44  * @author foxBMS Team
45  * @date 2017-12-18 (date of creation)
46  * @updated 2022-10-27 (date of last update)
47  * @version v1.4.1
48  * @ingroup ALGORITHMS
49  * @prefix ALGO
50  *
51  * @brief moving average algorithm
52  *
53  */
54 
55 /*========== Includes =======================================================*/
56 #include "moving_average.h"
57 
58 #include "algorithm_cfg.h"
59 
60 #include "database.h"
61 
62 /*========== Macros and Definitions =========================================*/
63 /** TODO */
64 #define MEM_EXT_SDRAM
65 
66 #if ALGO_TICK_ms > ISA_CURRENT_CYCLE_TIME_ms
67 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_1s ((1000u) / ALGO_TICK_ms)
68 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_5s ((5000u) / ALGO_TICK_ms)
69 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_10s ((10000u) / ALGO_TICK_ms)
70 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_30s ((30000u) / ALGO_TICK_ms)
71 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_60s ((60000u) / ALGO_TICK_ms)
72 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_CFG (MOVING_AVERAGE_DURATION_CURRENT_CONFIG_ms / ALGO_TICK_ms)
73 #else
74 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_1s ((1000u) / ISA_CURRENT_CYCLE_TIME_ms)
75 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_5s ((5000u) / ISA_CURRENT_CYCLE_TIME_ms)
76 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_10s ((10000u) / ISA_CURRENT_CYCLE_TIME_ms)
77 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_30s ((30000u) / ISA_CURRENT_CYCLE_TIME_ms)
78 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_60s ((60000u) / ISA_CURRENT_CYCLE_TIME_ms)
79 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_CFG (MOVING_AVERAGE_DURATION_CURRENT_CONFIG_ms / ISA_CURRENT_CYCLE_TIME_ms)
80 #endif
81 
82 #if ALGO_TICK_ms > ISA_POWER_CYCLE_TIME_ms
83 #define ALGO_NUMBER_AVERAGE_VALUES_POW_1s ((1000u) / ALGO_TICK_ms)
84 #define ALGO_NUMBER_AVERAGE_VALUES_POW_5s ((5000u) / ALGO_TICK_ms)
85 #define ALGO_NUMBER_AVERAGE_VALUES_POW_10s ((10000u) / ALGO_TICK_ms)
86 #define ALGO_NUMBER_AVERAGE_VALUES_POW_30s ((30000u) / ALGO_TICK_ms)
87 #define ALGO_NUMBER_AVERAGE_VALUES_POW_60s ((60000u) / ALGO_TICK_ms)
88 #define ALGO_NUMBER_AVERAGE_VALUES_POW_CFG (MOVING_AVERAGE_DURATION_POWER_CONFIG_ms / ALGO_TICK_ms)
89 #else
90 #define ALGO_NUMBER_AVERAGE_VALUES_POW_1s ((1000u) / ISA_POWER_CYCLE_TIME_ms)
91 #define ALGO_NUMBER_AVERAGE_VALUES_POW_5s ((5000u) / ISA_POWER_CYCLE_TIME_ms)
92 #define ALGO_NUMBER_AVERAGE_VALUES_POW_10s ((10000u) / ISA_POWER_CYCLE_TIME_ms)
93 #define ALGO_NUMBER_AVERAGE_VALUES_POW_30s ((30000u) / ISA_POWER_CYCLE_TIME_ms)
94 #define ALGO_NUMBER_AVERAGE_VALUES_POW_60s ((60000u) / ISA_POWER_CYCLE_TIME_ms)
95 #define ALGO_NUMBER_AVERAGE_VALUES_POW_CFG (MOVING_AVERAGE_DURATION_POWER_CONFIG_ms / ISA_POWER_CYCLE_TIME_ms)
96 #endif
97 
98 /*========== Static Constant and Variable Definitions =======================*/
99 
100 /* Arrays in extern SDRAM to calculate moving average current and power */
101 
102 /* Check if minimum algo cycle time > current sensor sample time */
103 #if ALGO_TICK_ms > ISA_CURRENT_CYCLE_TIME_ms
104 #if MOVING_AVERAGE_DURATION_CURRENT_CONFIG_ms / ALGO_TICK_ms > 60000u / ALGO_TICK_ms
105 /* If array length of configured time > 60s array take this array size */
108 #else
109 /* Take array size of 60s moving average */
110 static float MEM_EXT_SDRAM curValues[(60000u / ALGO_TICK_ms) + 1u] = {};
111 static uint32_t movingAverageCurrentLength = (60000u / ALGO_TICK_ms) + 1;
112 #endif
113 #else
114 /* If array length of configured time > 60s array take this array size */
115 #if (MOVING_AVERAGE_DURATION_CURRENT_CONFIG_ms / ISA_CURRENT_CYCLE_TIME_ms) > (60000u / ISA_CURRENT_CYCLE_TIME_ms)
118  1u;
119 #else
120 /* Take array size of 60s moving average */
121 static float MEM_EXT_SDRAM curValues[(60000u / ISA_CURRENT_CYCLE_TIME_ms) + 1u] = {0.0f};
122 static uint32_t movingAverageCurrentLength = (60000u / ISA_CURRENT_CYCLE_TIME_ms) + 1u;
123 #endif
124 #endif
125 
126 /* Check if minimum algo cycle time > current sensor sample time */
127 #if ALGO_TICK_ms > ISA_POWER_CYCLE_TIME_ms
128 #if (MOVING_AVERAGE_DURATION_POWER_CONFIG_ms / ALGO_TICK_ms) > (60000u / ALGO_TICK_ms)
129 /* If array length of configured time > 60s array take this array size */
132 #else
133 /* Take array size of 60s moving average */
134 static float MEM_EXT_SDRAM powValues[(60000u / ALGO_TICK_ms) + 1] = {};
135 static uint32_t movingAveragePowerLength = (60000u / ALGO_TICK_ms) + 1u;
136 #endif
137 #else
138 #if (MOVING_AVERAGE_DURATION_POWER_CONFIG_ms / ISA_POWER_CYCLE_TIME_ms) > (60000u / ISA_POWER_CYCLE_TIME_ms)
139 /* If array length of configured time > 60s array take this array size */
142 #else
143 /* Take array size of 60s moving average */
144 static float MEM_EXT_SDRAM powValues[(60000u / ISA_POWER_CYCLE_TIME_ms) + 1u] = {0.0f};
145 static uint32_t movingAveragePowerLength = (60000u / ISA_POWER_CYCLE_TIME_ms) + 1u;
146 #endif
147 #endif
148 
149 /** Pointer for current moving average calculation @{*/
157 /**@}*/
158 
159 /** Pointer for power moving average calculation @{*/
160 static float *pMovingAveragePowerNew = &powValues[0];
161 static float *pMovingAveragePower_1s = &powValues[0];
162 static float *pMovingAveragePower_5s = &powValues[0];
163 static float *pMovingAveragePower_10s = &powValues[0];
164 static float *pMovingAveragePower_30s = &powValues[0];
165 static float *pMovingAveragePower_60s = &powValues[0];
166 static float *pMovingAveragePower_cfg = &powValues[0];
167 /**@}*/
168 
169 /*========== Extern Constant and Variable Definitions =======================*/
170 
171 /*========== Static Function Prototypes =====================================*/
172 
173 /*========== Static Function Implementations ================================*/
174 
175 /*========== Extern Function Implementations ================================*/
176 extern void ALGO_MovAverage(void) {
177  static uint8_t curCounter = 0u;
178  static uint8_t powCounter = 0u;
181  static uint8_t curInit = 0u; /* bit0: 1s, bit1: 5s, bit2: 10s, bit3: 30s, bit4: 60s, bit5: cfg */
182  static uint8_t powInit = 0u; /* bit0: 1s, bit1: 5s, bit2: 10s, bit3: 30s, bit4: 60s, bit5: cfg */
183  static uint8_t newValues = 0u;
184  float divider = 0.0f;
185  bool validValues = true;
186 
187  DATA_READ_DATA(&curPow_tab);
188  DATA_READ_DATA(&movingAverage_tab);
189 
190  /* Check if new current value */
191  if (curCounter != curPow_tab.newCurrent) {
192  curCounter = curPow_tab.newCurrent;
193 
194  /* Check if valid values */
195  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
196  if (curPow_tab.invalidCurrentMeasurement[s] != 0u) {
197  validValues = false;
198  }
199  }
200 
201  if (validValues == true) {
202  /* new Values -> Save later in database */
203  newValues = 1u;
204 
205  int32_t packCurrent = 0;
206  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
207  packCurrent += curPow_tab.current_mA[s];
208  }
209 
210  /* Add value to array and calculate new moving average values */
211  *pMovingAverageCurrentNew = packCurrent;
212 
213  /* Calculate new moving average - first add new value */
215  movingAverage_tab.movingAverageCurrent1sInterval_mA += (*pMovingAverageCurrentNew) / divider;
217  movingAverage_tab.movingAverageCurrent5sInterval_mA += (*pMovingAverageCurrentNew) / divider;
219  movingAverage_tab.movingAverageCurrent10sInterval_mA += (*pMovingAverageCurrentNew) / divider;
221  movingAverage_tab.movingAverageCurrent30sInterval_mA += (*pMovingAverageCurrentNew) / divider;
223  movingAverage_tab.movingAverageCurrent60sInterval_mA += (*pMovingAverageCurrentNew) / divider;
225  movingAverage_tab.movingAverageCurrentConfigurableInterval_mA += (*pMovingAverageCurrentNew) / divider;
226 
227  /* Then, increment pointer and subtract oldest value when respective window is filled with data */
229  if ((curInit & 0x01u) == 0x01u) {
231  movingAverage_tab.movingAverageCurrent1sInterval_mA -= ((*pMovingAverageCurrent_1s) / divider);
233  } else {
235  curInit |= 0x01u;
236  }
237  }
238  if ((curInit & 0x02u) == 0x02u) {
240  movingAverage_tab.movingAverageCurrent5sInterval_mA -= (*pMovingAverageCurrent_5s) / divider;
242  } else {
244  curInit |= 0x02u;
245  }
246  }
247  if ((curInit & 0x04u) == 0x04u) {
249  movingAverage_tab.movingAverageCurrent10sInterval_mA -= (*pMovingAverageCurrent_10s) / divider;
251  } else {
253  curInit |= 0x04u;
254  }
255  }
256  if ((curInit & 0x08u) == 0x08u) {
258  movingAverage_tab.movingAverageCurrent30sInterval_mA -= (*pMovingAverageCurrent_30s) / divider;
260  } else {
262  curInit |= 0x08u;
263  }
264  }
265  if ((curInit & 0x10u) == 0x10u) {
267  movingAverage_tab.movingAverageCurrent60sInterval_mA -= (*pMovingAverageCurrent_60s) / divider;
269  } else {
271  curInit |= 0x10u;
272  }
273  }
274  if ((curInit & 0x20u) == 0x20u) {
276  movingAverage_tab.movingAverageCurrentConfigurableInterval_mA -= (*pMovingAverageCurrent_cfg) / divider;
278  } else {
280  curInit |= 0x20u;
281  }
282  }
283 
284  /* Check pointer for buffer overflow */
287  }
290  }
293  }
296  }
299  }
302  }
305  }
306  }
307  }
308 
309  validValues = true;
310 
311  /* Check if new power value */
312  if (powCounter != curPow_tab.newPower) {
313  powCounter = curPow_tab.newPower;
314 
315  /* Check if valid values */
316  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
317  if (curPow_tab.invalidPowerMeasurement[s] != 0u) {
318  validValues = false;
319  }
320  }
321  if (validValues == true) {
322  newValues = 1u;
323 
324  int32_t packPower = 0;
325  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
326  packPower += curPow_tab.power_W[s];
327  }
328 
329  /* Add value to array and calculate new moving mean values */
330  *pMovingAveragePowerNew = packPower;
331 
332  /* Calculate new moving means - first add new value */
334  movingAverage_tab.movingAveragePower1sInterval_mA += (*pMovingAveragePowerNew) / divider;
336  movingAverage_tab.movingAveragePower5sInterval_mA += (*pMovingAveragePowerNew) / divider;
338  movingAverage_tab.movingAveragePower10sInterval_mA += (*pMovingAveragePowerNew) / divider;
340  movingAverage_tab.movingAveragePower30sInterval_mA += (*pMovingAveragePowerNew) / divider;
342  movingAverage_tab.movingAveragePower60sInterval_mA += (*pMovingAveragePowerNew) / divider;
344  movingAverage_tab.movingAveragePowerConfigurableInterval_mA += (*pMovingAveragePowerNew) / divider;
345 
346  /* Then, increment pointer and subtract oldest value when respective window is filled with data */
348  if ((powInit & 0x01u) == 0x01u) {
350  movingAverage_tab.movingAveragePower1sInterval_mA -= ((*pMovingAveragePower_1s) / divider);
352  } else {
354  powInit |= 0x01u;
355  }
356  }
357  if ((powInit & 0x02u) == 0x02u) {
359  movingAverage_tab.movingAveragePower5sInterval_mA -= ((*pMovingAveragePower_5s) / divider);
361  } else {
363  powInit |= 0x02u;
364  }
365  }
366  if ((powInit & 0x04u) == 0x04u) {
368  movingAverage_tab.movingAveragePower10sInterval_mA -= ((*pMovingAveragePower_10s) / divider);
370  } else {
372  powInit |= 0x04u;
373  }
374  }
375  if ((powInit & 0x08u) == 0x08u) {
377  movingAverage_tab.movingAveragePower30sInterval_mA -= ((*pMovingAveragePower_30s) / divider);
379  } else {
381  powInit |= 0x08u;
382  }
383  }
384  if ((powInit & 0x10u) == 0x10u) {
386  movingAverage_tab.movingAveragePower60sInterval_mA -= ((*pMovingAveragePower_60s) / divider);
388  } else {
390  powInit |= 0x10u;
391  }
392  }
393  if ((powInit & 0x20u) == 0x20u) {
395  movingAverage_tab.movingAveragePowerConfigurableInterval_mA -= ((*pMovingAveragePower_cfg) / divider);
397  } else {
399  powInit |= 0x20u;
400  }
401  }
402 
403  /* Check pointer for buffer overflow */
406  }
409  }
412  }
415  }
418  }
421  }
424  }
425  }
426  }
427 
428  if (newValues == 1u) {
429  newValues = 0;
430 
431  DATA_WRITE_DATA(&movingAverage_tab);
432  }
433 }
434 
435 /*========== Externalized Static Function Implementations (Unit Test) =======*/
Headers for the configuration of the algorithm module.
#define BS_NR_OF_STRINGS
Number of parallel strings in the battery pack.
Database module header.
#define DATA_READ_DATA(...)
Definition: database.h:83
#define DATA_WRITE_DATA(...)
Definition: database.h:93
@ DATA_BLOCK_ID_MOVING_AVERAGE
Definition: database_cfg.h:96
@ DATA_BLOCK_ID_CURRENT_SENSOR
Definition: database_cfg.h:79
#define ALGO_TICK_ms
Definition: algorithm_cfg.h:67
#define ALGO_NUMBER_AVERAGE_VALUES_CUR_5s
#define ALGO_NUMBER_AVERAGE_VALUES_CUR_60s
#define ALGO_NUMBER_AVERAGE_VALUES_CUR_CFG
#define MEM_EXT_SDRAM
static float * pMovingAveragePower_10s
static float MEM_EXT_SDRAM powValues[(60000u/ISA_POWER_CYCLE_TIME_ms)+1u]
static float * pMovingAverageCurrent_10s
#define ALGO_NUMBER_AVERAGE_VALUES_CUR_10s
static float * pMovingAveragePower_1s
static float * pMovingAverageCurrent_5s
#define ALGO_NUMBER_AVERAGE_VALUES_POW_60s
#define ALGO_NUMBER_AVERAGE_VALUES_CUR_1s
static float * pMovingAverageCurrent_1s
#define ALGO_NUMBER_AVERAGE_VALUES_POW_CFG
static float * pMovingAveragePower_5s
#define ALGO_NUMBER_AVERAGE_VALUES_CUR_30s
static float MEM_EXT_SDRAM curValues[(60000u/ISA_CURRENT_CYCLE_TIME_ms)+1u]
static float * pMovingAverageCurrentNew
#define ALGO_NUMBER_AVERAGE_VALUES_POW_10s
static float * pMovingAveragePower_cfg
#define ALGO_NUMBER_AVERAGE_VALUES_POW_5s
static float * pMovingAveragePower_30s
static uint32_t movingAveragePowerLength
#define ALGO_NUMBER_AVERAGE_VALUES_POW_30s
static float * pMovingAveragePower_60s
static float * pMovingAveragePowerNew
static float * pMovingAverageCurrent_30s
static float * pMovingAverageCurrent_cfg
static uint32_t movingAverageCurrentLength
static float * pMovingAverageCurrent_60s
void ALGO_MovAverage(void)
#define ALGO_NUMBER_AVERAGE_VALUES_POW_1s
moving average algorithm
#define MOVING_AVERAGE_DURATION_POWER_CONFIG_ms
#define MOVING_AVERAGE_DURATION_CURRENT_CONFIG_ms
#define ISA_CURRENT_CYCLE_TIME_ms
#define ISA_POWER_CYCLE_TIME_ms
int32_t current_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:212
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:211
uint8_t invalidCurrentMeasurement[BS_NR_OF_STRINGS]
Definition: database_cfg.h:213
int32_t power_W[BS_NR_OF_STRINGS]
Definition: database_cfg.h:219
uint8_t invalidPowerMeasurement[BS_NR_OF_STRINGS]
Definition: database_cfg.h:220
DATA_BLOCK_ID_e uniqueId
Definition: database_cfg.h:119
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:534
float movingAverageCurrentConfigurableInterval_mA
Definition: database_cfg.h:540
float movingAveragePowerConfigurableInterval_mA
Definition: database_cfg.h:546