source: trunk/fw_g473rct/SES/src/ah_counter.c@ 35

Last change on this file since 35 was 35, checked in by f.jahn, 7 weeks ago
File size: 12.6 KB
Line 
1
2 /******************************************************************************
3*
4* @file ah_counter.c
5* @author ECS, Falko Jahn
6* @version V1.0.0
7* @date 2020-05-01
8* @brief
9*
10******************************************************************************/
11
12// --- INCLUDES -----------------------------------------------------------------
13#include "main.h"
14#include "math.h"
15#include "sysdata.h"
16#include "ah_counter.h"
17#include "wh_counter.h"
18#include "eeprom.h"
19#include "stdio.h"
20// --- EXTERNE VARIABLEN --------------------------------------------------------
21
22// --- LOKALE DEFINES - bitte hier dokumentieren --------------------------------
23
24// --- LOKALE TYPE DEFS - bitte hier dokumentieren-------------------------------
25
26// --- DEFINITIONEN GLOBALER VARIABLEN - Bitte in Header dokumentieren ----------
27
28// --- LOKALE VARIABLEN - bitte hier dokumentieren ------------------------------
29int startMeasurementDischarge = 0;
30int startMeasurementCEF = 0;
31
32// --- LOKALE FUNKTIONS PROTOTYPEN ----------------------------------------------
33int getSocAhRated(void);
34int getSocAhAuto(void);
35
36//int64_t mAs_AutoMode;
37
38
39void AH_COUNTER_Init(void)
40{
41 sys_data.s.values.mAs_AutoMode = (int32_t)-sys_data.s.parameter.cellCapacity * 3600;
42 sys_data.s.values.mAh_AutoMode = (int32_t)-sys_data.s.parameter.cellCapacity ;
43
44 sys_data.s.values.mAs_AutoModeU = (int32_t)-sys_data.s.parameter.cellCapacity * 3600;
45 sys_data.s.values.mAh_AutoModeU = (int32_t)-sys_data.s.parameter.cellCapacity ;
46}
47
48void AH_COUNTER_SetDetectedAh(void)
49{
50 sys_data.s.values.detectedCapacity = sys_data.s.values.mAh_AutoMode >= 0 ? sys_data.s.values.mAh_AutoMode : -sys_data.s.values.mAh_AutoMode;
51}
52
53// --- LOKALE FUNKTIONEN - bitte hier dokumentieren -----------------------------
54int getSocAhRated(void)
55{
56 int64_t cellCapacitySeconds = (int64_t)sys_data.s.parameter.cellCapacity * 60 * 60; // Umrechnung mAh zu mAs
57 return (100000 * sys_data.s.values.mAsCounter) / cellCapacitySeconds;
58}
59
60
61int getSocAhAuto(void)
62{
63
64 const int64_t _100mPercent = 100000LL;
65
66
67 int64_t mAh_AutoMode = sys_data.s.values.mAh_AutoMode < 0 ? -sys_data.s.values.mAh_AutoMode : 0;
68 int64_t tmp = 0LL;
69 if (sys_data.s.values.detectedCapacity <= 0)
70 {
71 tmp = _100mPercent - (mAh_AutoMode * _100mPercent) / (int64_t)sys_data.s.parameter.cellCapacity;
72 }
73 else
74 {
75 tmp = _100mPercent - (mAh_AutoMode * _100mPercent) / (int64_t)sys_data.s.values.detectedCapacity;
76 }
77
78 if (tmp > _100mPercent) tmp = _100mPercent;
79 else if (tmp <= 0) tmp = 0LL;
80 return tmp;
81 }
82
83
84// --- GLOBALE FUNKTIONEN - bitte in Header dokumentieren------------------------
85
86void AH_COUNTER_Exec(void)
87{
88 double iBatDivIbatNenn = 0;
89 double current = 0;
90 double peukert = 0;
91 double calcPow = 0;
92 double cef = 0;
93 double soc = 0;
94 int64_t maxCurrentForBatteryFullDetection = 0;
95 static int16_t batteryFullCounter = 0;
96 static uint64_t totalDischarge = 0;
97 static uint64_t totalCharge = 0;
98
99 int64_t cellCapacitySeconds = (int64_t)sys_data.s.parameter.cellCapacity * 60 * 60; // Umrechnung mAh zu mAs
100
101
102 if (totalDischarge == 0) totalDischarge = sys_data.s.values.dischargeTotalAh * 3600000;
103 if (totalCharge == 0) totalCharge = sys_data.s.values.chargeTotalAh * 3600000;
104
105
106 int32_t realStrom = (int32_t) sys_data.s.values.batteryCurrent - sys_data.s.parameter.extraDischargeStrom_mA;
107
108 // bei Strom größer 0 -> Ladestrom CEF rechnen
109 if (realStrom >= 0)
110 {
111 //99 --> 99% --> 0.99
112 //if (sys_data.s.values.calculatedCEFAh <= 0)
113 //{
114 cef = sys_data.s.parameter.cef / 1000.0;
115 //}
116 //else
117 //{
118 // cef = sys_data.s.values.calculatedCEFAh / 1000.0;
119 //}
120 sys_data.s.values.batteryCurrentCorrected = realStrom * cef * (sys_data.s.values.peukertRemoveCorrectionFaktor/1000.0);
121 }
122 else // if (realStrom < 0)
123 { // bei Strom kleiner 0 peukert rechnen
124 //int32_t ratedCurrent = sys_data.s.parameter.cellRatedCurrent * 1000;
125 int32_t ratedCurrent = sys_data.s.parameter.cellCapacity / sys_data.s.parameter.cellRatedDischargeTime;
126
127
128 if (realStrom < -ratedCurrent) //ACHTUNG mit Minus das vorzeichen gedreht!
129 {
130 current = realStrom;
131 iBatDivIbatNenn = current / ratedCurrent;
132 iBatDivIbatNenn = -iBatDivIbatNenn;
133 peukert = (sys_data.s.parameter.peukert / 100.0);
134 calcPow = pow(iBatDivIbatNenn , peukert - 1.0);
135 sys_data.s.values.batteryCurrentCorrected = (current * calcPow);
136
137 }
138 else sys_data.s.values.batteryCurrentCorrected = realStrom;
139 }
140
141
142 // Counting negative current
143 if (sys_data.s.values.batteryCurrent < 0)
144 {
145 totalDischarge += -realStrom;
146 sys_data.s.values.dischargeTotalAh = totalDischarge / 3600000; //Umrechnung von mAs auf Ah
147
148 sys_data.s.values.fullCyclesCnt = (uint16_t) ((sys_data.s.values.dischargeTotalAh * 1000) / sys_data.s.parameter.cellCapacity);
149 }
150 else
151 {
152 totalCharge += realStrom;
153 sys_data.s.values.chargeTotalAh = totalCharge / 3600000; //Umrechnung von mAs auf Ah
154 }
155
156
157 // Aufsummieren
158 sys_data.s.values.mAsCounter += sys_data.s.values.batteryCurrentCorrected;
159 sys_data.s.values.mAs_AutoMode += sys_data.s.values.batteryCurrentCorrected;
160
161 sys_data.s.values.mAh_AutoMode = sys_data.s.values.mAs_AutoMode / 3600LL;
162
163
164
165 if ((sys_data.s.values.soc > 0) || startMeasurementDischarge)
166 {
167 sys_data.s.values.mAsCounterUncorrected += realStrom;
168 sys_data.s.values.mAhCounterUncorrected = sys_data.s.values.mAsCounterUncorrected / 3600;
169 }
170
171
172 sys_data.s.values.mAs_AutoModeU += sys_data.s.values.batteryCurrent;
173 sys_data.s.values.mAh_AutoModeU = sys_data.s.values.mAs_AutoModeU / 3600LL;
174 if (sys_data.s.values.mAh_AutoModeU != 0)
175 {
176 sys_data.s.values.peukertRemoveCorrectionFaktor = 1000 * sys_data.s.values.mAh_AutoMode / sys_data.s.values.mAh_AutoModeU;
177 }
178 else
179 {
180 sys_data.s.values.peukertRemoveCorrectionFaktor=1000;
181 }
182
183 // Begrenzen, Batterie darf nicht über 100% gehen
184 if (sys_data.s.values.mAsCounter > cellCapacitySeconds) sys_data.s.values.mAsCounter = cellCapacitySeconds;
185
186 if (sys_data.s.values.mAs_AutoMode > 0)
187 {
188 sys_data.s.values.mAs_AutoMode = 0;
189 sys_data.s.values.mAh_AutoMode = 0;
190 sys_data.s.values.mAs_AutoModeU = 0;
191 sys_data.s.values.mAh_AutoModeU = 0;
192
193
194 }
195
196 //Prüfe Battery Voll Bedinungen
197 maxCurrentForBatteryFullDetection = sys_data.s.parameter.cellCapacity * sys_data.s.parameter.iBatFull / 100.0;
198
199 if (sys_data.s.values.batteryVoltage > sys_data.s.parameter.uBatFull && sys_data.s.values.batteryCurrent < maxCurrentForBatteryFullDetection)
200 {
201 batteryFullCounter++;
202 if (batteryFullCounter > sys_data.s.parameter.tBatFull) batteryFullCounter = sys_data.s.parameter.tBatFull;
203 }
204 else
205 {
206 batteryFullCounter = 0;
207 }
208
209 if (batteryFullCounter >= sys_data.s.parameter.tBatFull)
210 {
211 sys_data.s.values.mAsCounter = cellCapacitySeconds;
212 sys_data.s.values.mAs_AutoMode = 0;
213 sys_data.s.values.mAh_AutoMode = 0;
214 // Here we can set Wh to max
215 WH_COUNTER_SetToMax();
216
217 //und wir starten eine neue Battery Kapazitäts und Energiemessung
218 if (startMeasurementDischarge == 0)
219 {
220
221 startMeasurementDischarge = 1;
222 }
223
224 if (startMeasurementCEF == 1)
225 {
226 startMeasurementCEF = 0;
227 sys_data.s.values.calculatedCEFAh = (1000LL * sys_data.s.values.detectedCapacityAtActualCRate * 3600LL) / sys_data.s.values.mAsCounterUncorrected ;
228 sys_data.s.values.calculatedCEFWh = (1000LL * sys_data.s.values.detectedEnergyAtActualCRate * 3600LL) / sys_data.s.values.mWsCounterUncorrected;
229 printf("Time %d: Batterie Full event mAhCarged=%d, tCharge=%d, cefAh=%d, cefWh=%d, u=%d, i=%d\r\n",sys_data.s.values.onTime, sys_data.s.values.mAhCounterUncorrected, sys_data.s.values.lastTimeVbatEmpty, sys_data.s.values.calculatedCEFAh, sys_data.s.values.calculatedCEFWh, sys_data.s.values.batteryVoltage, sys_data.s.values.batteryCurrent);
230 }
231 else {
232
233 //Messung CEF ferig, halter Zähler auf 0 solange Batterie voll, damit die Messung der Kapazität/Energy bei aktuellen Entladestrom korrekt startet
234 sys_data.s.values.mAsCounterUncorrected = 0;
235 sys_data.s.values.mAhCounterUncorrected = 0;
236 sys_data.s.values.mWsCounterUncorrected = 0;
237 }
238
239 }
240
241 sys_data.s.values.mAhCounter = sys_data.s.values.mAsCounter / 3600LL;
242
243 // --- BATTERY LEER ERKENNUNG
244 static uint16_t cnt;
245 if (sys_data.s.parameter.batteryEmptyDetectionMode == 0)
246 {
247 if (sys_data.s.values.batteryVoltage < sys_data.s.values.uBatEmptyTempComp && sys_data.s.values.batteryVoltage > 1000) // Verhindert das beim abziehen der Sense ein Batt Empty erkannt wird
248 {
249 cnt++;
250 if (cnt >= 10)
251 {
252 cnt = 10; //sys_data.s.parameter.tBatFull;
253
254 if ( (startMeasurementDischarge == 1) && (sys_data.s.values.lastTimeVbatFull >= 1200U) && (sys_data.s.values.lastTimeVbatFull <= 200U * 3600U)) // This line prevents from very high discharge-currents to be used to estimate battery capacity
255 {
256
257 AH_COUNTER_SetDetectedAh();
258 WH_COUNTER_SetDetectedEnergy();
259 sys_data.s.values.detectedCapacityAtActualCRate = -sys_data.s.values.mAsCounterUncorrected / 3600;
260 sys_data.s.values.detectedEnergyAtActualCRate = -sys_data.s.values.mWsCounterUncorrected /3600;
261 printf("Time %d: Empty event(1), cn=%d, ca=%d, tDischarge=%d, u=%d, i=%d\r\n",sys_data.s.values.onTime, sys_data.s.values.detectedCapacity, sys_data.s.values.detectedCapacityAtActualCRate, sys_data.s.values.lastTimeVbatFull, sys_data.s.values.batteryVoltage, sys_data.s.values.batteryCurrent);
262 }
263 sys_data.s.values.lastTimeVbatEmpty = 0U;
264
265
266 //Messung wurde gespeichert (bzw. verworfen). Nächste Messung nach Aufladung
267 startMeasurementDischarge = 0;
268
269
270 //Batterie ist Leer, wir können die Messung der Ladung beginnen
271 startMeasurementCEF = 1;
272
273 sys_data.s.values.mAsCounterUncorrected = 0;
274 sys_data.s.values.mAhCounterUncorrected = 0;
275 sys_data.s.values.mWsCounterUncorrected = 0;
276
277 }
278 }
279 else
280 {
281 cnt = 0;
282 }
283 }
284 else
285 {
286 // Neuer Modus. Spannungsmessung wird ignoriert. Erkannt wird Batt Leer mit LVP Signal von LiPro
287 // OVP darf nicht ausgehen, sonst handelt es sich um ein Temperaturabschaltung oder ein andere Fehler
288 // 1000mV als Schwelle um sicher vor rauschen um den Nullpunkt zu seinzu sein
289 if ((sys_data.s.values.ovp_sense > 1000) && (sys_data.s.values.lvp_sense < 1000))
290 {
291 cnt++;
292 if (cnt >= 10)
293 {
294 cnt = 10; //sys_data.s.parameter.tBatFull;
295
296 if ( (startMeasurementDischarge == 1) && (sys_data.s.values.lastTimeVbatFull >= 3600U) && (sys_data.s.values.lastTimeVbatFull <= 240U * 3600U)) // This line prevents from very high discharge-currents to be used to estimate battery capacity
297 {
298
299 AH_COUNTER_SetDetectedAh();
300 WH_COUNTER_SetDetectedEnergy();
301 sys_data.s.values.detectedCapacityAtActualCRate = -sys_data.s.values.mAsCounterUncorrected/ 3600;
302 sys_data.s.values.detectedEnergyAtActualCRate = -sys_data.s.values.mWsCounterUncorrected / 3600;
303 printf("Time %d: Empty event(2), cn=%d, ca=%d, tDischarge=%d, u=%d, i=%d\r\n",sys_data.s.values.onTime, sys_data.s.values.detectedCapacity, sys_data.s.values.detectedCapacityAtActualCRate, sys_data.s.values.lastTimeVbatFull, sys_data.s.values.batteryVoltage, sys_data.s.values.batteryCurrent);
304 }
305
306
307
308 sys_data.s.values.lastTimeVbatEmpty = 0U;
309
310 //Messung wurde gespeichert (bzw. verworfen). Nächste Messung nach Aufladung
311 startMeasurementDischarge = 0;
312
313 //Batterie leer wir können mit der Messung der Ladung beginnen
314 startMeasurementCEF = 1;
315
316
317 sys_data.s.values.mAsCounterUncorrected = 0;
318 sys_data.s.values.mAhCounterUncorrected = 0;
319 sys_data.s.values.mWsCounterUncorrected = 0;
320 }
321 }
322 else
323 {
324 cnt = 0;
325 }
326 }
327
328
329 switch (sys_data.s.parameter.socCalcMode)
330 {
331 case SOC_CALC_MODE_AH_RATED: sys_data.s.values.soc = getSocAhRated(); break;
332 case SOC_CALC_MODE_AH_AUTO: sys_data.s.values.soc = getSocAhAuto(); break;
333 case SOC_CALC_MODE_WH_RATED: sys_data.s.values.soc = WH_COUNTER_GetSoCManual(); break;
334 case SOC_CALC_MODE_WH_AUTO: sys_data.s.values.soc = WH_COUNTER_GetSoCAuto(); break;
335 case SOC_CALC_MODE_WH_AUTO_TEMP: sys_data.s.values.soc = WH_COUNTER_GetSoCAutoTemp(); break;
336 default: sys_data.s.values.soc = 0;
337 }
338
339 sys_data.s.values.soc0 = getSocAhRated()/100;
340 sys_data.s.values.soc1 = getSocAhAuto()/100;
341 sys_data.s.values.soc2 = WH_COUNTER_GetSoCManual()/100;
342 sys_data.s.values.soc3 = WH_COUNTER_GetSoCAuto()/100;
343 sys_data.s.values.soc4 = WH_COUNTER_GetSoCAutoTemp()/100;
344
345
346
347}
Note: See TracBrowser for help on using the repository browser.