A public repository for BMS algorithms for a NUCLEO BOARD.

Dependencies:   mbed

Hi Everyone!

Welcome to this repository from Howey's Research Group at the University of Oxford.

The code published here incorporates BMS algorithms for diagnosis functions such as SOC, SOH and Power estimation on a Kokam 53Ah Li-ion battery. This code was designed to work with a NUCLEO F401-RE board and to be tested with a dSPACE HIL Simulator. A short guide on how the set up works is available at https://bitbucket.org/ff95/bms .

The code is made up of three key parts. "Headers" and "Source" folders and the "main.cpp" file. As the code was generated by converting a Simulink model ( available on the BitBucket page), the headers and source code files generated by the conversion are in the corresponding "Headers" and "Source" folders. The "main.cpp" file sets up the ADC, the USB data transmission and starts the estimation (once a character "y" has been received by the computer it is connected to). It also transmits the data from the estimation via USB. Explanation on how to set up the communication with the board is available at BitBucket webpage, from where a MATLAB file can be downloaded which allows real time communication.

For any questions you can contact the author at federicomariaferrari@gmail.com .

The Simulink and Matlab files, together with a short guide, are all available at: https://bitbucket.org/ff95/bms.

Thanks for trying this out!

Federico

Revision:
22:caf41c9bb9d0
Parent:
21:534cd02b6bc4
Child:
23:447ef1071e49
--- a/source/Simulink/EKF.cpp	Fri Mar 03 19:00:02 2017 +0000
+++ b/source/Simulink/EKF.cpp	Wed Mar 08 18:49:52 2017 +0000
@@ -7,9 +7,9 @@
 //
 // Code generated for Simulink model 'EKF'.
 //
-// Model version                  : 1.408
+// Model version                  : 1.425
 // Simulink Coder version         : 8.11 (R2016b) 25-Aug-2016
-// C/C++ source code generated on : Wed Mar  1 17:25:41 2017
+// C/C++ source code generated on : Wed Mar  8 10:23:12 2017
 //
 // Target selection: ert.tlc
 // Embedded hardware selection: STMicroelectronics->ST10/Super10
@@ -35,6 +35,7 @@
 // Forward declaration for local functions
 static int16_T EKF_bsearch(const real_T x[4], real_T xi);
 static real_T EKF_interp2(real_T varargin_4, real_T varargin_5);
+static real_T EKF_interp2_p(real_T varargin_4, real_T varargin_5);
 static real_T EKF_interp2_dispatch(const real_T V[76], real_T Xq, real_T Yq,
   real_T extrapval);
 static void EKF_InterpolateR0(real_T SOC, real_T MeasTemp, real_T XhatParam,
@@ -171,6 +172,109 @@
 }
 
 // Function for MATLAB Function: '<Root>/MATLAB Function'
+static real_T EKF_interp2_p(real_T varargin_4, real_T varargin_5)
+{
+  real_T Vq;
+  int32_T b_y1;
+  int32_T y2;
+  int16_T low_i;
+  int16_T low_ip1;
+  int16_T high_i;
+  int16_T mid_i;
+  real_T qx1;
+  real_T rx;
+  static const real_T b[17] = { 0.05, 0.10625000000000007, 0.16250000000000009,
+    0.21875, 0.275, 0.33125000000000004, 0.38749999999999996, 0.44375, 0.5,
+    0.55625, 0.6125, 0.66875, 0.725, 0.78125, 0.83749999999999991,
+    0.89374999999999993, 0.95 };
+
+  static const real_T V[68] = { 0.003318750942826959, 0.0023001508295625922,
+    0.001810091258767631, 0.0014328808446455602, 0.0030545289991703731,
+    0.0021115342558727062, 0.0016216012369423278, 0.0012823414045409901,
+    0.0027529509371346668, 0.002036583066188943, 0.001545886433903926,
+    0.0012446724248481845, 0.0027524319432923596, 0.0017720469026882386,
+    0.0013951734539969804, 0.0011314777098891079, 0.0029413982954973922,
+    0.0018856539447880626, 0.0013197089099204458, 0.0010937617862261414,
+    0.0027527433161129741, 0.0020366598778004175, 0.001659312893615418,
+    0.0013955418096782679, 0.0025641025641025663, 0.0018852273584194189,
+    0.0015085800490288528, 0.0012819546037252021, 0.0023759239704329357,
+    0.0017728490060729568, 0.0014328268164850424, 0.0012065910033558322,
+    0.0022251555723175622, 0.0016591877521776855, 0.0012822446824558853,
+    0.0010559263868461751, 0.0021121713876211686, 0.0015462945502545701,
+    0.0012444846702115593, 0.0010182531301855535, 0.0019607843137254919,
+    0.0014709210228558553, 0.0011689731890342826, 0.00098024430704267071,
+    0.0022244844097575752, 0.0015838298514216688, 0.0012444846702115593,
+    0.0010559662090813104, 0.0027153416804947981, 0.0021879361726206297,
+    0.0018478711769808023, 0.0015460613145292029, 0.0025639092074504211,
+    0.001998717803673113, 0.0016216012369423445, 0.0013197089099204289,
+    0.002413455011690175, 0.001810023002375657, 0.0014330969980389297,
+    0.0011689291101055859, 0.0021869461935824378, 0.001659250320537012,
+    0.0012820029410655633, 0.0010935555639352886, 0.0020366598778004175,
+    0.0014707546102500505, 0.0012066820015837712, 0.0010181379388362777 };
+
+  real_T tmp[4];
+  if ((varargin_4 >= 0.05) && (varargin_4 <= 0.95) && (varargin_5 >= 15.0) &&
+      (varargin_5 <= 45.0)) {
+    low_i = 0;
+    low_ip1 = 2;
+    high_i = 17;
+    while (high_i > low_ip1) {
+      mid_i = ((low_i + high_i) + 1) >> 1;
+      if (varargin_4 >= b[mid_i - 1]) {
+        low_i = mid_i - 1;
+        low_ip1 = mid_i + 1;
+      } else {
+        high_i = mid_i;
+      }
+    }
+
+    tmp[0] = 15.0;
+    tmp[1] = 25.0;
+    tmp[2] = 35.0;
+    tmp[3] = 45.0;
+    low_ip1 = EKF_bsearch(tmp, varargin_5);
+    b_y1 = (low_ip1 - 1) * 10L + 15L;
+    y2 = 10L * low_ip1 + 15L;
+    if (varargin_4 == b[low_i]) {
+      qx1 = V[((low_i << 2) + low_ip1) - 1];
+      Vq = V[(low_i << 2) + low_ip1];
+    } else if (b[low_i + 1] == varargin_4) {
+      qx1 = V[(((low_i + 1) << 2) + low_ip1) - 1];
+      Vq = V[((low_i + 1) << 2) + low_ip1];
+    } else {
+      rx = (varargin_4 - b[low_i]) / (b[low_i + 1] - b[low_i]);
+      if (V[(((low_i + 1) << 2) + low_ip1) - 1] == V[((low_i << 2) + low_ip1) -
+          1]) {
+        qx1 = V[((low_i << 2) + low_ip1) - 1];
+      } else {
+        qx1 = V[(((low_i + 1) << 2) + low_ip1) - 1] * rx + V[((low_i << 2) +
+          low_ip1) - 1] * (1.0 - rx);
+      }
+
+      if (V[((low_i + 1) << 2) + low_ip1] == V[(low_i << 2) + low_ip1]) {
+        Vq = V[(low_i << 2) + low_ip1];
+      } else {
+        Vq = V[((low_i + 1) << 2) + low_ip1] * rx + V[(low_i << 2) + low_ip1] *
+          (1.0 - rx);
+      }
+    }
+
+    if ((varargin_5 == b_y1) || (qx1 == Vq)) {
+      Vq = qx1;
+    } else {
+      if (!(varargin_5 == y2)) {
+        rx = (varargin_5 - (real_T)b_y1) / (real_T)(y2 - b_y1);
+        Vq = (1.0 - rx) * qx1 + rx * Vq;
+      }
+    }
+  } else {
+    Vq = (rtNaN);
+  }
+
+  return Vq;
+}
+
+// Function for MATLAB Function: '<Root>/MATLAB Function'
 static real_T EKF_interp2_dispatch(const real_T V[76], real_T Xq, real_T Yq,
   real_T extrapval)
 {
@@ -321,9 +425,9 @@
   // IT ASSUMES IT KNOWS THE BEHAVIOUR OF THE DATA BUT NOT THE VALUE (I
   // CALCULATE THE ESTIMATED R0 AND I CAN USE THE KNOWN PARAMETERS TO GET THE
   // 25°C VALUE
-  // '<S1>:1:261' zData=fliplr(ParamData.zR0);
-  // '<S1>:1:262' SlopeData= fliplr(ParamData.SlopeR0);
-  // '<S1>:1:264' InterpSlope=interp1(zData,SlopeData,SOC);
+  // '<S1>:1:274' zData=fliplr(ParamData.zR0);
+  // '<S1>:1:275' SlopeData= fliplr(ParamData.SlopeR0);
+  // '<S1>:1:277' InterpSlope=interp1(zData,SlopeData,SOC);
   InterpSlope = (rtNaN);
   if ((!rtIsNaN(SOC)) && (!((SOC > 1.0) || (SOC < 0.0)))) {
     low_i = 0;
@@ -351,13 +455,13 @@
     }
   }
 
-  // '<S1>:1:266' ParamOffset=XhatParam-InterpSlope*MeasTemp;
-  // '<S1>:1:267' Param25Value=InterpSlope*25+ParamOffset;
+  // '<S1>:1:279' ParamOffset=XhatParam-InterpSlope*MeasTemp;
+  // '<S1>:1:280' Param25Value=InterpSlope*25+ParamOffset;
   *EstimatedT25R0 = (XhatParam - InterpSlope * MeasTemp) + InterpSlope * 25.0;
 
-  // '<S1>:1:270' EstimatedT25R0=Param25Value;
+  // '<S1>:1:283' EstimatedT25R0=Param25Value;
   // DETERMINE THE CORRECT R0 AT 25 VALUE
-  // '<S1>:1:274' TrueT25R0=interp2(ParamData.R0d_x,ParamData.R0d_y,ParamData.R0_map,SOC,25); 
+  // '<S1>:1:287' TrueT25R0=interp2(ParamData.R0d_x,ParamData.R0d_y,ParamData.R0_map,SOC,25); 
   if ((SOC >= 0.05) && (SOC <= 0.95)) {
     low_i = 0;
     low_ip1 = 2;
@@ -415,7 +519,7 @@
     *TrueT25R0 = (rtNaN);
   }
 
-  // '<S1>:1:276' DegradationIndex=EstimatedT25R0/TrueT25R0;
+  // '<S1>:1:289' DegradationIndex=EstimatedT25R0/TrueT25R0;
   *DegradationIndex = *EstimatedT25R0 / *TrueT25R0;
 }
 
@@ -850,29 +954,29 @@
   int16_T i_0;
   real_T Current_0[3];
 
-  // '<S1>:1:229' LoadedData=coder.load('ParamData.mat');
-  // '<S1>:1:230' ParamData=LoadedData.ParamData;
-  // '<S1>:1:232' A=Power.Ahat;
-  // '<S1>:1:233' Xhat=Power.Xhat_;
-  // '<S1>:1:234' TempBattInt=Power.Temp;
-  // '<S1>:1:235' Iterations=Power.Iterations;
-  // '<S1>:1:236' B=Power.Bhat;
-  // '<S1>:1:237' R0=Power.R0;
-  // '<S1>:1:239' PolynomialA=0*A;
+  // '<S1>:1:242' LoadedData=coder.load('ParamData.mat');
+  // '<S1>:1:243' ParamData=LoadedData.ParamData;
+  // '<S1>:1:245' A=Power.Ahat;
+  // '<S1>:1:246' Xhat=Power.Xhat_;
+  // '<S1>:1:247' TempBattInt=Power.Temp;
+  // '<S1>:1:248' Iterations=Power.Iterations;
+  // '<S1>:1:249' B=Power.Bhat;
+  // '<S1>:1:250' R0=Power.R0;
+  // '<S1>:1:252' PolynomialA=0*A;
   for (i_0 = 0; i_0 < 9; i_0++) {
     PolynomialA[i_0] = 0.0 * Power_Ahat[i_0];
   }
 
-  // '<S1>:1:241' for i=0:1:(Iterations-1)
+  // '<S1>:1:254' for i=0:1:(Iterations-1)
   for (i = 0; i < (int16_T)((Power_Iterations - 1.0) + 1.0); i++) {
-    // '<S1>:1:242' PolynomialA=PolynomialA+A^i;
+    // '<S1>:1:255' PolynomialA=PolynomialA+A^i;
     EKF_mpower(Power_Ahat, (real_T)i, tmp);
     for (i_0 = 0; i_0 < 9; i_0++) {
       PolynomialA[i_0] += tmp[i_0];
     }
   }
 
-  // '<S1>:1:245' PredictedStates=A^(Iterations)*Xhat+PolynomialA*B.*[Current Current 0]'; 
+  // '<S1>:1:258' PredictedStates=A^(Iterations)*Xhat+PolynomialA*B.*[Current Current 0]'; 
   EKF_mpower(Power_Ahat, Power_Iterations, tmp);
   Current_0[0] = Current;
   Current_0[1] = Current;
@@ -884,8 +988,8 @@
                        Power_Bhat[0])) * Current_0[i_0];
   }
 
-  // '<S1>:1:247' OCVatSOC= interp2(ParamData.OCVdatad_x,ParamData.OCVdatad_y,ParamData.OCVdata_map,PredictedStates(1),TempBattInt); 
-  // '<S1>:1:249' TerminalVoltage=OCVatSOC -PredictedStates(2) -R0*(Current);
+  // '<S1>:1:260' OCVatSOC= interp2(ParamData.OCVdatad_x,ParamData.OCVdatad_y,ParamData.OCVdata_map,PredictedStates(1),TempBattInt); 
+  // '<S1>:1:262' TerminalVoltage=OCVatSOC -PredictedStates(2) -R0*(Current);
   TerminalVoltage = (EKF_interp2_dispatch(b, PredictedStates[0], Power_Temp,
     (rtNaN)) - PredictedStates[1]) - Power_R0 * Current;
   return TerminalVoltage;
@@ -941,22 +1045,19 @@
 void EKF_step(void)
 {
   real_T C1;
+  real_T tau;
   real_T Ahat[9];
   real_T Bhat[3];
+  real_T Cth;
+  real_T KGainTh;
   real_T C[3];
   real_T KGain[3];
+  real_T OCVatSOC_power;
   real_T dOCVatSOC_power;
   real_T A;
   real_T PolynomialA;
-  int32_T b_y1;
-  int32_T y2;
-  int16_T low_i;
-  int16_T low_ip1;
-  int16_T high_i;
-  int16_T mid_i;
-  real_T qx1;
-  real_T rx;
-  real_T ry;
+  int16_T ixstart;
+  int16_T ix;
   static const real_T d[76] = { 1.2199999999999978, 1.2699999999999967,
     1.2900000000000034, 1.3100000000000012, 1.12, 1.169999999999999, 1.2,
     1.2100000000000033, 1.04, 1.0900000000000034, 1.1199999999999957,
@@ -988,36 +1089,6 @@
     3.946, 3.948, 4.002, 4.001, 4.0, 4.002, 4.056, 4.057, 4.058, 4.06, 4.114,
     4.118, 4.12, 4.123 };
 
-  static const real_T V[68] = { 0.003318750942826959, 0.0023001508295625922,
-    0.001810091258767631, 0.0014328808446455602, 0.0030545289991703731,
-    0.0021115342558727062, 0.0016216012369423278, 0.0012823414045409901,
-    0.0027529509371346668, 0.002036583066188943, 0.001545886433903926,
-    0.0012446724248481845, 0.0027524319432923596, 0.0017720469026882386,
-    0.0013951734539969804, 0.0011314777098891079, 0.0029413982954973922,
-    0.0018856539447880626, 0.0013197089099204458, 0.0010937617862261414,
-    0.0027527433161129741, 0.0020366598778004175, 0.001659312893615418,
-    0.0013955418096782679, 0.0025641025641025663, 0.0018852273584194189,
-    0.0015085800490288528, 0.0012819546037252021, 0.0023759239704329357,
-    0.0017728490060729568, 0.0014328268164850424, 0.0012065910033558322,
-    0.0022251555723175622, 0.0016591877521776855, 0.0012822446824558853,
-    0.0010559263868461751, 0.0021121713876211686, 0.0015462945502545701,
-    0.0012444846702115593, 0.0010182531301855535, 0.0019607843137254919,
-    0.0014709210228558553, 0.0011689731890342826, 0.00098024430704267071,
-    0.0022244844097575752, 0.0015838298514216688, 0.0012444846702115593,
-    0.0010559662090813104, 0.0027153416804947981, 0.0021879361726206297,
-    0.0018478711769808023, 0.0015460613145292029, 0.0025639092074504211,
-    0.001998717803673113, 0.0016216012369423445, 0.0013197089099204289,
-    0.002413455011690175, 0.001810023002375657, 0.0014330969980389297,
-    0.0011689291101055859, 0.0021869461935824378, 0.001659250320537012,
-    0.0012820029410655633, 0.0010935555639352886, 0.0020366598778004175,
-    0.0014707546102500505, 0.0012066820015837712, 0.0010181379388362777 };
-
-  static const real_T h[17] = { 0.05, 0.10625000000000007, 0.16250000000000009,
-    0.21875, 0.275, 0.33125000000000004, 0.38749999999999996, 0.44375, 0.5,
-    0.55625, 0.6125, 0.66875, 0.725, 0.78125, 0.83749999999999991,
-    0.89374999999999993, 0.95 };
-
-  real_T tmp[4];
   real_T Ahat_0[3];
   real_T Ahat_1[9];
   real_T Ahat_2[9];
@@ -1032,76 +1103,85 @@
   //   Inport: '<Root>/TimeStep'
   //   Inport: '<Root>/Voltage'
 
-  // DECIDE WHAT CAPACITY TO USE IN BATTERY SIMULATION AND WHAT IN ESTIMATION
+  // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  // INITIALISE VARIABLES
   // MATLAB Function 'MATLAB Function': '<S1>:1'
-  // DECIDE ON PROCESS AND MEASUREMENT NOISE COVARIANCES
-  // '<S1>:1:8' Q=1;
-  // PROCESS NOISE (CURRENT)
-  // '<S1>:1:9' R=0.01;
-  // SENSOR NOISE (VOLTAGE) THIS NEEDS TO BE FAIRLY LARGE TO ALLOW TO CONVERGE
-  // '<S1>:1:12' InitialSOC=0.8;
-  // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-  // INITIALISE ESTIMATION VECTORS AND P0 MATRICES
-  // '<S1>:1:22' LoadedData=coder.load('ParamData.mat');
-  // '<S1>:1:23' ParamData=LoadedData.ParamData;
-  // '<S1>:1:26' if isempty(Count)
+  // '<S1>:1:13' LoadedData=coder.load('ParamData.mat');
+  // '<S1>:1:14' ParamData=LoadedData.ParamData;
+  //
+  // '<S1>:1:18' if isempty(Count)
   if (!EKF_DW.Count_not_empty) {
-    // '<S1>:1:27' Count=0;
+    // '<S1>:1:20' Count=0;
     EKF_DW.Count = 0.0;
     EKF_DW.Count_not_empty = true;
 
-    // '<S1>:1:29' Xhat=[0.5 0.1 -6.76]';
-    // '<S1>:1:30' P0=[0.1 0 0;
-    // '<S1>:1:31'         0 0.05 0;
-    // '<S1>:1:32'         0 0 .1];
-    // '<S1>:1:34' Qhat=53;
-    // '<S1>:1:35' ThetaHat=Qhat;
-    EKF_DW.ThetaHat = EKF_DW.Qhat;
+    // States
+    // '<S1>:1:23' Xhat=[0.8 0.1 -6.76]';
+    // '<S1>:1:24' P0=[0.1 0 0;
+    // '<S1>:1:25'         0 0.05 0;
+    // '<S1>:1:26'         0 0 .1];
+    // '<S1>:1:27' Current_prev=0;
+    // '<S1>:1:28' Q=1;
+    // PROCESS NOISE (CURRENT)
+    // '<S1>:1:29' R=sqrt(0.1);
+    EKF_DW.R = 0.1;
+    EKF_DW.R = std::sqrt(EKF_DW.R);
 
-    // '<S1>:1:36' P0th=2;
-    // '<S1>:1:37' XhatTh=InitialSOC;
-    // '<S1>:1:38' CthPrev=0;
-    // '<S1>:1:39' iQ=1;
-    // '<S1>:1:40' UpdateMacro=60*20;
-    // '<S1>:1:42' R0_filt=exp(Xhat(3));
-    EKF_DW.R0_filt = EKF_DW.Xhat[2];
-    EKF_DW.R0_filt = std::exp(EKF_DW.R0_filt);
+    // SENSOR NOISE (VOLTAGE) THIS NEEDS TO BE FAIRLY LARGE TO ALLOW TO CONVERGE 
+    // Capacity
+    // '<S1>:1:32' Qhat=53*3600;
+    // '<S1>:1:33' XhatTh=0;
+    // '<S1>:1:34' CthPrev=0;
+    // '<S1>:1:35' iQ=1;
+    // '<S1>:1:36' SumCC=0;
+    // '<S1>:1:37' TimeToUpdateQ=0;
+    // '<S1>:1:38' AbsSumCC=0;
+    // '<S1>:1:39' UpdateQ=60*20;
+    // '<S1>:1:40' Qth=(14400)*1000;
+    // Process Noise
+    // '<S1>:1:41' Rth=1e-6;
+    // SENSOR NOISE
+    // '<S1>:1:42' P0th=10*Qth;
+    EKF_DW.P0th = 10.0 * EKF_DW.Qth;
 
-    // '<S1>:1:43' R0_filt_prev=exp(Xhat(3));
+    // Resistance
+    // '<S1>:1:45' R0_filt_prev=exp(Xhat(3));
     EKF_DW.R0_filt_prev = EKF_DW.Xhat[2];
     EKF_DW.R0_filt_prev = std::exp(EKF_DW.R0_filt_prev);
 
-    // '<S1>:1:45' Current_prev=0;
-    // '<S1>:1:48' Power.iMaxDisch=424;
+    // '<S1>:1:46' Current_prev_R=0;
+    // '<S1>:1:47' alpha=0.999;
+    // Power
+    // '<S1>:1:51' Power.iMaxDisch=424;
     EKF_DW.Power.iMaxDisch = 424.0;
 
     // for max 10s otherwise mac is 265
-    // '<S1>:1:49' Power.iMaxCh=-100;
+    // '<S1>:1:52' Power.iMaxCh=-100;
     EKF_DW.Power.iMaxCh = -100.0;
 
-    // '<S1>:1:50' Power.MaxSOC=0.95;
+    // '<S1>:1:53' Power.MaxSOC=0.95;
     EKF_DW.Power.MaxSOC = 0.95;
 
-    // '<S1>:1:51' Power.MinSOC=0.05;
+    // '<S1>:1:54' Power.MinSOC=0.05;
     EKF_DW.Power.MinSOC = 0.05;
 
-    // '<S1>:1:52' Power.Vmax=4.2;
+    // '<S1>:1:55' Power.Vmax=4.2;
     EKF_DW.Power.Vmax = 4.2;
 
-    // '<S1>:1:53' Power.Vmin=2.7;
+    // '<S1>:1:56' Power.Vmin=2.7;
     EKF_DW.Power.Vmin = 2.7;
 
-    // '<S1>:1:54' Power.Time=0;
+    // '<S1>:1:57' Power.Time=0;
     EKF_DW.Power.Time = 0.0;
 
-    // '<S1>:1:55' Power.Ahat=zeros(3,3);
+    // '<S1>:1:58' Power.Ahat=zeros(3,3);
     memset(&EKF_DW.Power.Ahat[0], 0, 9U * sizeof(real_T));
 
-    // '<S1>:1:56' Power.Bhat=[0 0 0]';
-    // '<S1>:1:57' Power.Temp=0;
+    // '<S1>:1:59' Power.Bhat=[0 0 0]';
+    // '<S1>:1:60' Power.Temp=0;
     EKF_DW.Power.Temp = 0.0;
 
-    // '<S1>:1:58' Power.Xhat_=Xhat;
+    // '<S1>:1:61' Power.Xhat_=Xhat;
     EKF_DW.Power.Bhat[0] = 0.0;
     EKF_DW.Power.Xhat_[0] = EKF_DW.Xhat[0];
     EKF_DW.Power.Bhat[1] = 0.0;
@@ -1109,109 +1189,45 @@
     EKF_DW.Power.Bhat[2] = 0.0;
     EKF_DW.Power.Xhat_[2] = EKF_DW.Xhat[2];
 
-    // '<S1>:1:59' Power.TimeStep=0;
+    // '<S1>:1:62' Power.TimeStep=0;
     EKF_DW.Power.TimeStep = 0.0;
 
-    // '<S1>:1:60' Power.Iterations=0;
+    // '<S1>:1:63' Power.Iterations=0;
     EKF_DW.Power.Iterations = 0.0;
 
-    // '<S1>:1:61' Power.R0=0;
+    // '<S1>:1:64' Power.R0=0;
     EKF_DW.Power.R0 = 0.0;
 
-    // '<S1>:1:62' PowerDischHat=0;
-    // '<S1>:1:63' PowerChHat=0;
-    // '<S1>:1:64' iP=1;
+    // '<S1>:1:65' PowerDischHat=0;
+    // '<S1>:1:66' PowerChHat=0;
+    // '<S1>:1:67' iP=1;
+    // '<S1>:1:68' Power.TimeWindow=10;
+    EKF_DW.Power.TimeWindow = 10.0;
+
+    // '<S1>:1:69' UpdatePower=1;
   } else {
-    // '<S1>:1:66' else
-    // '<S1>:1:67' Count=Count+1;
+    // '<S1>:1:70' else
+    // '<S1>:1:71' Count=Count+1;
     EKF_DW.Count++;
   }
 
-  // '<S1>:1:71' Power.TimeWindow=10;
-  EKF_DW.Power.TimeWindow = 10.0;
-
-  // '<S1>:1:72' UpdatePower=1;
-  // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-  // INITIALISE VARIABLE FOR CAPACITY ESTIMATION
-  // IN SECONDS
-  // Qth=Qhat*1/100*4;
-  // '<S1>:1:80' Qth=5;
-  // '<S1>:1:81' Rth=1e-6;
-  // SENSOR NOISE
+  //
   // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   // INTERPOLATE PARAMETRES
-  // '<S1>:1:85' C1=interp2(ParamData.C1d_x,ParamData.C1d_y,ParamData.C1_map,Xhat(1),TemperatureIn); 
+  // '<S1>:1:81' C1=interp2(ParamData.C1d_x,ParamData.C1d_y,ParamData.C1_map,Xhat(1),TemperatureIn); 
   C1 = EKF_interp2(EKF_DW.Xhat[0], EKF_U.TemperatureIn);
 
-  // '<S1>:1:86' R1=interp2(ParamData.R1d_x,ParamData.R1d_y,ParamData.R1_map,Xhat(1),TemperatureIn); 
-  if ((EKF_DW.Xhat[0] >= 0.05) && (EKF_DW.Xhat[0] <= 0.95) &&
-      ((EKF_U.TemperatureIn >= 15.0) && (EKF_U.TemperatureIn <= 45.0))) {
-    low_i = 0;
-    low_ip1 = 2;
-    high_i = 17;
-    while (high_i > low_ip1) {
-      mid_i = ((low_i + high_i) + 1) >> 1;
-      if (EKF_DW.Xhat[0] >= h[mid_i - 1]) {
-        low_i = mid_i - 1;
-        low_ip1 = mid_i + 1;
-      } else {
-        high_i = mid_i;
-      }
-    }
-
-    tmp[0] = 15.0;
-    tmp[1] = 25.0;
-    tmp[2] = 35.0;
-    tmp[3] = 45.0;
-    low_ip1 = EKF_bsearch(tmp, EKF_U.TemperatureIn);
-    b_y1 = (low_ip1 - 1) * 10L + 15L;
-    y2 = 10L * low_ip1 + 15L;
-    if (EKF_DW.Xhat[0] == h[low_i]) {
-      qx1 = V[((low_i << 2) + low_ip1) - 1];
-      rx = V[(low_i << 2) + low_ip1];
-    } else if (h[low_i + 1] == EKF_DW.Xhat[0]) {
-      qx1 = V[(((low_i + 1) << 2) + low_ip1) - 1];
-      rx = V[((low_i + 1) << 2) + low_ip1];
-    } else {
-      rx = (EKF_DW.Xhat[0] - h[low_i]) / (h[low_i + 1] - h[low_i]);
-      if (V[(((low_i + 1) << 2) + low_ip1) - 1] == V[((low_i << 2) + low_ip1) -
-          1]) {
-        qx1 = V[((low_i << 2) + low_ip1) - 1];
-      } else {
-        qx1 = V[(((low_i + 1) << 2) + low_ip1) - 1] * rx + V[((low_i << 2) +
-          low_ip1) - 1] * (1.0 - rx);
-      }
-
-      if (V[((low_i + 1) << 2) + low_ip1] == V[(low_i << 2) + low_ip1]) {
-        rx = V[(low_i << 2) + low_ip1];
-      } else {
-        rx = V[((low_i + 1) << 2) + low_ip1] * rx + V[(low_i << 2) + low_ip1] *
-          (1.0 - rx);
-      }
-    }
-
-    if ((EKF_U.TemperatureIn == b_y1) || (qx1 == rx)) {
-      rx = qx1;
-    } else {
-      if (!(EKF_U.TemperatureIn == y2)) {
-        ry = (EKF_U.TemperatureIn - (real_T)b_y1) / (real_T)(y2 - b_y1);
-        rx = (1.0 - ry) * qx1 + ry * rx;
-      }
-    }
-  } else {
-    rx = (rtNaN);
-  }
-
-  // '<S1>:1:87' tau=C1*R1;
-  qx1 = C1 * rx;
+  // '<S1>:1:82' R1=interp2(ParamData.R1d_x,ParamData.R1d_y,ParamData.R1_map,Xhat(1),TemperatureIn); 
+  // '<S1>:1:83' tau=C1*R1;
+  tau = C1 * EKF_interp2_p(EKF_DW.Xhat[0], EKF_U.TemperatureIn);
 
   // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   // DISCRETE TIME SS MATRICES
-  // '<S1>:1:91' Ahat=[1     0        0;
-  // '<S1>:1:92'     0 exp(-TimeStep/tau) 0;
-  // '<S1>:1:93'     0     0        1;];
+  // '<S1>:1:87' Ahat=[1     0        0;
+  // '<S1>:1:88'     0 exp(-TimeStep/tau) 0;
+  // '<S1>:1:89'     0     0        1;];
   Ahat[1] = 0.0;
-  Ahat[4] = std::exp(-EKF_U.TimeStep / qx1);
+  Ahat[4] = std::exp(-EKF_U.TimeStep / tau);
   Ahat[7] = 0.0;
   Ahat[0] = 1.0;
   Ahat[2] = 0.0;
@@ -1220,10 +1236,10 @@
   Ahat[6] = 0.0;
   Ahat[8] = 1.0;
 
-  // '<S1>:1:96' Bhat=[-TimeStep/(Qhat*3600)
-  // '<S1>:1:97'     TimeStep/C1
-  // '<S1>:1:98'     1];
-  Bhat[0] = -EKF_U.TimeStep / (EKF_DW.Qhat * 3600.0);
+  // '<S1>:1:92' Bhat=[-TimeStep/(Qhat)
+  // '<S1>:1:93'     TimeStep/C1
+  // '<S1>:1:94'     1];
+  Bhat[0] = -EKF_U.TimeStep / EKF_DW.Qhat;
   Bhat[1] = EKF_U.TimeStep / C1;
   Bhat[2] = 1.0;
 
@@ -1231,162 +1247,186 @@
   // PREDICTION STAGE
   // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   // SOC ESTIMATION FOR CAPACITY ESTIMATION
-  // '<S1>:1:105' if MacroTime>5*60
-  if (EKF_U.MacroTime > 300.0) {
-    // '<S1>:1:106' XhatTh=XhatTh-TimeStep/(Qhat*3600)*Current_prev;
-    EKF_DW.XhatTh -= EKF_U.TimeStep / (EKF_DW.Qhat * 3600.0) *
-      EKF_DW.Current_prev;
+  // '<S1>:1:101' if MacroTime>10*60
+  if (EKF_U.MacroTime > 600.0) {
+    // '<S1>:1:102' SumCC=(Current_prev*TimeStep)+SumCC;
+    EKF_DW.SumCC += EKF_DW.Current_prev * EKF_U.TimeStep;
+
+    // '<S1>:1:103' AbsSumCC=abs(Current_prev*TimeStep)+AbsSumCC;
+    EKF_DW.AbsSumCC += std::abs(EKF_DW.Current_prev * EKF_U.TimeStep);
+
+    // '<S1>:1:104' TimeToUpdateQ=TimeToUpdateQ+TimeStep;
+    EKF_DW.TimeToUpdateQ += EKF_U.TimeStep;
   } else {
-    // '<S1>:1:107' else
-    // '<S1>:1:108' XhatTh=Xhat(1);
+    // '<S1>:1:105' else
+    // '<S1>:1:106' XhatTh=Xhat(1);
     EKF_DW.XhatTh = EKF_DW.Xhat[0];
   }
 
-  // '<S1>:1:112' if MacroTime>UpdateMacro*iQ
-  if (EKF_U.MacroTime > EKF_DW.UpdateMacro * EKF_DW.iQ) {
-    // MACROSCALE EKF FOR CAPACITY ESTIMATION
-    // '<S1>:1:114' P0th=P0th+Qth;
-    EKF_DW.P0th += 5.0;
+  // '<S1>:1:110' if TimeToUpdateQ>UpdateQ
+  if (EKF_DW.TimeToUpdateQ > EKF_DW.UpdateQ) {
+    // if AbsSumCC>1.5e4
+    // '<S1>:1:113' XhatTh=XhatTh-SumCC/(Qhat);
+    EKF_DW.XhatTh -= EKF_DW.SumCC / EKF_DW.Qhat;
 
-    // '<S1>:1:115' Cth=+Current_prev*TimeStep/(ThetaHat^2)+ CthPrev;
-    rx = EKF_DW.Current_prev * EKF_U.TimeStep / (EKF_DW.ThetaHat *
-      EKF_DW.ThetaHat) + EKF_DW.CthPrev;
+    // '<S1>:1:115' P0th=P0th+Qth;
+    EKF_DW.P0th += EKF_DW.Qth;
 
-    // '<S1>:1:116' KGainTh=P0th*(Cth')*(Cth*P0th*Cth'+Rth)^-1;
-    ry = 1.0 / (rx * EKF_DW.P0th * rx + 1.0E-6) * (EKF_DW.P0th * rx);
+    // '<S1>:1:117' Cth=+SumCC/((Qhat)^2)+ CthPrev;
+    Cth = EKF_DW.SumCC / (EKF_DW.Qhat * EKF_DW.Qhat) + EKF_DW.CthPrev;
+
+    // '<S1>:1:119' KGainTh=P0th*(Cth')*(Cth*P0th*Cth'+Rth)^-1;
+    KGainTh = 1.0 / (Cth * EKF_DW.P0th * Cth + EKF_DW.Rth) * (EKF_DW.P0th * Cth);
 
-    // '<S1>:1:117' ThetaHat=ThetaHat+KGainTh*(Xhat(1)-XhatTh(1));
-    EKF_DW.ThetaHat += (EKF_DW.Xhat[0] - EKF_DW.XhatTh) * ry;
+    // '<S1>:1:121' MeasError=Xhat(1)-XhatTh(1);
+    // '<S1>:1:123' Qhat=Qhat+KGainTh*(MeasError);
+    EKF_DW.Qhat += (EKF_DW.Xhat[0] - EKF_DW.XhatTh) * KGainTh;
 
-    // '<S1>:1:118' P0th=P0th-KGainTh*Cth*KGainTh';
-    EKF_DW.P0th -= ry * rx * ry;
+    // '<S1>:1:124' P0th=P0th-KGainTh*Cth*KGainTh';
+    EKF_DW.P0th -= KGainTh * Cth * KGainTh;
 
-    // '<S1>:1:119' CthPrev=Cth;
-    EKF_DW.CthPrev = rx;
+    // '<S1>:1:125' CthPrev=Cth;
+    EKF_DW.CthPrev = Cth;
 
-    // '<S1>:1:120' Qhat=ThetaHat
-    EKF_DW.Qhat = EKF_DW.ThetaHat;
+    // '<S1>:1:127' Qhat/3600;
+    // '<S1>:1:129' iQ=iQ+1;
+    EKF_DW.iQ++;
 
-    // THIS HAS TO BE DONE TO AVOID OVERSHOOTING
-    // '<S1>:1:122' XhatTh=Xhat(1);
+    // '<S1>:1:131' XhatTh=Xhat(1);
     EKF_DW.XhatTh = EKF_DW.Xhat[0];
 
-    // '<S1>:1:123' iQ=iQ+1;
-    EKF_DW.iQ++;
+    // '<S1>:1:133' AbsSumCC=0;
+    EKF_DW.AbsSumCC = 0.0;
+
+    // '<S1>:1:134' SumCC=0;
+    EKF_DW.SumCC = 0.0;
+
+    // '<S1>:1:135' TimeToUpdateQ=0;
+    EKF_DW.TimeToUpdateQ = 0.0;
   }
 
-  // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  //
   // PREDICTION FOR STATES
-  // '<S1>:1:129' Xhat=Ahat*Xhat+Bhat.*[Current_prev Current_prev 0]';
+  // '<S1>:1:140' Xhat=Ahat*Xhat+Bhat.*[Current_prev Current_prev 0]';
   KGain[0] = EKF_DW.Current_prev;
   KGain[1] = EKF_DW.Current_prev;
   KGain[2] = 0.0;
-  for (low_i = 0; low_i < 3; low_i++) {
-    Ahat_0[low_i] = ((Ahat[low_i + 3] * EKF_DW.Xhat[1] + Ahat[low_i] *
-                      EKF_DW.Xhat[0]) + Ahat[low_i + 6] * EKF_DW.Xhat[2]) +
-      Bhat[low_i] * KGain[low_i];
+  for (ixstart = 0; ixstart < 3; ixstart++) {
+    Ahat_0[ixstart] = ((Ahat[ixstart + 3] * EKF_DW.Xhat[1] + Ahat[ixstart] *
+                        EKF_DW.Xhat[0]) + Ahat[ixstart + 6] * EKF_DW.Xhat[2]) +
+      Bhat[ixstart] * KGain[ixstart];
   }
 
-  // '<S1>:1:130' P0=Ahat*P0*Ahat' + Bhat*Q*Bhat';
-  for (low_i = 0; low_i < 3; low_i++) {
-    EKF_DW.Xhat[low_i] = Ahat_0[low_i];
-    for (low_ip1 = 0; low_ip1 < 3; low_ip1++) {
-      Ahat_1[low_i + 3 * low_ip1] = 0.0;
-      Ahat_1[low_i + 3 * low_ip1] += EKF_DW.P0[3 * low_ip1] * Ahat[low_i];
-      Ahat_1[low_i + 3 * low_ip1] += EKF_DW.P0[3 * low_ip1 + 1] * Ahat[low_i + 3];
-      Ahat_1[low_i + 3 * low_ip1] += EKF_DW.P0[3 * low_ip1 + 2] * Ahat[low_i + 6];
+  // '<S1>:1:141' P0=Ahat*P0*Ahat' + Bhat*Q*Bhat';
+  for (ixstart = 0; ixstart < 3; ixstart++) {
+    EKF_DW.Xhat[ixstart] = Ahat_0[ixstart];
+    for (ix = 0; ix < 3; ix++) {
+      Ahat_1[ixstart + 3 * ix] = 0.0;
+      Ahat_1[ixstart + 3 * ix] += EKF_DW.P0[3 * ix] * Ahat[ixstart];
+      Ahat_1[ixstart + 3 * ix] += EKF_DW.P0[3 * ix + 1] * Ahat[ixstart + 3];
+      Ahat_1[ixstart + 3 * ix] += EKF_DW.P0[3 * ix + 2] * Ahat[ixstart + 6];
     }
 
-    for (low_ip1 = 0; low_ip1 < 3; low_ip1++) {
-      Ahat_2[low_i + 3 * low_ip1] = 0.0;
-      Ahat_2[low_i + 3 * low_ip1] += Ahat_1[low_i] * Ahat[low_ip1];
-      Ahat_2[low_i + 3 * low_ip1] += Ahat_1[low_i + 3] * Ahat[low_ip1 + 3];
-      Ahat_2[low_i + 3 * low_ip1] += Ahat_1[low_i + 6] * Ahat[low_ip1 + 6];
-      Bhat_0[low_i + 3 * low_ip1] = Bhat[low_i] * Bhat[low_ip1];
+    for (ix = 0; ix < 3; ix++) {
+      Ahat_2[ixstart + 3 * ix] = 0.0;
+      Ahat_2[ixstart + 3 * ix] += Ahat_1[ixstart] * Ahat[ix];
+      Ahat_2[ixstart + 3 * ix] += Ahat_1[ixstart + 3] * Ahat[ix + 3];
+      Ahat_2[ixstart + 3 * ix] += Ahat_1[ixstart + 6] * Ahat[ix + 6];
+      Bhat_0[ixstart + 3 * ix] = Bhat[ixstart] * EKF_DW.Q * Bhat[ix];
     }
   }
 
-  // '<S1>:1:133' Ytrue=Voltage;
+  // '<S1>:1:143' Current_prev=Current;
+  EKF_DW.Current_prev = EKF_U.Current;
+
+  // '<S1>:1:145' Ytrue=Voltage;
   // ESTIMATION STAGE
   // INTERPOLATE CORRECT VALUES
-  // '<S1>:1:139' OCVatSOC=interp2(ParamData.OCVdatad_x,ParamData.OCVdatad_y,ParamData.OCVdata_map,Xhat(1),TemperatureIn); 
-  // '<S1>:1:140' dOCVatSOC=interp2(ParamData.dOCVdatad_x,ParamData.dOCVdatad_y,ParamData.dOCVdata_map,Xhat(1),TemperatureIn); 
-  // '<S1>:1:143' Yhat=OCVatSOC -Xhat(2) -exp(Xhat(3))*Current;
-  // '<S1>:1:144' C=[dOCVatSOC -1 -exp(Xhat(3))*Current];
-  ry = EKF_interp2_dispatch(d, EKF_DW.Xhat[0], EKF_U.TemperatureIn, (rtNaN));
+  // '<S1>:1:151' OCVatSOC=interp2(ParamData.OCVdatad_x,ParamData.OCVdatad_y,ParamData.OCVdata_map,Xhat(1),TemperatureIn); 
+  // '<S1>:1:152' dOCVatSOC=interp2(ParamData.dOCVdatad_x,ParamData.dOCVdatad_y,ParamData.dOCVdata_map,Xhat(1),TemperatureIn); 
+  // '<S1>:1:155' Yhat=OCVatSOC -Xhat(2) -exp(Xhat(3))*Current;
+  // '<S1>:1:156' C=[dOCVatSOC -1 -exp(Xhat(3))*Current];
+  KGainTh = EKF_interp2_dispatch(d, EKF_DW.Xhat[0], EKF_U.TemperatureIn, (rtNaN));
   C[0] = EKF_interp2_dispatch(d, EKF_DW.Xhat[0], EKF_U.TemperatureIn, (rtNaN));
   C[1] = -1.0;
   C[2] = -std::exp(EKF_DW.Xhat[2]) * EKF_U.Current;
 
-  // '<S1>:1:145' KGain=P0*C'*(C*P0*C'+R)^-1;
-  dOCVatSOC_power = 0.0;
-  for (low_i = 0; low_i < 3; low_i++) {
-    EKF_DW.P0[3 * low_i] = Ahat_2[3 * low_i] + Bhat_0[3 * low_i];
-    rx = EKF_DW.P0[3 * low_i] * ry;
-    EKF_DW.P0[1 + 3 * low_i] = Ahat_2[3 * low_i + 1] + Bhat_0[3 * low_i + 1];
-    rx += -EKF_DW.P0[3 * low_i + 1];
-    EKF_DW.P0[2 + 3 * low_i] = Ahat_2[3 * low_i + 2] + Bhat_0[3 * low_i + 2];
-    rx += EKF_DW.P0[3 * low_i + 2] * C[2];
-    dOCVatSOC_power += rx * C[low_i];
-  }
-
-  rx = 1.0 / (dOCVatSOC_power + 0.01);
-  for (low_i = 0; low_i < 3; low_i++) {
-    KGain[low_i] = (EKF_DW.P0[low_i + 6] * C[2] + (-EKF_DW.P0[low_i + 3] +
-      EKF_DW.P0[low_i] * ry)) * rx;
+  // '<S1>:1:157' KGain=P0*C'*(C*P0*C'+R)^-1;
+  OCVatSOC_power = 0.0;
+  for (ixstart = 0; ixstart < 3; ixstart++) {
+    EKF_DW.P0[3 * ixstart] = Ahat_2[3 * ixstart] + Bhat_0[3 * ixstart];
+    Cth = EKF_DW.P0[3 * ixstart] * KGainTh;
+    EKF_DW.P0[1 + 3 * ixstart] = Ahat_2[3 * ixstart + 1] + Bhat_0[3 * ixstart +
+      1];
+    Cth += -EKF_DW.P0[3 * ixstart + 1];
+    EKF_DW.P0[2 + 3 * ixstart] = Ahat_2[3 * ixstart + 2] + Bhat_0[3 * ixstart +
+      2];
+    Cth += EKF_DW.P0[3 * ixstart + 2] * C[2];
+    OCVatSOC_power += Cth * C[ixstart];
   }
 
-  // '<S1>:1:146' Xhat=Xhat+KGain*(Ytrue-Yhat);
-  rx = EKF_U.Voltage - ((EKF_interp2_dispatch(e, EKF_DW.Xhat[0],
-    EKF_U.TemperatureIn, (rtNaN)) - EKF_DW.Xhat[1]) - std::exp(EKF_DW.Xhat[2]) *
-                        EKF_U.Current);
-
-  // '<S1>:1:147' P0=P0-KGain*(C*P0*C'+R)*KGain';
-  dOCVatSOC_power = 0.0;
-  for (low_i = 0; low_i < 3; low_i++) {
-    EKF_DW.Xhat[low_i] += KGain[low_i] * rx;
-    dOCVatSOC_power += (EKF_DW.P0[3 * low_i + 2] * C[2] + (-EKF_DW.P0[3 * low_i
-      + 1] + EKF_DW.P0[3 * low_i] * ry)) * C[low_i];
+  Cth = 1.0 / (OCVatSOC_power + EKF_DW.R);
+  for (ixstart = 0; ixstart < 3; ixstart++) {
+    KGain[ixstart] = (EKF_DW.P0[ixstart + 6] * C[2] + (-EKF_DW.P0[ixstart + 3] +
+      EKF_DW.P0[ixstart] * KGainTh)) * Cth;
   }
 
-  for (low_i = 0; low_i < 3; low_i++) {
-    EKF_DW.P0[low_i] -= (dOCVatSOC_power + 0.01) * KGain[low_i] * KGain[0];
-    EKF_DW.P0[low_i + 3] -= (dOCVatSOC_power + 0.01) * KGain[low_i] * KGain[1];
-    EKF_DW.P0[low_i + 6] -= (dOCVatSOC_power + 0.01) * KGain[low_i] * KGain[2];
+  // '<S1>:1:158' Xhat=Xhat+KGain*(Ytrue-Yhat);
+  Cth = EKF_U.Voltage - ((EKF_interp2_dispatch(e, EKF_DW.Xhat[0],
+    EKF_U.TemperatureIn, (rtNaN)) - EKF_DW.Xhat[1]) - std::exp(EKF_DW.Xhat[2]) *
+    EKF_U.Current);
+
+  // '<S1>:1:159' P0=P0-KGain*(C*P0*C'+R)*KGain';
+  OCVatSOC_power = 0.0;
+  for (ixstart = 0; ixstart < 3; ixstart++) {
+    EKF_DW.Xhat[ixstart] += KGain[ixstart] * Cth;
+    OCVatSOC_power += (EKF_DW.P0[3 * ixstart + 2] * C[2] + (-EKF_DW.P0[3 *
+      ixstart + 1] + EKF_DW.P0[3 * ixstart] * KGainTh)) * C[ixstart];
+  }
+
+  Cth = OCVatSOC_power + EKF_DW.R;
+  for (ixstart = 0; ixstart < 3; ixstart++) {
+    EKF_DW.P0[ixstart] -= KGain[ixstart] * Cth * KGain[0];
+    EKF_DW.P0[ixstart + 3] -= KGain[ixstart] * Cth * KGain[1];
+    EKF_DW.P0[ixstart + 6] -= KGain[ixstart] * Cth * KGain[2];
   }
 
   // R0 FILTER
-  // '<S1>:1:152' DI=Current-Current_prev;
-  // '<S1>:1:153' Current_prev=Current;
-  EKF_DW.Current_prev = EKF_U.Current;
+  // '<S1>:1:164' if abs(Current-Current_prev_R)>5
+  if (std::abs(EKF_U.Current - EKF_DW.Current_prev_R) > 5.0) {
+    // '<S1>:1:165' 1;
+    // '<S1>:1:166' R0_filt=R0_filt_prev*alpha + (1-alpha)*exp(Xhat(3));
+    Cth = (1.0 - EKF_DW.alpha) * std::exp(EKF_DW.Xhat[2]) + EKF_DW.R0_filt_prev *
+      EKF_DW.alpha;
 
-  // '<S1>:1:155' alpha=0.995;
-  // '<S1>:1:156' if abs(Current)>20
-  if (std::abs(EKF_U.Current) > 5.0) {
-    // '<S1>:1:158' R0_filt=R0_filt_prev*alpha + (1-alpha)*exp(Xhat(3));
-    EKF_DW.R0_filt = EKF_DW.R0_filt_prev * 0.995 + 0.0050000000000000044 * std::
-      exp(EKF_DW.Xhat[2]);
-
-    // '<S1>:1:159' R0_filt_prev=R0_filt;
-    EKF_DW.R0_filt_prev = EKF_DW.R0_filt;
+    // '<S1>:1:167' R0_filt_prev=R0_filt;
+    EKF_DW.R0_filt_prev = Cth;
+  } else {
+    // '<S1>:1:168' else
+    // '<S1>:1:169' R0_filt=R0_filt_prev;
+    Cth = EKF_DW.R0_filt_prev;
   }
 
-  // '<S1>:1:162' [~,~,DegradationIndex]=InterpolateR0(Xhat(1),TemperatureIn, R0_filt,ParamData); 
-  EKF_InterpolateR0(EKF_DW.Xhat[0], EKF_U.TemperatureIn, EKF_DW.R0_filt, &ry,
-                    &dOCVatSOC_power, &rx);
+  // '<S1>:1:174' [~,~,DegradationIndex]=InterpolateR0(Xhat(1),TemperatureIn, R0_filt,ParamData); 
+  EKF_InterpolateR0(EKF_DW.Xhat[0], EKF_U.TemperatureIn, Cth, &OCVatSOC_power,
+                    &dOCVatSOC_power, &KGainTh);
 
-  // '<S1>:1:162' ~
+  // '<S1>:1:174' ~
+  //
   // POWER ESTIMATION
-  // '<S1>:1:166' if MacroTime>UpdatePower*iP
-  if (EKF_U.MacroTime > EKF_DW.iP) {
-    // '<S1>:1:168' Power.Ahat=Ahat;
+  // '<S1>:1:178' if MacroTime>UpdatePower*iP
+  if (EKF_U.MacroTime > EKF_DW.UpdatePower * EKF_DW.iP) {
+    // '<S1>:1:180' Current_prev_R=Current;
+    EKF_DW.Current_prev_R = EKF_U.Current;
+
+    // '<S1>:1:182' Power.Ahat=Ahat;
     memcpy(&EKF_DW.Power.Ahat[0], &Ahat[0], 9U * sizeof(real_T));
 
-    // '<S1>:1:169' Power.Bhat=Bhat;
-    // '<S1>:1:170' Power.Temp=TemperatureIn;
+    // '<S1>:1:183' Power.Bhat=Bhat;
+    // '<S1>:1:184' Power.Temp=TemperatureIn;
     EKF_DW.Power.Temp = EKF_U.TemperatureIn;
 
-    // '<S1>:1:171' Power.Xhat_=Xhat;
+    // '<S1>:1:185' Power.Xhat_=Xhat;
     EKF_DW.Power.Bhat[0] = Bhat[0];
     EKF_DW.Power.Xhat_[0] = EKF_DW.Xhat[0];
     EKF_DW.Power.Bhat[1] = Bhat[1];
@@ -1394,140 +1434,142 @@
     EKF_DW.Power.Bhat[2] = 1.0;
     EKF_DW.Power.Xhat_[2] = EKF_DW.Xhat[2];
 
-    // '<S1>:1:172' Power.TimeStep=TimeStep;
+    // '<S1>:1:186' Power.TimeStep=TimeStep;
     EKF_DW.Power.TimeStep = EKF_U.TimeStep;
 
-    // '<S1>:1:173' Power.Iterations=50;
+    // '<S1>:1:187' Power.Iterations=50;
     EKF_DW.Power.Iterations = 50.0;
 
     // 50 iterations at 0.2s time step is 10seconds
-    // '<S1>:1:174' Power.R0=R0_filt;
-    EKF_DW.Power.R0 = EKF_DW.R0_filt;
+    // '<S1>:1:188' Power.R0=R0_filt;
+    EKF_DW.Power.R0 = Cth;
 
-    // '<S1>:1:176' iChSOC=(Xhat(1)-Power.MaxSOC)*(Qhat*3600)/(Power.TimeWindow); 
-    // '<S1>:1:177' iDischSOC=(Xhat(1)-Power.MinSOC)*(Qhat*3600)/(Power.TimeWindow); 
-    // '<S1>:1:179' OCVatSOC_power=interp2(ParamData.OCVdatad_x,ParamData.OCVdatad_y,ParamData.OCVdata_map,Xhat(1),TemperatureIn); 
-    ry = EKF_interp2_dispatch(e, EKF_DW.Xhat[0], EKF_U.TemperatureIn, (rtNaN));
+    // '<S1>:1:190' iChSOC=(Xhat(1)-Power.MaxSOC)*(Qhat)/(Power.TimeWindow);
+    // '<S1>:1:191' iDischSOC=(Xhat(1)-Power.MinSOC)*(Qhat)/(Power.TimeWindow);
+    // '<S1>:1:193' OCVatSOC_power=interp2(ParamData.OCVdatad_x,ParamData.OCVdatad_y,ParamData.OCVdata_map,Xhat(1),TemperatureIn); 
+    OCVatSOC_power = EKF_interp2_dispatch(e, EKF_DW.Xhat[0], EKF_U.TemperatureIn,
+      (rtNaN));
 
-    // '<S1>:1:180' dOCVatSOC_power=interp2(ParamData.dOCVdatad_x,ParamData.dOCVdatad_y,ParamData.dOCVdata_map,Xhat(1),TemperatureIn); 
+    // '<S1>:1:194' dOCVatSOC_power=interp2(ParamData.dOCVdatad_x,ParamData.dOCVdatad_y,ParamData.dOCVdata_map,Xhat(1),TemperatureIn); 
     dOCVatSOC_power = EKF_interp2_dispatch(d, EKF_DW.Xhat[0],
       EKF_U.TemperatureIn, (rtNaN));
 
-    // '<S1>:1:182' A=exp(-Power.TimeWindow/tau);
-    A = std::exp(-EKF_DW.Power.TimeWindow / qx1);
+    // '<S1>:1:196' A=exp(-Power.TimeWindow/tau);
+    A = std::exp(-EKF_DW.Power.TimeWindow / tau);
 
-    // '<S1>:1:183' PolynomialA=0;
+    // '<S1>:1:197' PolynomialA=0;
     PolynomialA = 0.0;
 
-    // '<S1>:1:184' for i=0:1:(Power.Iterations-1)
-    for (low_i = 0; low_i < (int16_T)((EKF_DW.Power.Iterations - 1.0) + 1.0);
-         low_i++) {
-      // '<S1>:1:185' PolynomialA=PolynomialA+A^i;
-      PolynomialA += rt_powd_snf(A, (real_T)low_i);
+    // '<S1>:1:198' for i=0:1:(Power.Iterations-1)
+    for (ixstart = 0; ixstart < (int16_T)((EKF_DW.Power.Iterations - 1.0) + 1.0);
+         ixstart++) {
+      // '<S1>:1:199' PolynomialA=PolynomialA+A^i;
+      PolynomialA += rt_powd_snf(A, (real_T)ixstart);
     }
 
-    // '<S1>:1:188' iDischOCV=(OCVatSOC_power-Xhat(2)*exp(-Power.TimeWindow/tau)-Power.Vmin)/... 
-    // '<S1>:1:189'         ((Power.TimeWindow/(Qhat*3600))*dOCVatSOC_power+...
-    // '<S1>:1:190'         (Power.TimeStep/C1)*PolynomialA+...
-    // '<S1>:1:191'         Power.R0);
-    // '<S1>:1:193' iChOCV=(OCVatSOC_power-Xhat(2)*exp(-Power.TimeWindow/tau)-Power.Vmax)/... 
-    // '<S1>:1:194'         ((Power.TimeWindow/(Qhat*3600))*dOCVatSOC_power+...
-    // '<S1>:1:195'         (Power.TimeStep/C1)*PolynomialA+...
-    // '<S1>:1:196'         Power.R0);
-    // '<S1>:1:198' IMaxDisch=min([Power.iMaxDisch; iDischOCV; iDischSOC]);
+    // '<S1>:1:202' iDischOCV=(OCVatSOC_power-Xhat(2)*exp(-Power.TimeWindow/tau)-Power.Vmin)/... 
+    // '<S1>:1:203'         ((Power.TimeWindow/(Qhat))*dOCVatSOC_power+...
+    // '<S1>:1:204'         (Power.TimeStep/C1)*PolynomialA+...
+    // '<S1>:1:205'         Power.R0);
+    // '<S1>:1:207' iChOCV=(OCVatSOC_power-Xhat(2)*exp(-Power.TimeWindow/tau)-Power.Vmax)/... 
+    // '<S1>:1:208'         ((Power.TimeWindow/(Qhat))*dOCVatSOC_power+...
+    // '<S1>:1:209'         (Power.TimeStep/C1)*PolynomialA+...
+    // '<S1>:1:210'         Power.R0);
+    // '<S1>:1:212' IMaxDisch=min([Power.iMaxDisch; iDischOCV; iDischSOC]);
     Bhat[0] = EKF_DW.Power.iMaxDisch;
-    Bhat[1] = ((ry - std::exp(-EKF_DW.Power.TimeWindow / qx1) * EKF_DW.Xhat[1])
-               - EKF_DW.Power.Vmin) / ((EKF_DW.Power.TimeWindow / (EKF_DW.Qhat *
-      3600.0) * dOCVatSOC_power + EKF_DW.Power.TimeStep / C1 * PolynomialA) +
-      EKF_DW.Power.R0);
-    Bhat[2] = (EKF_DW.Xhat[0] - EKF_DW.Power.MinSOC) * (EKF_DW.Qhat * 3600.0) /
+    Bhat[1] = ((OCVatSOC_power - std::exp(-EKF_DW.Power.TimeWindow / tau) *
+                EKF_DW.Xhat[1]) - EKF_DW.Power.Vmin) / ((EKF_DW.Power.TimeWindow
+      / EKF_DW.Qhat * dOCVatSOC_power + EKF_DW.Power.TimeStep / C1 * PolynomialA)
+      + EKF_DW.Power.R0);
+    Bhat[2] = (EKF_DW.Xhat[0] - EKF_DW.Power.MinSOC) * EKF_DW.Qhat /
       EKF_DW.Power.TimeWindow;
-    low_i = 1;
+    ixstart = 1;
     A = EKF_DW.Power.iMaxDisch;
     if (rtIsNaN(EKF_DW.Power.iMaxDisch)) {
-      low_ip1 = 2;
+      ix = 2;
       exitg2 = false;
-      while ((!exitg2) && (low_ip1 < 4)) {
-        low_i = low_ip1;
-        if (!rtIsNaN(Bhat[low_ip1 - 1])) {
-          A = Bhat[low_ip1 - 1];
+      while ((!exitg2) && (ix < 4)) {
+        ixstart = ix;
+        if (!rtIsNaN(Bhat[ix - 1])) {
+          A = Bhat[ix - 1];
           exitg2 = true;
         } else {
-          low_ip1++;
+          ix++;
         }
       }
     }
 
-    if (low_i < 3) {
-      while (low_i + 1 < 4) {
-        if (Bhat[low_i] < A) {
-          A = Bhat[low_i];
+    if (ixstart < 3) {
+      while (ixstart + 1 < 4) {
+        if (Bhat[ixstart] < A) {
+          A = Bhat[ixstart];
         }
 
-        low_i++;
+        ixstart++;
       }
     }
 
-    // '<S1>:1:199' IMaxCh=max([Power.iMaxCh;iChOCV;iChSOC]);
+    // '<S1>:1:213' IMaxCh=max([Power.iMaxCh;iChOCV;iChSOC]);
     Bhat[0] = EKF_DW.Power.iMaxCh;
-    Bhat[1] = ((ry - std::exp(-EKF_DW.Power.TimeWindow / qx1) * EKF_DW.Xhat[1])
-               - EKF_DW.Power.Vmax) / ((EKF_DW.Power.TimeWindow / (EKF_DW.Qhat *
-      3600.0) * dOCVatSOC_power + EKF_DW.Power.TimeStep / C1 * PolynomialA) +
-      EKF_DW.Power.R0);
-    Bhat[2] = (EKF_DW.Xhat[0] - EKF_DW.Power.MaxSOC) * (EKF_DW.Qhat * 3600.0) /
+    Bhat[1] = ((OCVatSOC_power - std::exp(-EKF_DW.Power.TimeWindow / tau) *
+                EKF_DW.Xhat[1]) - EKF_DW.Power.Vmax) / ((EKF_DW.Power.TimeWindow
+      / EKF_DW.Qhat * dOCVatSOC_power + EKF_DW.Power.TimeStep / C1 * PolynomialA)
+      + EKF_DW.Power.R0);
+    Bhat[2] = (EKF_DW.Xhat[0] - EKF_DW.Power.MaxSOC) * EKF_DW.Qhat /
       EKF_DW.Power.TimeWindow;
-    low_i = 1;
+    ixstart = 1;
     C1 = EKF_DW.Power.iMaxCh;
     if (rtIsNaN(EKF_DW.Power.iMaxCh)) {
-      low_ip1 = 2;
+      ix = 2;
       exitg1 = false;
-      while ((!exitg1) && (low_ip1 < 4)) {
-        low_i = low_ip1;
-        if (!rtIsNaN(Bhat[low_ip1 - 1])) {
-          C1 = Bhat[low_ip1 - 1];
+      while ((!exitg1) && (ix < 4)) {
+        ixstart = ix;
+        if (!rtIsNaN(Bhat[ix - 1])) {
+          C1 = Bhat[ix - 1];
           exitg1 = true;
         } else {
-          low_ip1++;
+          ix++;
         }
       }
     }
 
-    if (low_i < 3) {
-      while (low_i + 1 < 4) {
-        if (Bhat[low_i] > C1) {
-          C1 = Bhat[low_i];
+    if (ixstart < 3) {
+      while (ixstart + 1 < 4) {
+        if (Bhat[ixstart] > C1) {
+          C1 = Bhat[ixstart];
         }
 
-        low_i++;
+        ixstart++;
       }
     }
 
-    // '<S1>:1:201' VoltTermDisch=PredictTerminalVoltage(IMaxDisch,Power);
-    // '<S1>:1:202' VoltTermCh=PredictTerminalVoltage(IMaxCh,Power);
-    // '<S1>:1:204' PowerDischHat=abs(IMaxDisch*VoltTermDisch);
+    // '<S1>:1:215' VoltTermDisch=PredictTerminalVoltage(IMaxDisch,Power);
+    // '<S1>:1:216' VoltTermCh=PredictTerminalVoltage(IMaxCh,Power);
+    // '<S1>:1:218' PowerDischHat=abs(IMaxDisch*VoltTermDisch);
     EKF_DW.PowerDischHat = std::abs(A * EKF_PredictTerminalVoltage(A,
       EKF_DW.Power.Ahat, EKF_DW.Power.Bhat, EKF_DW.Power.Temp,
       EKF_DW.Power.Xhat_, EKF_DW.Power.Iterations, EKF_DW.Power.R0));
 
-    // '<S1>:1:205' PowerChHat=abs(IMaxCh*VoltTermCh);
+    // '<S1>:1:219' PowerChHat=abs(IMaxCh*VoltTermCh);
     EKF_DW.PowerChHat = std::abs(C1 * EKF_PredictTerminalVoltage(C1,
       EKF_DW.Power.Ahat, EKF_DW.Power.Bhat, EKF_DW.Power.Temp,
       EKF_DW.Power.Xhat_, EKF_DW.Power.Iterations, EKF_DW.Power.R0));
 
-    // '<S1>:1:206' iP=iP+1;
+    // '<S1>:1:220' iP=iP+1;
     EKF_DW.iP++;
   }
 
+  //
   // MAKE SURE SOC IS WITHIN LIMITS
-  // '<S1>:1:212' if Xhat(1)>1
+  // '<S1>:1:226' if Xhat(1)>1
   if (EKF_DW.Xhat[0] > 1.0) {
-    // '<S1>:1:213' Xhat(1)=1;
+    // '<S1>:1:227' Xhat(1)=1;
     EKF_DW.Xhat[0] = 1.0;
   }
 
-  // '<S1>:1:216' if Xhat(1)<0
+  // '<S1>:1:230' if Xhat(1)<0
   if (EKF_DW.Xhat[0] < 0.0) {
-    // '<S1>:1:217' Xhat(1)=0;
+    // '<S1>:1:231' Xhat(1)=0;
     EKF_DW.Xhat[0] = 0.0;
   }
 
@@ -1535,22 +1577,22 @@
   //   MATLAB Function: '<Root>/MATLAB Function'
 
   // OUTPUT THE VALUES
-  // '<S1>:1:221' SOC=Xhat(1);
-  // '<S1>:1:222' Q0=ThetaHat;
-  // '<S1>:1:223' R0=R0_filt;
-  // '<S1>:1:225' PowerDisch=PowerDischHat;
-  // '<S1>:1:226' PowerCh=PowerChHat;
+  // '<S1>:1:235' SOC=Xhat(1);
+  // '<S1>:1:236' Q0=Qhat/3600;
+  // '<S1>:1:237' R0=R0_filt;
+  // '<S1>:1:238' PowerDisch=PowerDischHat;
+  // '<S1>:1:239' PowerCh=PowerChHat;
   EKF_Y.SOC = EKF_DW.Xhat[0];
 
   // Outport: '<Root>/Q0' incorporates:
   //   MATLAB Function: '<Root>/MATLAB Function'
 
-  EKF_Y.Q0 = EKF_DW.ThetaHat;
+  EKF_Y.Q0 = EKF_DW.Qhat / 3600.0;
 
   // Outport: '<Root>/R0' incorporates:
   //   MATLAB Function: '<Root>/MATLAB Function'
 
-  EKF_Y.R0 = EKF_DW.R0_filt;
+  EKF_Y.R0 = Cth;
 
   // Outport: '<Root>/PowerDisch' incorporates:
   //   MATLAB Function: '<Root>/MATLAB Function'
@@ -1565,7 +1607,7 @@
   // Outport: '<Root>/DegradationIndex' incorporates:
   //   MATLAB Function: '<Root>/MATLAB Function'
 
-  EKF_Y.DegradationIndex = rx;
+  EKF_Y.DegradationIndex = KGainTh;
 }
 
 // Model initialize function
@@ -1595,21 +1637,29 @@
     };
 
     // SystemInitialize for MATLAB Function: '<Root>/MATLAB Function'
-    EKF_DW.Xhat[0] = 0.5;
+    EKF_DW.Xhat[0] = 0.85;
     EKF_DW.Xhat[1] = 0.1;
     EKF_DW.Xhat[2] = -6.76;
     memcpy(&EKF_DW.P0[0], &tmp[0], 9U * sizeof(real_T));
     EKF_DW.Count_not_empty = false;
-    EKF_DW.Qhat = 53.0;
-    EKF_DW.P0th = 2.0;
-    EKF_DW.XhatTh = 0.8;
+    EKF_DW.Current_prev = 0.0;
+    EKF_DW.Q = 1.0;
+    EKF_DW.Qhat = 190800.0;
+    EKF_DW.XhatTh = 0.0;
     EKF_DW.CthPrev = 0.0;
     EKF_DW.iQ = 1.0;
-    EKF_DW.UpdateMacro = 1200.0;
-    EKF_DW.Current_prev = 0.0;
+    EKF_DW.SumCC = 0.0;
+    EKF_DW.TimeToUpdateQ = 0.0;
+    EKF_DW.AbsSumCC = 0.0;
+    EKF_DW.UpdateQ = 1200.0;
+    EKF_DW.Qth = 1.44E+7;
+    EKF_DW.Rth = 1.0E-6;
+    EKF_DW.Current_prev_R = 0.0;
+    EKF_DW.alpha = 0.999;
     EKF_DW.PowerDischHat = 0.0;
     EKF_DW.PowerChHat = 0.0;
     EKF_DW.iP = 1.0;
+    EKF_DW.UpdatePower = 1.0;
   }
 }