foxBMS  1.6.0
The foxBMS Battery Management System API Documentation
moving_average.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2023, 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 2023-10-12 (date of last update)
47  * @version v1.6.0
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 #include "fstd_types.h"
62 
63 #include <math.h>
64 #include <stdbool.h>
65 #include <stdint.h>
66 
67 /*========== Macros and Definitions =========================================*/
68 /** TODO */
69 #define MEM_EXT_SDRAM
70 
71 #if ALGO_TICK_ms > ISA_CURRENT_CYCLE_TIME_ms
72 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_1s ((1000u) / ALGO_TICK_ms)
73 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_5s ((5000u) / ALGO_TICK_ms)
74 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_10s ((10000u) / ALGO_TICK_ms)
75 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_30s ((30000u) / ALGO_TICK_ms)
76 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_60s ((60000u) / ALGO_TICK_ms)
77 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_CFG (MOVING_AVERAGE_DURATION_CURRENT_CONFIG_ms / ALGO_TICK_ms)
78 #else
79 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_1s ((1000u) / ISA_CURRENT_CYCLE_TIME_ms)
80 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_5s ((5000u) / ISA_CURRENT_CYCLE_TIME_ms)
81 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_10s ((10000u) / ISA_CURRENT_CYCLE_TIME_ms)
82 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_30s ((30000u) / ISA_CURRENT_CYCLE_TIME_ms)
83 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_60s ((60000u) / ISA_CURRENT_CYCLE_TIME_ms)
84 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_CFG (MOVING_AVERAGE_DURATION_CURRENT_CONFIG_ms / ISA_CURRENT_CYCLE_TIME_ms)
85 #endif
86 
87 #if ALGO_TICK_ms > ISA_POWER_CYCLE_TIME_ms
88 #define ALGO_NUMBER_AVERAGE_VALUES_POW_1s ((1000u) / ALGO_TICK_ms)
89 #define ALGO_NUMBER_AVERAGE_VALUES_POW_5s ((5000u) / ALGO_TICK_ms)
90 #define ALGO_NUMBER_AVERAGE_VALUES_POW_10s ((10000u) / ALGO_TICK_ms)
91 #define ALGO_NUMBER_AVERAGE_VALUES_POW_30s ((30000u) / ALGO_TICK_ms)
92 #define ALGO_NUMBER_AVERAGE_VALUES_POW_60s ((60000u) / ALGO_TICK_ms)
93 #define ALGO_NUMBER_AVERAGE_VALUES_POW_CFG (MOVING_AVERAGE_DURATION_POWER_CONFIG_ms / ALGO_TICK_ms)
94 #else
95 #define ALGO_NUMBER_AVERAGE_VALUES_POW_1s ((1000u) / ISA_POWER_CYCLE_TIME_ms)
96 #define ALGO_NUMBER_AVERAGE_VALUES_POW_5s ((5000u) / ISA_POWER_CYCLE_TIME_ms)
97 #define ALGO_NUMBER_AVERAGE_VALUES_POW_10s ((10000u) / ISA_POWER_CYCLE_TIME_ms)
98 #define ALGO_NUMBER_AVERAGE_VALUES_POW_30s ((30000u) / ISA_POWER_CYCLE_TIME_ms)
99 #define ALGO_NUMBER_AVERAGE_VALUES_POW_60s ((60000u) / ISA_POWER_CYCLE_TIME_ms)
100 #define ALGO_NUMBER_AVERAGE_VALUES_POW_CFG (MOVING_AVERAGE_DURATION_POWER_CONFIG_ms / ISA_POWER_CYCLE_TIME_ms)
101 #endif
102 
103 /*========== Static Constant and Variable Definitions =======================*/
104 
105 /* Arrays in extern SDRAM to calculate moving average current and power */
106 
107 /* Check if minimum algorithm cycle time > current sensor sample time */
108 #if ALGO_TICK_ms > ISA_CURRENT_CYCLE_TIME_ms
109 #if MOVING_AVERAGE_DURATION_CURRENT_CONFIG_ms / ALGO_TICK_ms > 60000u / ALGO_TICK_ms
110 /* If array length of configured time > 60s array take this array size */
113 #else
114 /* Take array size of 60s moving average */
115 static float_t MEM_EXT_SDRAM curValues[(60000u / ALGO_TICK_ms) + 1u] = {};
116 static uint32_t movingAverageCurrentLength = (60000u / ALGO_TICK_ms) + 1;
117 #endif
118 #else
119 /* If array length of configured time > 60s array take this array size */
120 #if (MOVING_AVERAGE_DURATION_CURRENT_CONFIG_ms / ISA_CURRENT_CYCLE_TIME_ms) > (60000u / ISA_CURRENT_CYCLE_TIME_ms)
121 static float_t MEM_EXT_SDRAM
124  1u;
125 #else
126 /* Take array size of 60s moving average */
127 static float_t MEM_EXT_SDRAM curValues[(60000u / ISA_CURRENT_CYCLE_TIME_ms) + 1u] = {0.0f};
128 static uint32_t movingAverageCurrentLength = (60000u / ISA_CURRENT_CYCLE_TIME_ms) + 1u;
129 #endif
130 #endif
131 
132 /* Check if minimum algorithm cycle time > current sensor sample time */
133 #if ALGO_TICK_ms > ISA_POWER_CYCLE_TIME_ms
134 #if (MOVING_AVERAGE_DURATION_POWER_CONFIG_ms / ALGO_TICK_ms) > (60000u / ALGO_TICK_ms)
135 /* If array length of configured time > 60s array take this array size */
138 #else
139 /* Take array size of 60s moving average */
140 static float_t MEM_EXT_SDRAM powValues[(60000u / ALGO_TICK_ms) + 1] = {};
141 static uint32_t movingAveragePowerLength = (60000u / ALGO_TICK_ms) + 1u;
142 #endif
143 #else
144 #if (MOVING_AVERAGE_DURATION_POWER_CONFIG_ms / ISA_POWER_CYCLE_TIME_ms) > (60000u / ISA_POWER_CYCLE_TIME_ms)
145 /* If array length of configured time > 60s array take this array size */
148 #else
149 /* Take array size of 60s moving average */
150 static float_t MEM_EXT_SDRAM powValues[(60000u / ISA_POWER_CYCLE_TIME_ms) + 1u] = {0.0f};
151 static uint32_t movingAveragePowerLength = (60000u / ISA_POWER_CYCLE_TIME_ms) + 1u;
152 #endif
153 #endif
154 
155 /** Pointer for current moving average calculation @{*/
156 static float_t *pMovingAverageCurrentNew = &curValues[0];
157 static float_t *pMovingAverageCurrent_1s = &curValues[0];
158 static float_t *pMovingAverageCurrent_5s = &curValues[0];
159 static float_t *pMovingAverageCurrent_10s = &curValues[0];
160 static float_t *pMovingAverageCurrent_30s = &curValues[0];
161 static float_t *pMovingAverageCurrent_60s = &curValues[0];
162 static float_t *pMovingAverageCurrent_cfg = &curValues[0];
163 /**@}*/
164 
165 /** Pointer for power moving average calculation @{*/
166 static float_t *pMovingAveragePowerNew = &powValues[0];
167 static float_t *pMovingAveragePower_1s = &powValues[0];
168 static float_t *pMovingAveragePower_5s = &powValues[0];
169 static float_t *pMovingAveragePower_10s = &powValues[0];
170 static float_t *pMovingAveragePower_30s = &powValues[0];
171 static float_t *pMovingAveragePower_60s = &powValues[0];
172 static float_t *pMovingAveragePower_cfg = &powValues[0];
173 /**@}*/
174 
175 /*========== Extern Constant and Variable Definitions =======================*/
176 
177 /*========== Static Function Prototypes =====================================*/
178 
179 /*========== Static Function Implementations ================================*/
180 
181 /*========== Extern Function Implementations ================================*/
182 extern void ALGO_MovAverage(void) {
183  static uint8_t curCounter = 0u;
184  static uint8_t powCounter = 0u;
187  static uint8_t curInit = 0u; /* bit0: 1s, bit1: 5s, bit2: 10s, bit3: 30s, bit4: 60s, bit5: cfg */
188  static uint8_t powInit = 0u; /* bit0: 1s, bit1: 5s, bit2: 10s, bit3: 30s, bit4: 60s, bit5: cfg */
189  static uint8_t newValues = 0u;
190  float_t divider = 0.0f;
191  bool validValues = true;
192 
193  DATA_READ_DATA(&curPow_tab);
194  DATA_READ_DATA(&movingAverage_tab);
195 
196  /* Check if new current value */
197  if (curCounter != curPow_tab.newCurrent) {
198  curCounter = curPow_tab.newCurrent;
199 
200  /* Check if valid values */
201  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
202  if (curPow_tab.invalidCurrentMeasurement[s] != 0u) {
203  validValues = false;
204  }
205  }
206 
207  if (validValues == true) {
208  /* new Values -> Save later in database */
209  newValues = 1u;
210 
211  int32_t packCurrent = 0;
212  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
213  packCurrent += curPow_tab.current_mA[s];
214  }
215 
216  /* Add value to array and calculate new moving average values */
217  *pMovingAverageCurrentNew = packCurrent;
218 
219  /* Calculate new moving average - first add new value */
221  movingAverage_tab.movingAverageCurrent1sInterval_mA += (*pMovingAverageCurrentNew) / divider;
223  movingAverage_tab.movingAverageCurrent5sInterval_mA += (*pMovingAverageCurrentNew) / divider;
225  movingAverage_tab.movingAverageCurrent10sInterval_mA += (*pMovingAverageCurrentNew) / divider;
227  movingAverage_tab.movingAverageCurrent30sInterval_mA += (*pMovingAverageCurrentNew) / divider;
229  movingAverage_tab.movingAverageCurrent60sInterval_mA += (*pMovingAverageCurrentNew) / divider;
231  movingAverage_tab.movingAverageCurrentConfigurableInterval_mA += (*pMovingAverageCurrentNew) / divider;
232 
233  /* Then, increment pointer and subtract oldest value when respective window is filled with data */
235  if ((curInit & 0x01u) == 0x01u) {
237  movingAverage_tab.movingAverageCurrent1sInterval_mA -= ((*pMovingAverageCurrent_1s) / divider);
239  } else {
241  curInit |= 0x01u;
242  }
243  }
244  if ((curInit & 0x02u) == 0x02u) {
246  movingAverage_tab.movingAverageCurrent5sInterval_mA -= (*pMovingAverageCurrent_5s) / divider;
248  } else {
250  curInit |= 0x02u;
251  }
252  }
253  if ((curInit & 0x04u) == 0x04u) {
255  movingAverage_tab.movingAverageCurrent10sInterval_mA -= (*pMovingAverageCurrent_10s) / divider;
257  } else {
259  curInit |= 0x04u;
260  }
261  }
262  if ((curInit & 0x08u) == 0x08u) {
264  movingAverage_tab.movingAverageCurrent30sInterval_mA -= (*pMovingAverageCurrent_30s) / divider;
266  } else {
268  curInit |= 0x08u;
269  }
270  }
271  if ((curInit & 0x10u) == 0x10u) {
273  movingAverage_tab.movingAverageCurrent60sInterval_mA -= (*pMovingAverageCurrent_60s) / divider;
275  } else {
277  curInit |= 0x10u;
278  }
279  }
280  if ((curInit & 0x20u) == 0x20u) {
282  movingAverage_tab.movingAverageCurrentConfigurableInterval_mA -= (*pMovingAverageCurrent_cfg) / divider;
284  } else {
286  curInit |= 0x20u;
287  }
288  }
289 
290  /* Check pointer for buffer overflow */
293  }
296  }
299  }
302  }
305  }
308  }
311  }
312  }
313  }
314 
315  validValues = true;
316 
317  /* Check if new power value */
318  if (powCounter != curPow_tab.newPower) {
319  powCounter = curPow_tab.newPower;
320 
321  /* Check if valid values */
322  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
323  if (curPow_tab.invalidPowerMeasurement[s] != 0u) {
324  validValues = false;
325  }
326  }
327  if (validValues == true) {
328  newValues = 1u;
329 
330  int32_t packPower = 0;
331  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
332  packPower += curPow_tab.power_W[s];
333  }
334 
335  /* Add value to array and calculate new moving mean values */
336  *pMovingAveragePowerNew = packPower;
337 
338  /* Calculate new moving means - first add new value */
340  movingAverage_tab.movingAveragePower1sInterval_mA += (*pMovingAveragePowerNew) / divider;
342  movingAverage_tab.movingAveragePower5sInterval_mA += (*pMovingAveragePowerNew) / divider;
344  movingAverage_tab.movingAveragePower10sInterval_mA += (*pMovingAveragePowerNew) / divider;
346  movingAverage_tab.movingAveragePower30sInterval_mA += (*pMovingAveragePowerNew) / divider;
348  movingAverage_tab.movingAveragePower60sInterval_mA += (*pMovingAveragePowerNew) / divider;
350  movingAverage_tab.movingAveragePowerConfigurableInterval_mA += (*pMovingAveragePowerNew) / divider;
351 
352  /* Then, increment pointer and subtract oldest value when respective window is filled with data */
354  if ((powInit & 0x01u) == 0x01u) {
356  movingAverage_tab.movingAveragePower1sInterval_mA -= ((*pMovingAveragePower_1s) / divider);
358  } else {
360  powInit |= 0x01u;
361  }
362  }
363  if ((powInit & 0x02u) == 0x02u) {
365  movingAverage_tab.movingAveragePower5sInterval_mA -= ((*pMovingAveragePower_5s) / divider);
367  } else {
369  powInit |= 0x02u;
370  }
371  }
372  if ((powInit & 0x04u) == 0x04u) {
374  movingAverage_tab.movingAveragePower10sInterval_mA -= ((*pMovingAveragePower_10s) / divider);
376  } else {
378  powInit |= 0x04u;
379  }
380  }
381  if ((powInit & 0x08u) == 0x08u) {
383  movingAverage_tab.movingAveragePower30sInterval_mA -= ((*pMovingAveragePower_30s) / divider);
385  } else {
387  powInit |= 0x08u;
388  }
389  }
390  if ((powInit & 0x10u) == 0x10u) {
392  movingAverage_tab.movingAveragePower60sInterval_mA -= ((*pMovingAveragePower_60s) / divider);
394  } else {
396  powInit |= 0x10u;
397  }
398  }
399  if ((powInit & 0x20u) == 0x20u) {
401  movingAverage_tab.movingAveragePowerConfigurableInterval_mA -= ((*pMovingAveragePower_cfg) / divider);
403  } else {
405  powInit |= 0x20u;
406  }
407  }
408 
409  /* Check pointer for buffer overflow */
412  }
415  }
418  }
421  }
424  }
427  }
430  }
431  }
432  }
433 
434  if (newValues == 1u) {
435  newValues = 0;
436 
437  DATA_WRITE_DATA(&movingAverage_tab);
438  }
439 }
440 
441 /*========== Externalized Static Function Implementations (Unit Test) =======*/
442 #ifdef UNITY_UNIT_TEST
443 #endif
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:86
#define DATA_WRITE_DATA(...)
Definition: database.h:96
@ DATA_BLOCK_ID_MOVING_AVERAGE
Definition: database_cfg.h:101
@ DATA_BLOCK_ID_CURRENT_SENSOR
Definition: database_cfg.h:93
Definition of foxBMS standard types.
#define ALGO_TICK_ms
Definition: algorithm_cfg.h:69
#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_t * pMovingAverageCurrent_30s
static float_t * pMovingAverageCurrent_5s
static float_t * pMovingAveragePower_1s
static float_t * pMovingAveragePowerNew
static float_t * pMovingAveragePower_cfg
#define ALGO_NUMBER_AVERAGE_VALUES_CUR_10s
static float_t * pMovingAverageCurrent_10s
static float_t MEM_EXT_SDRAM powValues[(60000u/ISA_POWER_CYCLE_TIME_ms)+1u]
static float_t * pMovingAveragePower_5s
#define ALGO_NUMBER_AVERAGE_VALUES_POW_60s
#define ALGO_NUMBER_AVERAGE_VALUES_CUR_1s
static float_t * pMovingAverageCurrent_60s
static float_t * pMovingAverageCurrent_cfg
static float_t * pMovingAverageCurrentNew
static float_t MEM_EXT_SDRAM curValues[(60000u/ISA_CURRENT_CYCLE_TIME_ms)+1u]
#define ALGO_NUMBER_AVERAGE_VALUES_POW_CFG
static float_t * pMovingAveragePower_30s
#define ALGO_NUMBER_AVERAGE_VALUES_CUR_30s
static float_t * pMovingAverageCurrent_1s
#define ALGO_NUMBER_AVERAGE_VALUES_POW_10s
#define ALGO_NUMBER_AVERAGE_VALUES_POW_5s
static float_t * pMovingAveragePower_60s
static uint32_t movingAveragePowerLength
#define ALGO_NUMBER_AVERAGE_VALUES_POW_30s
static uint32_t movingAverageCurrentLength
static float_t * pMovingAveragePower_10s
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:220
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:219
uint8_t invalidCurrentMeasurement[BS_NR_OF_STRINGS]
Definition: database_cfg.h:221
int32_t power_W[BS_NR_OF_STRINGS]
Definition: database_cfg.h:227
uint8_t invalidPowerMeasurement[BS_NR_OF_STRINGS]
Definition: database_cfg.h:228
DATA_BLOCK_ID_e uniqueId
Definition: database_cfg.h:125
float_t movingAverageCurrentConfigurableInterval_mA
Definition: database_cfg.h:571
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:565
float_t movingAverageCurrent30sInterval_mA
Definition: database_cfg.h:569
float_t movingAverageCurrent10sInterval_mA
Definition: database_cfg.h:568
float_t movingAveragePowerConfigurableInterval_mA
Definition: database_cfg.h:577
float_t movingAverageCurrent60sInterval_mA
Definition: database_cfg.h:570