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

Last change on this file since 35 was 35, checked in by f.jahn, 18 hours 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.