foxBMS  1.2.1
The foxBMS Battery Management System API Documentation
moving_average.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 moving_average.c
44  * @author foxBMS Team
45  * @date 2017-12-18 (date of creation)
46  * @updated 2021-11-10 (date of last update)
47  * @ingroup ALGORITHMS
48  * @prefix ALGO
49  *
50  * @brief moving average algorithm
51  *
52  */
53 
54 /*========== Includes =======================================================*/
55 #include "moving_average.h"
56 
57 #include "database.h"
58 
59 /*========== Macros and Definitions =========================================*/
60 /** TODO */
61 #define MEM_EXT_SDRAM
62 
63 #if ALGO_TICK_MS > ISA_CURRENT_CYCLE_TIME_MS
64 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_1s ((1000u) / ALGO_TICK_MS)
65 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_5s ((5000u) / ALGO_TICK_MS)
66 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_10s ((10000u) / ALGO_TICK_MS)
67 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_30s ((30000u) / ALGO_TICK_MS)
68 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_60s ((60000u) / ALGO_TICK_MS)
69 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_CFG (MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS / ALGO_TICK_MS)
70 #else
71 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_1s ((1000u) / ISA_CURRENT_CYCLE_TIME_MS)
72 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_5s ((5000u) / ISA_CURRENT_CYCLE_TIME_MS)
73 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_10s ((10000u) / ISA_CURRENT_CYCLE_TIME_MS)
74 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_30s ((30000u) / ISA_CURRENT_CYCLE_TIME_MS)
75 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_60s ((60000u) / ISA_CURRENT_CYCLE_TIME_MS)
76 #define ALGO_NUMBER_AVERAGE_VALUES_CUR_CFG (MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS / ISA_CURRENT_CYCLE_TIME_MS)
77 #endif
78 
79 #if ALGO_TICK_MS > ISA_POWER_CYCLE_TIME_MS
80 #define ALGO_NUMBER_AVERAGE_VALUES_POW_1s ((1000u) / ALGO_TICK_MS)
81 #define ALGO_NUMBER_AVERAGE_VALUES_POW_5s ((5000u) / ALGO_TICK_MS)
82 #define ALGO_NUMBER_AVERAGE_VALUES_POW_10s ((10000u) / ALGO_TICK_MS)
83 #define ALGO_NUMBER_AVERAGE_VALUES_POW_30s ((30000u) / ALGO_TICK_MS)
84 #define ALGO_NUMBER_AVERAGE_VALUES_POW_60s ((60000u) / ALGO_TICK_MS)
85 #define ALGO_NUMBER_AVERAGE_VALUES_POW_CFG (MOVING_AVERAGE_DURATION_POWER_CONFIG_MS / ALGO_TICK_MS)
86 #else
87 #define ALGO_NUMBER_AVERAGE_VALUES_POW_1s ((1000u) / ISA_POWER_CYCLE_TIME_MS)
88 #define ALGO_NUMBER_AVERAGE_VALUES_POW_5s ((5000u) / ISA_POWER_CYCLE_TIME_MS)
89 #define ALGO_NUMBER_AVERAGE_VALUES_POW_10s ((10000u) / ISA_POWER_CYCLE_TIME_MS)
90 #define ALGO_NUMBER_AVERAGE_VALUES_POW_30s ((30000u) / ISA_POWER_CYCLE_TIME_MS)
91 #define ALGO_NUMBER_AVERAGE_VALUES_POW_60s ((60000u) / ISA_POWER_CYCLE_TIME_MS)
92 #define ALGO_NUMBER_AVERAGE_VALUES_POW_CFG (MOVING_AVERAGE_DURATION_POWER_CONFIG_MS / ISA_POWER_CYCLE_TIME_MS)
93 #endif
94 
95 /*========== Static Constant and Variable Definitions =======================*/
96 
97 /* Arrays in extern SDRAM to calculate moving average current and power */
98 
99 /* Check if minimum algo cycle time > current sensor sample time */
100 #if ALGO_TICK_MS > ISA_CURRENT_CYCLE_TIME_MS
101 #if MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS / ALGO_TICK_MS > 60000u / ALGO_TICK_MS
102 /* If array length of configured time > 60s array take this array size */
105 #else
106 /* Take array size of 60s moving average */
107 static float MEM_EXT_SDRAM curValues[(60000u / ALGO_TICK_MS) + 1u] = {};
108 static uint32_t movingAverageCurrentLength = (60000u / ALGO_TICK_MS) + 1;
109 #endif
110 #else
111 /* If array length of configured time > 60s array take this array size */
112 #if (MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS / ISA_CURRENT_CYCLE_TIME_MS) > (60000u / ISA_CURRENT_CYCLE_TIME_MS)
115  1u;
116 #else
117 /* Take array size of 60s moving average */
118 static float MEM_EXT_SDRAM curValues[(60000u / ISA_CURRENT_CYCLE_TIME_MS) + 1u] = {0.0f};
119 static uint32_t movingAverageCurrentLength = (60000u / ISA_CURRENT_CYCLE_TIME_MS) + 1u;
120 #endif
121 #endif
122 
123 /* Check if minimum algo cycle time > current sensor sample time */
124 #if ALGO_TICK_MS > ISA_POWER_CYCLE_TIME_MS
125 #if (MOVING_AVERAGE_DURATION_POWER_CONFIG_MS / ALGO_TICK_MS) > (60000u / ALGO_TICK_MS)
126 /* If array length of configured time > 60s array take this array size */
129 #else
130 /* Take array size of 60s moving average */
131 static float MEM_EXT_SDRAM powValues[(60000u / ALGO_TICK_MS) + 1] = {};
132 static uint32_t movingAveragePowerLength = (60000u / ALGO_TICK_MS) + 1u;
133 #endif
134 #else
135 #if (MOVING_AVERAGE_DURATION_POWER_CONFIG_MS / ISA_POWER_CYCLE_TIME_MS) > (60000u / ISA_POWER_CYCLE_TIME_MS)
136 /* If array length of configured time > 60s array take this array size */
139 #else
140 /* Take array size of 60s moving average */
141 static float MEM_EXT_SDRAM powValues[(60000u / ISA_POWER_CYCLE_TIME_MS) + 1u] = {0.0f};
142 static uint32_t movingAveragePowerLength = (60000u / ISA_POWER_CYCLE_TIME_MS) + 1u;
143 #endif
144 #endif
145 
146 /** Pointer for current moving average calculation @{*/
154 /**@}*/
155 
156 /** Pointer for power moving average calculation @{*/
157 static float *pMovingAveragePowerNew = &powValues[0];
158 static float *pMovingAveragePower_1s = &powValues[0];
159 static float *pMovingAveragePower_5s = &powValues[0];
160 static float *pMovingAveragePower_10s = &powValues[0];
161 static float *pMovingAveragePower_30s = &powValues[0];
162 static float *pMovingAveragePower_60s = &powValues[0];
163 static float *pMovingAveragePower_cfg = &powValues[0];
164 /**@}*/
165 
166 /*========== Extern Constant and Variable Definitions =======================*/
167 
168 /*========== Static Function Prototypes =====================================*/
169 
170 /*========== Static Function Implementations ================================*/
171 
172 /*========== Extern Function Implementations ================================*/
173 extern void ALGO_MovAverage(void) {
174  static uint8_t curCounter = 0u;
175  static uint8_t powCounter = 0u;
178  static uint8_t curInit = 0u; /* bit0: 1s, bit1: 5s, bit2: 10s, bit3: 30s, bit4: 60s, bit5: cfg */
179  static uint8_t powInit = 0u; /* bit0: 1s, bit1: 5s, bit2: 10s, bit3: 30s, bit4: 60s, bit5: cfg */
180  static uint8_t newValues = 0u;
181  float divider = 0.0f;
182  bool validValues = true;
183 
184  DATA_READ_DATA(&curPow_tab);
185  DATA_READ_DATA(&movingAverage_tab);
186 
187  /* Check if new current value */
188  if (curCounter != curPow_tab.newCurrent) {
189  curCounter = curPow_tab.newCurrent;
190 
191  /* Check if valid values */
192  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
193  if (curPow_tab.invalidCurrentMeasurement[stringNumber] != 0u) {
194  validValues = false;
195  }
196  }
197 
198  if (validValues == true) {
199  /* new Values -> Save later in database */
200  newValues = 1u;
201 
202  int32_t packCurrent = 0;
203  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
204  packCurrent += curPow_tab.current_mA[stringNumber];
205  }
206 
207  /* Add value to array and calculate new moving average values */
208  *pMovingAverageCurrentNew = packCurrent;
209 
210  /* Calculate new moving average - first add new value */
212  movingAverage_tab.movingAverageCurrent1sInterval_mA += (*pMovingAverageCurrentNew) / divider;
214  movingAverage_tab.movingAverageCurrent5sInterval_mA += (*pMovingAverageCurrentNew) / divider;
216  movingAverage_tab.movingAverageCurrent10sInterval_mA += (*pMovingAverageCurrentNew) / divider;
218  movingAverage_tab.movingAverageCurrent30sInterval_mA += (*pMovingAverageCurrentNew) / divider;
220  movingAverage_tab.movingAverageCurrent60sInterval_mA += (*pMovingAverageCurrentNew) / divider;
222  movingAverage_tab.movingAverageCurrentConfigurableInterval_mA += (*pMovingAverageCurrentNew) / divider;
223 
224  /* Then, increment pointer and substract oldest value when respective window is filled with data */
226  if ((curInit & 0x01u) == 0x01u) {
228  movingAverage_tab.movingAverageCurrent1sInterval_mA -= ((*pMovingAverageCurrent_1s) / divider);
230  } else {
232  curInit |= 0x01u;
233  }
234  }
235  if ((curInit & 0x02u) == 0x02u) {
237  movingAverage_tab.movingAverageCurrent5sInterval_mA -= (*pMovingAverageCurrent_5s) / divider;
239  } else {
241  curInit |= 0x02u;
242  }
243  }
244  if ((curInit & 0x04u) == 0x04u) {
246  movingAverage_tab.movingAverageCurrent10sInterval_mA -= (*pMovingAverageCurrent_10s) / divider;
248  } else {
250  curInit |= 0x04u;
251  }
252  }
253  if ((curInit & 0x08u) == 0x08u) {
255  movingAverage_tab.movingAverageCurrent30sInterval_mA -= (*pMovingAverageCurrent_30s) / divider;
257  } else {
259  curInit |= 0x08u;
260  }
261  }
262  if ((curInit & 0x10u) == 0x10u) {
264  movingAverage_tab.movingAverageCurrent60sInterval_mA -= (*pMovingAverageCurrent_60s) / divider;
266  } else {
268  curInit |= 0x10u;
269  }
270  }
271  if ((curInit & 0x20u) == 0x20u) {
273  movingAverage_tab.movingAverageCurrentConfigurableInterval_mA -= (*pMovingAverageCurrent_cfg) / divider;
275  } else {
277  curInit |= 0x20u;
278  }
279  }
280 
281  /* Check pointer for buffer overflow */
284  }
287  }
290  }
293  }
296  }
299  }
302  }
303  }
304  }
305 
306  validValues = true;
307 
308  /* Check if new power value */
309  if (powCounter != curPow_tab.newPower) {
310  powCounter = curPow_tab.newPower;
311 
312  /* Check if valid values */
313  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
314  if (curPow_tab.invalidPowerMeasurement[stringNumber] != 0u) {
315  validValues = false;
316  }
317  }
318  if (validValues == true) {
319  newValues = 1u;
320 
321  int32_t packPower = 0;
322  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
323  packPower += curPow_tab.power_W[stringNumber];
324  }
325 
326  /* Add value to array and calculate new moving mean values */
327  *pMovingAveragePowerNew = packPower;
328 
329  /* Calculate new moving means - first add new value */
331  movingAverage_tab.movingAveragePower1sInterval_mA += (*pMovingAveragePowerNew) / divider;
333  movingAverage_tab.movingAveragePower5sInterval_mA += (*pMovingAveragePowerNew) / divider;
335  movingAverage_tab.movingAveragePower10sInterval_mA += (*pMovingAveragePowerNew) / divider;
337  movingAverage_tab.movingAveragePower30sInterval_mA += (*pMovingAveragePowerNew) / divider;
339  movingAverage_tab.movingAveragePower60sInterval_mA += (*pMovingAveragePowerNew) / divider;
341  movingAverage_tab.movingAveragePowerConfigurableInterval_mA += (*pMovingAveragePowerNew) / divider;
342 
343  /* Then, increment pointer and substract oldest value when respective window is filled with data */
345  if ((powInit & 0x01u) == 0x01u) {
347  movingAverage_tab.movingAveragePower1sInterval_mA -= ((*pMovingAveragePower_1s) / divider);
349  } else {
351  powInit |= 0x01u;
352  }
353  }
354  if ((powInit & 0x02u) == 0x02u) {
356  movingAverage_tab.movingAveragePower5sInterval_mA -= ((*pMovingAveragePower_5s) / divider);
358  } else {
360  powInit |= 0x02u;
361  }
362  }
363  if ((powInit & 0x04u) == 0x04u) {
365  movingAverage_tab.movingAveragePower10sInterval_mA -= ((*pMovingAveragePower_10s) / divider);
367  } else {
369  powInit |= 0x04u;
370  }
371  }
372  if ((powInit & 0x08u) == 0x08u) {
374  movingAverage_tab.movingAveragePower30sInterval_mA -= ((*pMovingAveragePower_30s) / divider);
376  } else {
378  powInit |= 0x08u;
379  }
380  }
381  if ((powInit & 0x10u) == 0x10u) {
383  movingAverage_tab.movingAveragePower60sInterval_mA -= ((*pMovingAveragePower_60s) / divider);
385  } else {
387  powInit |= 0x10u;
388  }
389  }
390  if ((powInit & 0x20u) == 0x20u) {
392  movingAverage_tab.movingAveragePowerConfigurableInterval_mA -= ((*pMovingAveragePower_cfg) / divider);
394  } else {
396  powInit |= 0x20u;
397  }
398  }
399 
400  /* Check pointer for buffer overflow */
403  }
406  }
409  }
412  }
415  }
418  }
421  }
422  }
423  }
424 
425  if (newValues == 1u) {
426  newValues = 0;
427 
428  DATA_WRITE_DATA(&movingAverage_tab);
429  }
430 }
431 
432 /*========== Externalized Static Function Implementations (Unit Test) =======*/
#define BS_NR_OF_STRINGS
Database module header.
#define DATA_READ_DATA(...)
Definition: database.h:76
#define DATA_WRITE_DATA(...)
Definition: database.h:86
@ DATA_BLOCK_ID_MOVING_AVERAGE
Definition: database_cfg.h:93
@ DATA_BLOCK_ID_CURRENT_SENSOR
Definition: database_cfg.h:76
#define ALGO_TICK_MS
Definition: algorithm_cfg.h:66
#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 * pMovingAverageCurrent_10s
static float MEM_EXT_SDRAM powValues[(60000u/ISA_POWER_CYCLE_TIME_MS)+1u]
#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 * 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
static float MEM_EXT_SDRAM curValues[(60000u/ISA_CURRENT_CYCLE_TIME_MS)+1u]
moving average algorithm
#define ISA_POWER_CYCLE_TIME_MS
#define MOVING_AVERAGE_DURATION_POWER_CONFIG_MS
#define MOVING_AVERAGE_DURATION_CURRENT_CONFIG_MS
#define ISA_CURRENT_CYCLE_TIME_MS
DATA_BLOCK_ID_e uniqueId
Definition: database_cfg.h:111
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:202
uint8_t invalidCurrentMeasurement[BS_NR_OF_STRINGS]
Definition: database_cfg.h:204
int32_t power_W[BS_NR_OF_STRINGS]
Definition: database_cfg.h:210
int32_t current_mA[BS_NR_OF_STRINGS]
Definition: database_cfg.h:203
uint8_t invalidPowerMeasurement[BS_NR_OF_STRINGS]
Definition: database_cfg.h:211
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:514
float movingAverageCurrentConfigurableInterval_mA
Definition: database_cfg.h:520
float movingAveragePowerConfigurableInterval_mA
Definition: database_cfg.h:526