A public repository for BMS algorithms for a NUCLEO BOARD.
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
Diff: source/Simulink/EKF.cpp
- Revision:
- 23:447ef1071e49
- Parent:
- 22:caf41c9bb9d0
--- a/source/Simulink/EKF.cpp Wed Mar 08 18:49:52 2017 +0000 +++ b/source/Simulink/EKF.cpp Thu Jul 13 10:50:13 2017 +0000 @@ -7,9 +7,9 @@ // // Code generated for Simulink model 'EKF'. // -// Model version : 1.425 +// Model version : 1.439 // Simulink Coder version : 8.11 (R2016b) 25-Aug-2016 -// C/C++ source code generated on : Wed Mar 8 10:23:12 2017 +// C/C++ source code generated on : Wed Mar 15 14:31:33 2017 // // Target selection: ert.tlc // Embedded hardware selection: STMicroelectronics->ST10/Super10 @@ -34,10 +34,12 @@ // 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 real_T EKF_interp2_local(const real_T V[64], real_T Xq, real_T Yq, real_T + extrapval, const real_T X[16], const real_T Y[4]); +static real_T EKF_interp2_local_e(const real_T V[68], real_T Xq, real_T Yq, + real_T extrapval, const real_T X[17], const real_T Y[4]); +static real_T EKF_interp2_local_el(const real_T V[76], real_T Xq, real_T Yq, + real_T extrapval, const real_T X[19], const real_T Y[4]); static void EKF_InterpolateR0(real_T SOC, real_T MeasTemp, real_T XhatParam, real_T *EstimatedT25R0, real_T *TrueT25R0, real_T *DegradationIndex); static void EKF_inv(const real_T x[9], real_T y[9]); @@ -70,54 +72,23 @@ } // Function for MATLAB Function: '<Root>/MATLAB Function' -static real_T EKF_interp2(real_T varargin_4, real_T varargin_5) +static real_T EKF_interp2_local(const real_T V[64], real_T Xq, real_T Yq, real_T + extrapval, const real_T X[16], const real_T Y[4]) { 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[16] = { 0.05, 0.1100000000000001, 0.17000000000000004, - 0.22999999999999998, 0.29000000000000004, 0.35, 0.41000000000000003, - 0.47000000000000003, 0.53, 0.59, 0.64999999999999991, 0.71, 0.77, 0.83, 0.89, - 0.95 }; - - static const real_T V[64] = { 16576.9425034523, 20138.979107141495, - 24421.239197254181, 28529.878780245781, 15374.498069286346, - 21772.293746471405, 25693.107843399048, 32291.115447878838, - 18555.804342031479, 20658.149644732475, 25824.466645717621, - 31220.083832740784, 25359.847992658615, 27558.146119117737, - 28088.040053844452, 32270.592749118805, 23069.943785667419, - 32527.030557394028, 42899.709641933441, 47403.486669063568, - 21542.409062385559, 27543.162256479263, 34497.639834880829, - 38461.93790435791, 20651.820003986359, 25631.530284881592, - 31862.854510545731, 33635.095953941345, 19963.297843933105, - 24295.083433389664, 28222.531974315643, 30071.003437042236, - 19400.93457698822, 23581.461608409882, 28570.601940155029, - 29711.003303527832, 20319.71737742424, 24107.016921043396, - 27998.240292072296, 30197.245478630066, 27554.730474948883, - 30108.308792114258, 31208.517402410507, 34530.265778303146, - 40256.447046995163, 47065.51194190979, 48255.230188369751, - 42222.758531570435, 25791.702717542648, 26096.538305282593, - 26316.764354705811, 28954.031467437744, 20904.739797115326, - 22026.374936103821, 24867.414683103561, 29067.600816488266, - 17860.728204250336, 21127.029955387115, 24830.964803695679, - 28136.543035507202, 16835.392713546753, 21224.110424518585, - 25584.730058908463, 28471.727073192596 }; - - real_T tmp[4]; - if ((varargin_4 >= 0.05) && (varargin_4 <= 0.95) && (varargin_5 >= 15.0) && - (varargin_5 <= 45.0)) { + if ((Xq >= X[0]) && (Xq <= X[15]) && (Yq >= Y[0]) && (Yq <= Y[3])) { low_i = 0; low_ip1 = 2; high_i = 16; while (high_i > low_ip1) { mid_i = ((low_i + high_i) + 1) >> 1; - if (varargin_4 >= b[mid_i - 1]) { + if (Xq >= X[mid_i - 1]) { low_i = mid_i - 1; low_ip1 = mid_i + 1; } else { @@ -125,21 +96,15 @@ } } - 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]) { + low_ip1 = EKF_bsearch(Y, Yq); + if (Xq == X[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) { + } else if (X[low_i + 1] == Xq) { 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]); + rx = (Xq - X[low_i]) / (X[low_i + 1] - X[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]; @@ -156,71 +121,39 @@ } } - if ((varargin_5 == b_y1) || (qx1 == Vq)) { + if ((Y[low_ip1 - 1] == Yq) || (qx1 == Vq)) { Vq = qx1; } else { - if (!(varargin_5 == y2)) { - rx = (varargin_5 - (real_T)b_y1) / (real_T)(y2 - b_y1); + if (!(Yq == Y[low_ip1])) { + rx = (Yq - Y[low_ip1 - 1]) / (Y[low_ip1] - Y[low_ip1 - 1]); Vq = (1.0 - rx) * qx1 + rx * Vq; } } } else { - Vq = (rtNaN); + Vq = extrapval; } return Vq; } // Function for MATLAB Function: '<Root>/MATLAB Function' -static real_T EKF_interp2_p(real_T varargin_4, real_T varargin_5) +static real_T EKF_interp2_local_e(const real_T V[68], real_T Xq, real_T Yq, + real_T extrapval, const real_T X[17], const real_T Y[4]) { 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)) { + if ((Xq >= X[0]) && (Xq <= X[16]) && (Yq >= Y[0]) && (Yq <= Y[3])) { 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]) { + if (Xq >= X[mid_i - 1]) { low_i = mid_i - 1; low_ip1 = mid_i + 1; } else { @@ -228,21 +161,15 @@ } } - 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]) { + low_ip1 = EKF_bsearch(Y, Yq); + if (Xq == X[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) { + } else if (X[low_i + 1] == Xq) { 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]); + rx = (Xq - X[low_i]) / (X[low_i + 1] - X[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]; @@ -259,47 +186,39 @@ } } - if ((varargin_5 == b_y1) || (qx1 == Vq)) { + if ((Y[low_ip1 - 1] == Yq) || (qx1 == Vq)) { Vq = qx1; } else { - if (!(varargin_5 == y2)) { - rx = (varargin_5 - (real_T)b_y1) / (real_T)(y2 - b_y1); + if (!(Yq == Y[low_ip1])) { + rx = (Yq - Y[low_ip1 - 1]) / (Y[low_ip1] - Y[low_ip1 - 1]); Vq = (1.0 - rx) * qx1 + rx * Vq; } } } else { - Vq = (rtNaN); + Vq = extrapval; } 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) +static real_T EKF_interp2_local_el(const real_T V[76], real_T Xq, real_T Yq, + real_T extrapval, const real_T X[19], const real_T Y[4]) { 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[19] = { 0.05, 0.099999999999999978, 0.15000000000000002, - 0.20000000000000007, 0.25000000000000011, 0.30000000000000004, 0.35, 0.4, - 0.44999999999999996, 0.5, 0.55, 0.60000000000000009, 0.64999999999999991, - 0.7, 0.75, 0.79999999999999993, 0.85, 0.89999999999999991, 0.95 }; - - real_T tmp[4]; - if ((Xq >= 0.05) && (Xq <= 0.95) && (Yq >= 15.0) && (Yq <= 45.0)) { + if ((Xq >= X[0]) && (Xq <= X[18]) && (Yq >= Y[0]) && (Yq <= Y[3])) { low_i = 0; low_ip1 = 2; high_i = 19; while (high_i > low_ip1) { mid_i = ((low_i + high_i) + 1) >> 1; - if (Xq >= b[mid_i - 1]) { + if (Xq >= X[mid_i - 1]) { low_i = mid_i - 1; low_ip1 = mid_i + 1; } else { @@ -307,21 +226,15 @@ } } - tmp[0] = 15.0; - tmp[1] = 25.0; - tmp[2] = 35.0; - tmp[3] = 45.0; - low_ip1 = EKF_bsearch(tmp, Yq); - b_y1 = (low_ip1 - 1) * 10L + 15L; - y2 = 10L * low_ip1 + 15L; - if (Xq == b[low_i]) { + low_ip1 = EKF_bsearch(Y, Yq); + if (Xq == X[low_i]) { qx1 = V[((low_i << 2) + low_ip1) - 1]; Vq = V[(low_i << 2) + low_ip1]; - } else if (b[low_i + 1] == Xq) { + } else if (X[low_i + 1] == Xq) { qx1 = V[(((low_i + 1) << 2) + low_ip1) - 1]; Vq = V[((low_i + 1) << 2) + low_ip1]; } else { - rx = (Xq - b[low_i]) / (b[low_i + 1] - b[low_i]); + rx = (Xq - X[low_i]) / (X[low_i + 1] - X[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]; @@ -338,11 +251,11 @@ } } - if ((Yq == b_y1) || (qx1 == Vq)) { + if ((Y[low_ip1 - 1] == Yq) || (qx1 == Vq)) { Vq = qx1; } else { - if (!(Yq == y2)) { - rx = (Yq - (real_T)b_y1) / (real_T)(y2 - b_y1); + if (!(Yq == Y[low_ip1])) { + rx = (Yq - Y[low_ip1 - 1]) / (Y[low_ip1] - Y[low_ip1 - 1]); Vq = (1.0 - rx) * qx1 + rx * Vq; } } @@ -425,9 +338,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:274' zData=fliplr(ParamData.zR0); - // '<S1>:1:275' SlopeData= fliplr(ParamData.SlopeR0); - // '<S1>:1:277' InterpSlope=interp1(zData,SlopeData,SOC); + // '<S1>:1:344' zData=fliplr(ParamData.zR0); + // '<S1>:1:345' SlopeData= fliplr(ParamData.SlopeR0); + // '<S1>:1:347' InterpSlope=interp1(zData,SlopeData,SOC); InterpSlope = (rtNaN); if ((!rtIsNaN(SOC)) && (!((SOC > 1.0) || (SOC < 0.0)))) { low_i = 0; @@ -455,13 +368,13 @@ } } - // '<S1>:1:279' ParamOffset=XhatParam-InterpSlope*MeasTemp; - // '<S1>:1:280' Param25Value=InterpSlope*25+ParamOffset; + // '<S1>:1:349' ParamOffset=XhatParam-InterpSlope*MeasTemp; + // '<S1>:1:350' Param25Value=InterpSlope*25+ParamOffset; *EstimatedT25R0 = (XhatParam - InterpSlope * MeasTemp) + InterpSlope * 25.0; - // '<S1>:1:283' EstimatedT25R0=Param25Value; + // '<S1>:1:353' EstimatedT25R0=Param25Value; // DETERMINE THE CORRECT R0 AT 25 VALUE - // '<S1>:1:287' TrueT25R0=interp2(ParamData.R0d_x,ParamData.R0d_y,ParamData.R0_map,SOC,25); + // '<S1>:1:357' 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; @@ -519,7 +432,7 @@ *TrueT25R0 = (rtNaN); } - // '<S1>:1:289' DegradationIndex=EstimatedT25R0/TrueT25R0; + // '<S1>:1:359' DegradationIndex=EstimatedT25R0/TrueT25R0; *DegradationIndex = *EstimatedT25R0 / *TrueT25R0; } @@ -940,8 +853,9 @@ real_T TerminalVoltage; real_T PolynomialA[9]; real_T PredictedStates[3]; + real_T OCVatSOC; int16_T i; - static const real_T b[76] = { 3.493, 3.464, 3.407, 3.412, 3.526, 3.495, 3.482, + static const real_T V[76] = { 3.493, 3.464, 3.407, 3.412, 3.526, 3.495, 3.482, 3.483, 3.556, 3.531, 3.517, 3.517, 3.578, 3.561, 3.549, 3.549, 3.604, 3.583, 3.574, 3.573, 3.629, 3.612, 3.6, 3.6, 3.643, 3.636, 3.633, 3.634, 3.658, 3.651, 3.649, 3.651, 3.675, 3.668, 3.666, 3.668, 3.696, 3.688, 3.685, 3.687, @@ -950,48 +864,87 @@ 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 }; - real_T tmp[9]; + static const real_T b[19] = { 0.05, 0.099999999999999978, 0.15000000000000002, + 0.20000000000000007, 0.25000000000000011, 0.30000000000000004, 0.35, 0.4, + 0.44999999999999996, 0.5, 0.55, 0.60000000000000009, 0.64999999999999991, + 0.7, 0.75, 0.79999999999999993, 0.85, 0.89999999999999991, 0.95 }; + + static const real_T b_V[76] = { 3.437, 3.46, 3.438, 3.394, 3.497, 3.501, 3.497, + 3.489, 3.532, 3.541, 3.536, 3.524, 3.571, 3.578, 3.575, 3.565, 3.6, 3.608, + 3.605, 3.597, 3.623, 3.63, 3.629, 3.623, 3.639, 3.645, 3.645, 3.643, 3.652, + 3.66, 3.66, 3.658, 3.667, 3.677, 3.677, 3.674, 3.685, 3.697, 3.698, 3.693, + 3.706, 3.722, 3.723, 3.717, 3.733, 3.753, 3.756, 3.748, 3.765, 3.795, 3.799, + 3.787, 3.812, 3.856, 3.86, 3.847, 3.868, 3.904, 3.909, 3.896, 3.914, 3.954, + 3.96, 3.946, 3.963, 4.007, 4.015, 3.999, 4.014, 4.064, 4.072, 4.055, 4.069, + 4.124, 4.133, 4.115 }; + + static const real_T c[19] = { 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, + 0.39999999999999991, 0.44999999999999996, 0.49999999999999994, 0.55, 0.6, + 0.65, 0.7, 0.74999999999999989, 0.79999999999999993, 0.85, 0.9, 0.95 }; + + real_T tmp[4]; + real_T tmp_0[9]; int16_T i_0; real_T Current_0[3]; - // '<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; + // '<S1>:1:308' LoadedDataDch=coder.load('ParamData.mat'); + // '<S1>:1:309' LoadedDataCh=coder.load('ParamDataCh.mat'); + // '<S1>:1:310' ParamData=LoadedDataDch.ParamData; + // '<S1>:1:311' ParamDataCh=LoadedDataCh.ParamDataCh; + // '<S1>:1:313' A=Power.Ahat; + // '<S1>:1:314' Xhat=Power.Xhat_; + // '<S1>:1:315' TempBattInt=Power.Temp; + // '<S1>:1:316' Iterations=Power.Iterations; + // '<S1>:1:317' B=Power.Bhat; + // '<S1>:1:318' R0=Power.R0; + // '<S1>:1:320' PolynomialA=0*A; for (i_0 = 0; i_0 < 9; i_0++) { PolynomialA[i_0] = 0.0 * Power_Ahat[i_0]; } - // '<S1>:1:254' for i=0:1:(Iterations-1) + // '<S1>:1:322' for i=0:1:(Iterations-1) for (i = 0; i < (int16_T)((Power_Iterations - 1.0) + 1.0); i++) { - // '<S1>:1:255' PolynomialA=PolynomialA+A^i; - EKF_mpower(Power_Ahat, (real_T)i, tmp); + // '<S1>:1:323' PolynomialA=PolynomialA+A^i; + EKF_mpower(Power_Ahat, (real_T)i, tmp_0); for (i_0 = 0; i_0 < 9; i_0++) { - PolynomialA[i_0] += tmp[i_0]; + PolynomialA[i_0] += tmp_0[i_0]; } } - // '<S1>:1:258' PredictedStates=A^(Iterations)*Xhat+PolynomialA*B.*[Current Current 0]'; - EKF_mpower(Power_Ahat, Power_Iterations, tmp); + // '<S1>:1:326' PredictedStates=A^(Iterations)*Xhat+PolynomialA*B.*[Current Current 0]'; + EKF_mpower(Power_Ahat, Power_Iterations, tmp_0); Current_0[0] = Current; Current_0[1] = Current; Current_0[2] = 0.0; for (i_0 = 0; i_0 < 3; i_0++) { - PredictedStates[i_0] = ((tmp[i_0 + 3] * Power_Xhat_[1] + tmp[i_0] * - Power_Xhat_[0]) + tmp[i_0 + 6] * Power_Xhat_[2]) + (PolynomialA[i_0 + 6] * - Power_Bhat[2] + (PolynomialA[i_0 + 3] * Power_Bhat[1] + PolynomialA[i_0] * - Power_Bhat[0])) * Current_0[i_0]; + PredictedStates[i_0] = ((tmp_0[i_0 + 3] * Power_Xhat_[1] + tmp_0[i_0] * + Power_Xhat_[0]) + tmp_0[i_0 + 6] * Power_Xhat_[2]) + (PolynomialA[i_0 + 6] + * Power_Bhat[2] + (PolynomialA[i_0 + 3] * Power_Bhat[1] + PolynomialA[i_0] + * Power_Bhat[0])) * Current_0[i_0]; } - // '<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; + // '<S1>:1:327' if Current>0 + if (Current > 0.0) { + // '<S1>:1:328' OCVatSOC= interp2(ParamData.OCVdatad_x,ParamData.OCVdatad_y,ParamData.OCVdata_map,PredictedStates(1),TempBattInt); + tmp[0] = 15.0; + tmp[1] = 25.0; + tmp[2] = 35.0; + tmp[3] = 45.0; + OCVatSOC = EKF_interp2_local_el(V, PredictedStates[0], Power_Temp, (rtNaN), + b, tmp); + } else { + // '<S1>:1:329' else + // '<S1>:1:330' OCVatSOC= interp2(ParamDataCh.OCVdatad_x,ParamDataCh.OCVdatad_y,ParamDataCh.OCVdata_map,PredictedStates(1),TempBattInt); + tmp[0] = 15.0; + tmp[1] = 25.0; + tmp[2] = 35.0; + tmp[3] = 45.0; + OCVatSOC = EKF_interp2_local_el(b_V, PredictedStates[0], Power_Temp, (rtNaN), + c, tmp); + } + + // '<S1>:1:332' TerminalVoltage=OCVatSOC -PredictedStates(2) -R0*(Current); + TerminalVoltage = (OCVatSOC - PredictedStates[1]) - Power_R0 * Current; return TerminalVoltage; } @@ -1048,17 +1001,51 @@ real_T tau; real_T Ahat[9]; real_T Bhat[3]; + int16_T UpdateNow; real_T Cth; real_T KGainTh; + real_T Qhat_old; real_T C[3]; real_T KGain[3]; - real_T OCVatSOC_power; real_T dOCVatSOC_power; real_T A; real_T PolynomialA; - int16_T ixstart; int16_T ix; - static const real_T d[76] = { 1.2199999999999978, 1.2699999999999967, + static const real_T d[19] = { 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, + 0.39999999999999991, 0.44999999999999996, 0.49999999999999994, 0.55, 0.6, + 0.65, 0.7, 0.74999999999999989, 0.79999999999999993, 0.85, 0.9, 0.95 }; + + static const real_T V[76] = { 3.6399999999999988, 2.9899999999999993, 3.71, + 5.77, 0.950000000000002, 0.80999999999999961, 0.97999999999999865, + 1.2999999999999989, 0.74000000000000288, 0.76999999999999957, + 0.78000000000000291, 0.76000000000000068, 0.6800000000000006, + 0.67000000000000171, 0.6899999999999995, 0.72999999999999954, + 0.52000000000000046, 0.52000000000000046, 0.53999999999999826, + 0.58000000000000274, 0.389999999999997, 0.36999999999999922, + 0.40000000000000036, 0.45999999999999819, 0.28999999999999915, + 0.30000000000000249, 0.31000000000000139, 0.349999999999997, + 0.28000000000000025, 0.32000000000000028, 0.32000000000000028, + 0.31000000000000139, 0.32999999999999918, 0.36999999999999922, + 0.37999999999999812, 0.35000000000000142, 0.39000000000000146, + 0.44999999999999929, 0.45999999999999819, 0.43000000000000149, + 0.48000000000000043, 0.5600000000000005, 0.57999999999999829, + 0.5500000000000016, 0.59000000000000163, 0.72999999999999954, + 0.76000000000000068, 0.6999999999999984, 0.78999999999999737, + 1.0299999999999976, 1.0400000000000009, 0.98999999999999755, + 1.0299999999999976, 1.0899999999999999, 1.0999999999999988, + 1.0899999999999999, 1.0200000000000031, 0.98000000000000309, + 1.0000000000000009, 0.990000000000002, 0.950000000000002, 1.0299999999999976, + 1.0599999999999987, 1.030000000000002, 1.0000000000000009, + 1.0999999999999988, 1.120000000000001, 1.0899999999999954, + 1.0599999999999987, 1.17, 1.1800000000000033, 1.160000000000001, + 1.6500000000000004, 1.2099999999999955, 1.1899999999999977, 1.33 }; + + static const real_T e[19] = { 0.05, 0.099999999999999978, 0.15000000000000002, + 0.20000000000000007, 0.25000000000000011, 0.30000000000000004, 0.35, 0.4, + 0.44999999999999996, 0.5, 0.55, 0.60000000000000009, 0.64999999999999991, + 0.7, 0.75, 0.79999999999999993, 0.85, 0.89999999999999991, 0.95 }; + + static const real_T b_V[76] = { 1.2199999999999978, 1.2699999999999967, 1.2900000000000034, 1.3100000000000012, 1.12, 1.169999999999999, 1.2, 1.2100000000000033, 1.04, 1.0900000000000034, 1.1199999999999957, 1.1199999999999957, 0.97999999999999776, 1.0300000000000011, @@ -1080,15 +1067,139 @@ 1.0499999999999989, 1.3099999999999967, 2.8099999999999987, 4.1499999999999968, 4.3099999999999969 }; - static const real_T e[76] = { 3.493, 3.464, 3.407, 3.412, 3.526, 3.495, 3.482, - 3.483, 3.556, 3.531, 3.517, 3.517, 3.578, 3.561, 3.549, 3.549, 3.604, 3.583, - 3.574, 3.573, 3.629, 3.612, 3.6, 3.6, 3.643, 3.636, 3.633, 3.634, 3.658, - 3.651, 3.649, 3.651, 3.675, 3.668, 3.666, 3.668, 3.696, 3.688, 3.685, 3.687, - 3.722, 3.713, 3.71, 3.712, 3.754, 3.744, 3.74, 3.743, 3.801, 3.787, 3.781, - 3.785, 3.859, 3.85, 3.846, 3.848, 3.904, 3.898, 3.895, 3.897, 3.952, 3.948, - 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 c_V[76] = { 3.437, 3.46, 3.438, 3.394, 3.497, 3.501, 3.497, + 3.489, 3.532, 3.541, 3.536, 3.524, 3.571, 3.578, 3.575, 3.565, 3.6, 3.608, + 3.605, 3.597, 3.623, 3.63, 3.629, 3.623, 3.639, 3.645, 3.645, 3.643, 3.652, + 3.66, 3.66, 3.658, 3.667, 3.677, 3.677, 3.674, 3.685, 3.697, 3.698, 3.693, + 3.706, 3.722, 3.723, 3.717, 3.733, 3.753, 3.756, 3.748, 3.765, 3.795, 3.799, + 3.787, 3.812, 3.856, 3.86, 3.847, 3.868, 3.904, 3.909, 3.896, 3.914, 3.954, + 3.96, 3.946, 3.963, 4.007, 4.015, 3.999, 4.014, 4.064, 4.072, 4.055, 4.069, + 4.124, 4.133, 4.115 }; + + static const real_T d_V[76] = { 3.493, 3.464, 3.407, 3.412, 3.526, 3.495, + 3.482, 3.483, 3.556, 3.531, 3.517, 3.517, 3.578, 3.561, 3.549, 3.549, 3.604, + 3.583, 3.574, 3.573, 3.629, 3.612, 3.6, 3.6, 3.643, 3.636, 3.633, 3.634, + 3.658, 3.651, 3.649, 3.651, 3.675, 3.668, 3.666, 3.668, 3.696, 3.688, 3.685, + 3.687, 3.722, 3.713, 3.71, 3.712, 3.754, 3.744, 3.74, 3.743, 3.801, 3.787, + 3.781, 3.785, 3.859, 3.85, 3.846, 3.848, 3.904, 3.898, 3.895, 3.897, 3.952, + 3.948, 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 e_V[68] = { 0.0032053699374010093, 0.0021497265698661111, + 0.0016214177978883919, 0.0012820512820512916, 0.0030545289991703731, + 0.0019988685649632259, 0.001546003016591249, 0.0013199577613516422, + 0.0025639092074504041, 0.0018101595203077287, 0.001395278678633378, + 0.0011690613568654123, 0.0022627847337456652, 0.0015837701270786915, + 0.0012820512820512749, 0.001131307036729761, 0.0020364294603461863, + 0.0014705882352941233, 0.0011690172712874327, 0.0010180611590814709, + 0.00211185277369235, 0.0015837104072398121, 0.0012443908141332599, + 0.00098039215686275441, 0.0023006713434411989, 0.0017344745673240004, + 0.0013577732518669395, 0.0010935555639352886, 0.0024130910187768668, + 0.0018475228112510345, 0.00143293487688072, 0.0011692377324331511, + 0.0025264904408160084, 0.0019608582525736285, 0.0015454202789295108, + 0.0012446254808780237, 0.0026399155227032674, 0.0020739064856711976, + 0.0016968325791855178, 0.0013952260643312314, 0.0026024968883189359, + 0.0021493212669683234, 0.0017345399698340974, 0.0014705882352941064, + 0.0026393183017871897, 0.0019979643382214323, 0.0016968325791855178, + 0.0015082956259426861, 0.0023004978126414388, 0.0013951734539969804, + 0.001131221719457023, 0.00098061401523724234, 0.0018480105600603405, + 0.0015084093823063591, 0.0012446254808780404, 0.00098042912628682247, + 0.0021494023153210886, 0.0017346053772766628, 0.0013951208476301769, + 0.0010935143288084432, 0.0024886877828054236, 0.0019232219624406121, + 0.00147058823529414, 0.0012066365007541323, 0.0027904521286624628, + 0.0020742193392668472, 0.001621723552706021, 0.0012821479749604305 }; + + 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 }; + static const real_T f_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 j[16] = { 0.05, 0.10999999999999999, 0.16999999999999998, + 0.22999999999999998, 0.29, 0.35, 0.41, 0.46999999999999992, + 0.52999999999999992, 0.59, 0.65, 0.71, 0.77, 0.83, 0.8899999999999999, 0.95 + }; + + static const real_T g_V[64] = { 12952.58454978466, 16721.245646476746, + 18094.454854726791, 19519.349336624146, 16455.746591091156, + 19678.233414888382, 22328.75183224678, 28442.932069301605, + 16769.467890262604, 20145.526826381683, 21402.607858181, 26433.236002922058, + 15587.565451860428, 20140.820145606995, 25156.97255730629, + 27427.809238433838, 13005.107939243317, 16267.156600952148, + 20800.438523292542, 28211.558312177658, 14418.013095855713, + 17023.013830184937, 20969.395637512207, 24025.956839323044, + 19510.320052504539, 16737.51026391983, 20584.938079118729, + 21689.800769090652, 25105.454325675964, 20594.489276409149, + 20420.795679092407, 24547.557830810547, 30244.764536619186, + 28689.835667610168, 21030.941307544708, 25378.375649452209, + 38914.605975151062, 39606.031626462936, 27208.808213472366, + 25108.094215393066, 50986.163169145584, 61406.42374753952, + 44493.357837200165, 28249.984309077263, 67713.165283203125, + 79396.185725927353, 76527.339890599251, 54358.5991859436, 36749.007776379585, + 20649.336278438568, 25218.520164489746, 27854.651063680649, + 16192.848384380341, 20641.534104943275, 24964.586496353149, + 26407.085955142975, 16436.644196510315, 21475.938558578491, + 26011.685431003571, 28530.018329620361, 16578.286588191986, + 22495.884746313095, 26096.648871898651, 29256.966412067413 }; + + static const real_T k[16] = { 0.05, 0.1100000000000001, 0.17000000000000004, + 0.22999999999999998, 0.29000000000000004, 0.35, 0.41000000000000003, + 0.47000000000000003, 0.53, 0.59, 0.64999999999999991, 0.71, 0.77, 0.83, 0.89, + 0.95 }; + + static const real_T h_V[64] = { 16576.9425034523, 20138.979107141495, + 24421.239197254181, 28529.878780245781, 15374.498069286346, + 21772.293746471405, 25693.107843399048, 32291.115447878838, + 18555.804342031479, 20658.149644732475, 25824.466645717621, + 31220.083832740784, 25359.847992658615, 27558.146119117737, + 28088.040053844452, 32270.592749118805, 23069.943785667419, + 32527.030557394028, 42899.709641933441, 47403.486669063568, + 21542.409062385559, 27543.162256479263, 34497.639834880829, + 38461.93790435791, 20651.820003986359, 25631.530284881592, + 31862.854510545731, 33635.095953941345, 19963.297843933105, + 24295.083433389664, 28222.531974315643, 30071.003437042236, + 19400.93457698822, 23581.461608409882, 28570.601940155029, + 29711.003303527832, 20319.71737742424, 24107.016921043396, + 27998.240292072296, 30197.245478630066, 27554.730474948883, + 30108.308792114258, 31208.517402410507, 34530.265778303146, + 40256.447046995163, 47065.51194190979, 48255.230188369751, + 42222.758531570435, 25791.702717542648, 26096.538305282593, + 26316.764354705811, 28954.031467437744, 20904.739797115326, + 22026.374936103821, 24867.414683103561, 29067.600816488266, + 17860.728204250336, 21127.029955387115, 24830.964803695679, + 28136.543035507202, 16835.392713546753, 21224.110424518585, + 25584.730058908463, 28471.727073192596 }; + + real_T tmp[4]; + real_T tmp_0[4]; + real_T tmp_1[4]; + real_T tmp_2[4]; + real_T tmp_3[17]; + real_T tmp_4[4]; + real_T tmp_5[4]; real_T Ahat_0[3]; real_T Ahat_1[9]; real_T Ahat_2[9]; @@ -1108,80 +1219,80 @@ // MATLAB Function 'MATLAB Function': '<S1>:1' // '<S1>:1:13' LoadedData=coder.load('ParamData.mat'); // '<S1>:1:14' ParamData=LoadedData.ParamData; + // '<S1>:1:15' LoadedData=coder.load('ParamDataCh.mat'); + // '<S1>:1:16' ParamDataCh=LoadedData.ParamDataCh; // - // '<S1>:1:18' if isempty(Count) + // '<S1>:1:21' if isempty(Count) if (!EKF_DW.Count_not_empty) { - // '<S1>:1:20' Count=0; + // '<S1>:1:23' Count=0; EKF_DW.Count = 0.0; EKF_DW.Count_not_empty = true; // 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; + // '<S1>:1:26' Xhat=[0.8 0.1 -6.76]'; + // '<S1>:1:27' P0=[0.1 0 0; + // '<S1>:1:28' 0 0.05 0; + // '<S1>:1:29' 0 0 .1]; + // '<S1>:1:30' Current_prev=0; + // '<S1>:1:31' 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:32' R=0.01; // 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; + // '<S1>:1:35' Qhat=53*3600; + // '<S1>:1:36' XhatTh=0; + // '<S1>:1:37' XhatTh_Update=0; + // '<S1>:1:38' CthPrev=0; + // '<S1>:1:39' iQ=1; + // '<S1>:1:40' SumCC=0; + // '<S1>:1:41' TimeToUpdateQ=0; + // '<S1>:1:42' AbsSumCC=0; + // '<S1>:1:43' UpdateQ=60*20; + // '<S1>:1:45' Qth=(14400)*1000; // Process Noise - // '<S1>:1:41' Rth=1e-6; + // '<S1>:1:46' Rth=1e-6; // SENSOR NOISE - // '<S1>:1:42' P0th=10*Qth; + // '<S1>:1:47' P0th=10*Qth; EKF_DW.P0th = 10.0 * EKF_DW.Qth; // Resistance - // '<S1>:1:45' R0_filt_prev=exp(Xhat(3)); + // '<S1>:1:50' 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:46' Current_prev_R=0; - // '<S1>:1:47' alpha=0.999; + // '<S1>:1:51' Current_prev_R=0; + // '<S1>:1:52' alpha=0.999; // Power - // '<S1>:1:51' Power.iMaxDisch=424; + // '<S1>:1:56' Power.iMaxDisch=424; EKF_DW.Power.iMaxDisch = 424.0; // for max 10s otherwise mac is 265 - // '<S1>:1:52' Power.iMaxCh=-100; + // '<S1>:1:57' Power.iMaxCh=-100; EKF_DW.Power.iMaxCh = -100.0; - // '<S1>:1:53' Power.MaxSOC=0.95; + // '<S1>:1:58' Power.MaxSOC=0.95; EKF_DW.Power.MaxSOC = 0.95; - // '<S1>:1:54' Power.MinSOC=0.05; + // '<S1>:1:59' Power.MinSOC=0.05; EKF_DW.Power.MinSOC = 0.05; - // '<S1>:1:55' Power.Vmax=4.2; + // '<S1>:1:60' Power.Vmax=4.2; EKF_DW.Power.Vmax = 4.2; - // '<S1>:1:56' Power.Vmin=2.7; + // '<S1>:1:61' Power.Vmin=2.7; EKF_DW.Power.Vmin = 2.7; - // '<S1>:1:57' Power.Time=0; + // '<S1>:1:62' Power.Time=0; EKF_DW.Power.Time = 0.0; - // '<S1>:1:58' Power.Ahat=zeros(3,3); + // '<S1>:1:63' Power.Ahat=zeros(3,3); memset(&EKF_DW.Power.Ahat[0], 0, 9U * sizeof(real_T)); - // '<S1>:1:59' Power.Bhat=[0 0 0]'; - // '<S1>:1:60' Power.Temp=0; + // '<S1>:1:64' Power.Bhat=[0 0 0]'; + // '<S1>:1:65' Power.Temp=0; EKF_DW.Power.Temp = 0.0; - // '<S1>:1:61' Power.Xhat_=Xhat; + // '<S1>:1:66' 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; @@ -1189,43 +1300,78 @@ EKF_DW.Power.Bhat[2] = 0.0; EKF_DW.Power.Xhat_[2] = EKF_DW.Xhat[2]; - // '<S1>:1:62' Power.TimeStep=0; + // '<S1>:1:67' Power.TimeStep=0; EKF_DW.Power.TimeStep = 0.0; - // '<S1>:1:63' Power.Iterations=0; + // '<S1>:1:68' Power.Iterations=0; EKF_DW.Power.Iterations = 0.0; - // '<S1>:1:64' Power.R0=0; + // '<S1>:1:69' Power.R0=0; EKF_DW.Power.R0 = 0.0; - // '<S1>:1:65' PowerDischHat=0; - // '<S1>:1:66' PowerChHat=0; - // '<S1>:1:67' iP=1; - // '<S1>:1:68' Power.TimeWindow=10; + // '<S1>:1:70' PowerDischHat=0; + // '<S1>:1:71' PowerChHat=0; + // '<S1>:1:72' iP=1; + // '<S1>:1:73' Power.TimeWindow=10; EKF_DW.Power.TimeWindow = 10.0; - // '<S1>:1:69' UpdatePower=1; + // '<S1>:1:74' UpdatePower=1; } else { - // '<S1>:1:70' else - // '<S1>:1:71' Count=Count+1; + // '<S1>:1:75' else + // '<S1>:1:76' Count=Count+1; EKF_DW.Count++; } // // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // INTERPOLATE PARAMETRES - // '<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:87' if Current>0 + if (EKF_U.Current > 0.0) { + // '<S1>:1:88' C1=interp2(ParamData.C1d_x,ParamData.C1d_y,ParamData.C1_map,Xhat(1),TemperatureIn); + tmp_5[0] = 15.0; + tmp_5[1] = 25.0; + tmp_5[2] = 35.0; + tmp_5[3] = 45.0; + C1 = EKF_interp2_local(h_V, EKF_DW.Xhat[0], EKF_U.TemperatureIn, (rtNaN), k, + tmp_5); - // '<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); + // '<S1>:1:89' R1=interp2(ParamData.R1d_x,ParamData.R1d_y,ParamData.R1_map,Xhat(1),TemperatureIn); + // '<S1>:1:90' tau=C1*R1; + tmp_4[0] = 15.0; + tmp_4[1] = 25.0; + tmp_4[2] = 35.0; + tmp_4[3] = 45.0; + tau = C1 * EKF_interp2_local_e(f_V, EKF_DW.Xhat[0], EKF_U.TemperatureIn, + (rtNaN), h, tmp_4); + } else { + // '<S1>:1:91' else + // '<S1>:1:92' C1=interp2(ParamDataCh.C1d_x,ParamDataCh.C1d_y,ParamDataCh.C1_map,Xhat(1),TemperatureIn); + tmp_5[0] = 15.0; + tmp_5[1] = 25.0; + tmp_5[2] = 35.0; + tmp_5[3] = 45.0; + C1 = EKF_interp2_local(g_V, EKF_DW.Xhat[0], EKF_U.TemperatureIn, (rtNaN), j, + tmp_5); + + // '<S1>:1:93' R1=interp2(ParamDataCh.R1d_x,ParamDataCh.R1d_y,ParamDataCh.R1_map,Xhat(1),TemperatureIn); + // '<S1>:1:94' tau=C1*R1; + for (UpdateNow = 0; UpdateNow < 17; UpdateNow++) { + tmp_3[UpdateNow] = 0.056249999999999994 * (real_T)UpdateNow + 0.05; + } + + tmp_4[0] = 15.0; + tmp_4[1] = 25.0; + tmp_4[2] = 35.0; + tmp_4[3] = 45.0; + tau = C1 * EKF_interp2_local_e(e_V, EKF_DW.Xhat[0], EKF_U.TemperatureIn, + (rtNaN), tmp_3, tmp_4); + } // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // DISCRETE TIME SS MATRICES - // '<S1>:1:87' Ahat=[1 0 0; - // '<S1>:1:88' 0 exp(-TimeStep/tau) 0; - // '<S1>:1:89' 0 0 1;]; + // '<S1>:1:100' Ahat=[1 0 0; + // '<S1>:1:101' 0 exp(-TimeStep/tau) 0; + // '<S1>:1:102' 0 0 1;]; Ahat[1] = 0.0; Ahat[4] = std::exp(-EKF_U.TimeStep / tau); Ahat[7] = 0.0; @@ -1236,9 +1382,9 @@ Ahat[6] = 0.0; Ahat[8] = 1.0; - // '<S1>:1:92' Bhat=[-TimeStep/(Qhat) - // '<S1>:1:93' TimeStep/C1 - // '<S1>:1:94' 1]; + // '<S1>:1:105' Bhat=[-TimeStep/(Qhat) + // '<S1>:1:106' TimeStep/C1 + // '<S1>:1:107' 1]; Bhat[0] = -EKF_U.TimeStep / EKF_DW.Qhat; Bhat[1] = EKF_U.TimeStep / C1; Bhat[2] = 1.0; @@ -1247,186 +1393,281 @@ // PREDICTION STAGE // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // SOC ESTIMATION FOR CAPACITY ESTIMATION - // '<S1>:1:101' if MacroTime>10*60 - if (EKF_U.MacroTime > 600.0) { - // '<S1>:1:102' SumCC=(Current_prev*TimeStep)+SumCC; + // '<S1>:1:114' if MacroTime>15*60 + if (EKF_U.MacroTime > 900.0) { + // '<S1>:1:115' XhatTh_Update=XhatTh_Update-TimeStep/(Qhat)*Current_prev; + EKF_DW.XhatTh_Update -= EKF_U.TimeStep / EKF_DW.Qhat * EKF_DW.Current_prev; + + // '<S1>:1:116' SumCC=(Current_prev*TimeStep)+SumCC; EKF_DW.SumCC += EKF_DW.Current_prev * EKF_U.TimeStep; - // '<S1>:1:103' AbsSumCC=abs(Current_prev*TimeStep)+AbsSumCC; + // '<S1>:1:117' AbsSumCC=abs(Current_prev*TimeStep)+AbsSumCC; EKF_DW.AbsSumCC += std::abs(EKF_DW.Current_prev * EKF_U.TimeStep); - // '<S1>:1:104' TimeToUpdateQ=TimeToUpdateQ+TimeStep; + // '<S1>:1:118' TimeToUpdateQ=TimeToUpdateQ+TimeStep; EKF_DW.TimeToUpdateQ += EKF_U.TimeStep; } else { - // '<S1>:1:105' else - // '<S1>:1:106' XhatTh=Xhat(1); + // '<S1>:1:119' else + // '<S1>:1:120' XhatTh=Xhat(1); EKF_DW.XhatTh = EKF_DW.Xhat[0]; + + // '<S1>:1:121' XhatTh_Update=Xhat(1); + EKF_DW.XhatTh_Update = EKF_DW.Xhat[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' P0th=P0th+Qth; - EKF_DW.P0th += EKF_DW.Qth; - - // '<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:124' MeasError_Update=Xhat(1)-XhatTh_Update(1); + // ONLY UPDATE IF ERROR IS ABOVE THRESHOLD AND ENOUGH TIME HAS ELAPSED + // '<S1>:1:127' if abs(MeasError_Update)<1.1e-3 + if (std::abs(EKF_DW.Xhat[0] - EKF_DW.XhatTh_Update) < 0.0011) { + // '<S1>:1:129' UpdateNow=0; + UpdateNow = 0; - // '<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:124' P0th=P0th-KGainTh*Cth*KGainTh'; - EKF_DW.P0th -= KGainTh * Cth * KGainTh; - - // '<S1>:1:125' CthPrev=Cth; - EKF_DW.CthPrev = Cth; + // '<S1>:1:130' if TimeToUpdateQ>60*30 + if (EKF_DW.TimeToUpdateQ > 1800.0) { + // '<S1>:1:132' SumCC=0; + EKF_DW.SumCC = 0.0; - // '<S1>:1:127' Qhat/3600; - // '<S1>:1:129' iQ=iQ+1; - EKF_DW.iQ++; + // '<S1>:1:133' AbsSumCC=0; + EKF_DW.AbsSumCC = 0.0; - // '<S1>:1:131' XhatTh=Xhat(1); - EKF_DW.XhatTh = EKF_DW.Xhat[0]; - - // '<S1>:1:133' AbsSumCC=0; - EKF_DW.AbsSumCC = 0.0; + // '<S1>:1:134' XhatTh=Xhat(1); + EKF_DW.XhatTh = EKF_DW.Xhat[0]; - // '<S1>:1:134' SumCC=0; - EKF_DW.SumCC = 0.0; + // '<S1>:1:135' TimeToUpdateQ=0; + EKF_DW.TimeToUpdateQ = 0.0; - // '<S1>:1:135' TimeToUpdateQ=0; - EKF_DW.TimeToUpdateQ = 0.0; - } + // '<S1>:1:136' XhatTh_Update=Xhat(1); + EKF_DW.XhatTh_Update = EKF_DW.Xhat[0]; + } + } else { + // '<S1>:1:139' else + // '<S1>:1:141' UpdateNow=0; + UpdateNow = 0; - // - // PREDICTION FOR STATES - // '<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 (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:142' if TimeToUpdateQ>UpdateQ + if (EKF_DW.TimeToUpdateQ > EKF_DW.UpdateQ) { + // '<S1>:1:143' TimeToUpdateQ=0; + EKF_DW.TimeToUpdateQ = 0.0; - // '<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]; - } + // '<S1>:1:144' UpdateNow=1; + UpdateNow = 1; - 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:145' XhatTh_Update=Xhat(1); + EKF_DW.XhatTh_Update = EKF_DW.Xhat[0]; } } - // '<S1>:1:143' Current_prev=Current; + // '<S1>:1:151' if UpdateNow + if (UpdateNow != 0) { + // if AbsSumCC>1.5e4 + // MACROSCALE EKF FOR CAPACITY ESTIMATION + // '<S1>:1:155' XhatTh=XhatTh-SumCC/(Qhat); + EKF_DW.XhatTh -= EKF_DW.SumCC / EKF_DW.Qhat; + + // '<S1>:1:157' P0th=P0th+Qth; + EKF_DW.P0th += EKF_DW.Qth; + + // '<S1>:1:159' Cth=+SumCC/((Qhat)^2)+ CthPrev; + Cth = EKF_DW.SumCC / (EKF_DW.Qhat * EKF_DW.Qhat) + EKF_DW.CthPrev; + + // '<S1>:1:161' 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:163' MeasError=Xhat(1)-XhatTh(1); + // STORE PREVIOUS VALUES + // '<S1>:1:166' Qhat_old=Qhat; + Qhat_old = EKF_DW.Qhat; + + // '<S1>:1:167' Qrated=53*3600; + // '<S1>:1:169' Qhat=Qhat+KGainTh*(MeasError); + EKF_DW.Qhat += (EKF_DW.Xhat[0] - EKF_DW.XhatTh) * KGainTh; + + // '<S1>:1:170' P0th=P0th-KGainTh*Cth*KGainTh'; + EKF_DW.P0th -= KGainTh * Cth * KGainTh; + + // '<S1>:1:171' CthPrev=Cth; + EKF_DW.CthPrev = Cth; + + // MAKRE SURE THE CAPACITY DOESN'T GO OUT OF SAFETY BOUNDS + // '<S1>:1:174' ErrorQ=abs(Qrated-Qhat)/Qrated; + // '<S1>:1:175' if ErrorQ>0.5 + if (std::abs(190800.0 - EKF_DW.Qhat) / 190800.0 > 0.5) { + // '<S1>:1:176' Qhat=Qhat_old; + EKF_DW.Qhat = Qhat_old; + } + + // '<S1>:1:180' QPrint=Qhat/3600 + // '<S1>:1:181' XhatTh=Xhat(1); + EKF_DW.XhatTh = EKF_DW.Xhat[0]; + + // '<S1>:1:182' iQ=iQ+1; + EKF_DW.iQ++; + + // '<S1>:1:184' AbsSumCC=0; + EKF_DW.AbsSumCC = 0.0; + + // '<S1>:1:185' SumCC=0; + EKF_DW.SumCC = 0.0; + + // '<S1>:1:186' TimeToUpdateQ=0; + EKF_DW.TimeToUpdateQ = 0.0; + + // '<S1>:1:187' UpdateNow=0; + // '<S1>:1:188' disp(' ' ) + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // PREDICTION FOR STATES + // '<S1>:1:194' 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 (UpdateNow = 0; UpdateNow < 3; UpdateNow++) { + Ahat_0[UpdateNow] = ((Ahat[UpdateNow + 3] * EKF_DW.Xhat[1] + Ahat[UpdateNow] + * EKF_DW.Xhat[0]) + Ahat[UpdateNow + 6] * EKF_DW.Xhat + [2]) + Bhat[UpdateNow] * KGain[UpdateNow]; + } + + // '<S1>:1:195' P0=Ahat*P0*Ahat' + Bhat*Q*Bhat'; + for (UpdateNow = 0; UpdateNow < 3; UpdateNow++) { + EKF_DW.Xhat[UpdateNow] = Ahat_0[UpdateNow]; + for (ix = 0; ix < 3; ix++) { + Ahat_1[UpdateNow + 3 * ix] = 0.0; + Ahat_1[UpdateNow + 3 * ix] += EKF_DW.P0[3 * ix] * Ahat[UpdateNow]; + Ahat_1[UpdateNow + 3 * ix] += EKF_DW.P0[3 * ix + 1] * Ahat[UpdateNow + 3]; + Ahat_1[UpdateNow + 3 * ix] += EKF_DW.P0[3 * ix + 2] * Ahat[UpdateNow + 6]; + } + + for (ix = 0; ix < 3; ix++) { + Ahat_2[UpdateNow + 3 * ix] = 0.0; + Ahat_2[UpdateNow + 3 * ix] += Ahat_1[UpdateNow] * Ahat[ix]; + Ahat_2[UpdateNow + 3 * ix] += Ahat_1[UpdateNow + 3] * Ahat[ix + 3]; + Ahat_2[UpdateNow + 3 * ix] += Ahat_1[UpdateNow + 6] * Ahat[ix + 6]; + Bhat_0[UpdateNow + 3 * ix] = Bhat[UpdateNow] * EKF_DW.Q * Bhat[ix]; + } + } + + for (UpdateNow = 0; UpdateNow < 3; UpdateNow++) { + EKF_DW.P0[3 * UpdateNow] = Ahat_2[3 * UpdateNow] + Bhat_0[3 * UpdateNow]; + EKF_DW.P0[1 + 3 * UpdateNow] = Ahat_2[3 * UpdateNow + 1] + Bhat_0[3 * + UpdateNow + 1]; + EKF_DW.P0[2 + 3 * UpdateNow] = Ahat_2[3 * UpdateNow + 2] + Bhat_0[3 * + UpdateNow + 2]; + } + + // '<S1>:1:197' Current_prev=Current; EKF_DW.Current_prev = EKF_U.Current; - // '<S1>:1:145' Ytrue=Voltage; + // '<S1>:1:199' Ytrue=Voltage; // ESTIMATION STAGE // INTERPOLATE CORRECT VALUES - // '<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)); + // '<S1>:1:205' if Current>0 + if (EKF_U.Current > 0.0) { + // '<S1>:1:206' OCVatSOC=interp2(ParamData.OCVdatad_x,ParamData.OCVdatad_y,ParamData.OCVdata_map,Xhat(1),TemperatureIn); + tmp_2[0] = 15.0; + tmp_2[1] = 25.0; + tmp_2[2] = 35.0; + tmp_2[3] = 45.0; + Cth = EKF_interp2_local_el(d_V, EKF_DW.Xhat[0], EKF_U.TemperatureIn, (rtNaN), + e, tmp_2); + + // '<S1>:1:207' dOCVatSOC=interp2(ParamData.dOCVdatad_x,ParamData.dOCVdatad_y,ParamData.dOCVdata_map,Xhat(1),TemperatureIn); + tmp_1[0] = 15.0; + tmp_1[1] = 25.0; + tmp_1[2] = 35.0; + tmp_1[3] = 45.0; + KGainTh = EKF_interp2_local_el(b_V, EKF_DW.Xhat[0], EKF_U.TemperatureIn, + (rtNaN), e, tmp_1); + } else { + // '<S1>:1:208' else + // '<S1>:1:209' OCVatSOC=interp2(ParamDataCh.OCVdatad_x,ParamDataCh.OCVdatad_y,ParamDataCh.OCVdata_map,Xhat(1),TemperatureIn); + tmp_2[0] = 15.0; + tmp_2[1] = 25.0; + tmp_2[2] = 35.0; + tmp_2[3] = 45.0; + Cth = EKF_interp2_local_el(c_V, EKF_DW.Xhat[0], EKF_U.TemperatureIn, (rtNaN), + d, tmp_2); + + // '<S1>:1:210' dOCVatSOC=interp2(ParamDataCh.dOCVdatad_x,ParamDataCh.dOCVdatad_y,ParamDataCh.dOCVdata_map,Xhat(1),TemperatureIn); + tmp_1[0] = 15.0; + tmp_1[1] = 25.0; + tmp_1[2] = 35.0; + tmp_1[3] = 45.0; + KGainTh = EKF_interp2_local_el(V, EKF_DW.Xhat[0], EKF_U.TemperatureIn, + (rtNaN), d, tmp_1); + } + + // '<S1>:1:214' Yhat=OCVatSOC -Xhat(2) -exp(Xhat(3))*Current; + // '<S1>:1:215' C=[dOCVatSOC -1 -exp(Xhat(3))*Current]; + C[0] = KGainTh; C[1] = -1.0; C[2] = -std::exp(EKF_DW.Xhat[2]) * EKF_U.Current; - // '<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:216' KGain=P0*C'*(C*P0*C'+R)^-1; + Qhat_old = 0.0; + for (UpdateNow = 0; UpdateNow < 3; UpdateNow++) { + Qhat_old += (EKF_DW.P0[3 * UpdateNow + 2] * C[2] + (-EKF_DW.P0[3 * UpdateNow + + 1] + EKF_DW.P0[3 * UpdateNow] * KGainTh)) * C[UpdateNow]; } - 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; - } + KGainTh = 1.0 / (Qhat_old + EKF_DW.R); - // '<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]) * + // '<S1>:1:217' Xhat=Xhat+KGain*(Ytrue-Yhat); + Cth = EKF_U.Voltage - ((Cth - 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]; + // '<S1>:1:218' P0=P0-KGain*(C*P0*C'+R)*KGain'; + Qhat_old = 0.0; + for (UpdateNow = 0; UpdateNow < 3; UpdateNow++) { + dOCVatSOC_power = (EKF_DW.P0[UpdateNow + 6] * C[2] + (-EKF_DW.P0[UpdateNow + + 3] + EKF_DW.P0[UpdateNow] * C[0])) * KGainTh; + EKF_DW.Xhat[UpdateNow] += dOCVatSOC_power * Cth; + Qhat_old += (EKF_DW.P0[3 * UpdateNow + 2] * C[2] + (-EKF_DW.P0[3 * UpdateNow + + 1] + EKF_DW.P0[3 * UpdateNow] * C[0])) * C[UpdateNow]; + KGain[UpdateNow] = dOCVatSOC_power; } - 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]; + Cth = Qhat_old + EKF_DW.R; + for (UpdateNow = 0; UpdateNow < 3; UpdateNow++) { + EKF_DW.P0[UpdateNow] -= KGain[UpdateNow] * Cth * KGain[0]; + EKF_DW.P0[UpdateNow + 3] -= KGain[UpdateNow] * Cth * KGain[1]; + EKF_DW.P0[UpdateNow + 6] -= KGain[UpdateNow] * Cth * KGain[2]; } // R0 FILTER - // '<S1>:1:164' if abs(Current-Current_prev_R)>5 + // '<S1>:1:223' 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)); + // '<S1>:1:225' 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:167' R0_filt_prev=R0_filt; + // '<S1>:1:226' R0_filt_prev=R0_filt; EKF_DW.R0_filt_prev = Cth; } else { - // '<S1>:1:168' else - // '<S1>:1:169' R0_filt=R0_filt_prev; + // '<S1>:1:227' else + // '<S1>:1:228' R0_filt=R0_filt_prev; Cth = EKF_DW.R0_filt_prev; } - // '<S1>:1:174' [~,~,DegradationIndex]=InterpolateR0(Xhat(1),TemperatureIn, R0_filt,ParamData); - EKF_InterpolateR0(EKF_DW.Xhat[0], EKF_U.TemperatureIn, Cth, &OCVatSOC_power, + // '<S1>:1:233' [~,~,DegradationIndex]=InterpolateR0(Xhat(1),TemperatureIn, R0_filt,ParamData); + EKF_InterpolateR0(EKF_DW.Xhat[0], EKF_U.TemperatureIn, Cth, &Qhat_old, &dOCVatSOC_power, &KGainTh); - // '<S1>:1:174' ~ - // + // '<S1>:1:233' ~ // POWER ESTIMATION - // '<S1>:1:178' if MacroTime>UpdatePower*iP + // '<S1>:1:237' if MacroTime>UpdatePower*iP if (EKF_U.MacroTime > EKF_DW.UpdatePower * EKF_DW.iP) { - // '<S1>:1:180' Current_prev_R=Current; + // '<S1>:1:239' Current_prev_R=Current; EKF_DW.Current_prev_R = EKF_U.Current; - // '<S1>:1:182' Power.Ahat=Ahat; + // '<S1>:1:241' Power.Ahat=Ahat; memcpy(&EKF_DW.Power.Ahat[0], &Ahat[0], 9U * sizeof(real_T)); - // '<S1>:1:183' Power.Bhat=Bhat; - // '<S1>:1:184' Power.Temp=TemperatureIn; + // '<S1>:1:242' Power.Bhat=Bhat; + // '<S1>:1:243' Power.Temp=TemperatureIn; EKF_DW.Power.Temp = EKF_U.TemperatureIn; - // '<S1>:1:185' Power.Xhat_=Xhat; + // '<S1>:1:244' 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]; @@ -1434,62 +1675,90 @@ EKF_DW.Power.Bhat[2] = 1.0; EKF_DW.Power.Xhat_[2] = EKF_DW.Xhat[2]; - // '<S1>:1:186' Power.TimeStep=TimeStep; + // '<S1>:1:245' Power.TimeStep=TimeStep; EKF_DW.Power.TimeStep = EKF_U.TimeStep; - // '<S1>:1:187' Power.Iterations=50; + // '<S1>:1:246' Power.Iterations=50; EKF_DW.Power.Iterations = 50.0; // 50 iterations at 0.2s time step is 10seconds - // '<S1>:1:188' Power.R0=R0_filt; + // '<S1>:1:247' Power.R0=R0_filt; EKF_DW.Power.R0 = Cth; - // '<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:249' iChSOC=(Xhat(1)-Power.MaxSOC)*(Qhat)/(Power.TimeWindow); + // '<S1>:1:250' iDischSOC=(Xhat(1)-Power.MinSOC)*(Qhat)/(Power.TimeWindow); + // '<S1>:1:252' if Current>0 + if (EKF_U.Current > 0.0) { + // '<S1>:1:253' OCVatSOC_power=interp2(ParamData.OCVdatad_x,ParamData.OCVdatad_y,ParamData.OCVdata_map,Xhat(1),TemperatureIn); + tmp_0[0] = 15.0; + tmp_0[1] = 25.0; + tmp_0[2] = 35.0; + tmp_0[3] = 45.0; + Qhat_old = EKF_interp2_local_el(d_V, EKF_DW.Xhat[0], EKF_U.TemperatureIn, + (rtNaN), e, tmp_0); - // '<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:254' dOCVatSOC_power=interp2(ParamData.dOCVdatad_x,ParamData.dOCVdatad_y,ParamData.dOCVdata_map,Xhat(1),TemperatureIn); + tmp[0] = 15.0; + tmp[1] = 25.0; + tmp[2] = 35.0; + tmp[3] = 45.0; + dOCVatSOC_power = EKF_interp2_local_el(b_V, EKF_DW.Xhat[0], + EKF_U.TemperatureIn, (rtNaN), e, tmp); + } else { + // '<S1>:1:255' else + // '<S1>:1:256' OCVatSOC_power=interp2(ParamDataCh.OCVdatad_x,ParamDataCh.OCVdatad_y,ParamDataCh.OCVdata_map,Xhat(1),TemperatureIn); + tmp_0[0] = 15.0; + tmp_0[1] = 25.0; + tmp_0[2] = 35.0; + tmp_0[3] = 45.0; + Qhat_old = EKF_interp2_local_el(c_V, EKF_DW.Xhat[0], EKF_U.TemperatureIn, + (rtNaN), d, tmp_0); - // '<S1>:1:196' A=exp(-Power.TimeWindow/tau); + // '<S1>:1:257' dOCVatSOC_power=interp2(ParamDataCh.dOCVdatad_x,ParamDataCh.dOCVdatad_y,ParamDataCh.dOCVdata_map,Xhat(1),TemperatureIn); + tmp[0] = 15.0; + tmp[1] = 25.0; + tmp[2] = 35.0; + tmp[3] = 45.0; + dOCVatSOC_power = EKF_interp2_local_el(V, EKF_DW.Xhat[0], + EKF_U.TemperatureIn, (rtNaN), d, tmp); + } + + // '<S1>:1:260' A=exp(-Power.TimeWindow/tau); A = std::exp(-EKF_DW.Power.TimeWindow / tau); - // '<S1>:1:197' PolynomialA=0; + // '<S1>:1:261' PolynomialA=0; PolynomialA = 0.0; - // '<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:262' for i=0:1:(Power.Iterations-1) + for (UpdateNow = 0; UpdateNow < (int16_T)((EKF_DW.Power.Iterations - 1.0) + + 1.0); UpdateNow++) { + // '<S1>:1:263' PolynomialA=PolynomialA+A^i; + PolynomialA += rt_powd_snf(A, (real_T)UpdateNow); } - // '<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]); + // '<S1>:1:266' iDischOCV=(OCVatSOC_power-Xhat(2)*exp(-Power.TimeWindow/tau)-Power.Vmin)/... + // '<S1>:1:267' ((Power.TimeWindow/(Qhat))*dOCVatSOC_power+... + // '<S1>:1:268' (Power.TimeStep/C1)*PolynomialA+... + // '<S1>:1:269' Power.R0); + // '<S1>:1:271' iChOCV=(OCVatSOC_power-Xhat(2)*exp(-Power.TimeWindow/tau)-Power.Vmax)/... + // '<S1>:1:272' ((Power.TimeWindow/(Qhat))*dOCVatSOC_power+... + // '<S1>:1:273' (Power.TimeStep/C1)*PolynomialA+... + // '<S1>:1:274' Power.R0); + // '<S1>:1:276' IMaxDisch=min([Power.iMaxDisch; iDischOCV; iDischSOC]); Bhat[0] = EKF_DW.Power.iMaxDisch; - Bhat[1] = ((OCVatSOC_power - std::exp(-EKF_DW.Power.TimeWindow / tau) * + Bhat[1] = ((Qhat_old - 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; - ixstart = 1; + UpdateNow = 1; A = EKF_DW.Power.iMaxDisch; if (rtIsNaN(EKF_DW.Power.iMaxDisch)) { ix = 2; exitg2 = false; while ((!exitg2) && (ix < 4)) { - ixstart = ix; + UpdateNow = ix; if (!rtIsNaN(Bhat[ix - 1])) { A = Bhat[ix - 1]; exitg2 = true; @@ -1499,31 +1768,31 @@ } } - if (ixstart < 3) { - while (ixstart + 1 < 4) { - if (Bhat[ixstart] < A) { - A = Bhat[ixstart]; + if (UpdateNow < 3) { + while (UpdateNow + 1 < 4) { + if (Bhat[UpdateNow] < A) { + A = Bhat[UpdateNow]; } - ixstart++; + UpdateNow++; } } - // '<S1>:1:213' IMaxCh=max([Power.iMaxCh;iChOCV;iChSOC]); + // '<S1>:1:277' IMaxCh=max([Power.iMaxCh;iChOCV;iChSOC]); Bhat[0] = EKF_DW.Power.iMaxCh; - Bhat[1] = ((OCVatSOC_power - std::exp(-EKF_DW.Power.TimeWindow / tau) * + Bhat[1] = ((Qhat_old - 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; - ixstart = 1; + UpdateNow = 1; C1 = EKF_DW.Power.iMaxCh; if (rtIsNaN(EKF_DW.Power.iMaxCh)) { ix = 2; exitg1 = false; while ((!exitg1) && (ix < 4)) { - ixstart = ix; + UpdateNow = ix; if (!rtIsNaN(Bhat[ix - 1])) { C1 = Bhat[ix - 1]; exitg1 = true; @@ -1533,43 +1802,43 @@ } } - if (ixstart < 3) { - while (ixstart + 1 < 4) { - if (Bhat[ixstart] > C1) { - C1 = Bhat[ixstart]; + if (UpdateNow < 3) { + while (UpdateNow + 1 < 4) { + if (Bhat[UpdateNow] > C1) { + C1 = Bhat[UpdateNow]; } - ixstart++; + UpdateNow++; } } - // '<S1>:1:215' VoltTermDisch=PredictTerminalVoltage(IMaxDisch,Power); - // '<S1>:1:216' VoltTermCh=PredictTerminalVoltage(IMaxCh,Power); - // '<S1>:1:218' PowerDischHat=abs(IMaxDisch*VoltTermDisch); + // '<S1>:1:279' VoltTermDisch=PredictTerminalVoltage(IMaxDisch,Power); + // '<S1>:1:280' VoltTermCh=PredictTerminalVoltage(IMaxCh,Power); + // '<S1>:1:282' 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:219' PowerChHat=abs(IMaxCh*VoltTermCh); + // '<S1>:1:283' 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:220' iP=iP+1; + // '<S1>:1:284' iP=iP+1; EKF_DW.iP++; } - // + // '<S1>:1:288' if isnan(Xhat(1)) // MAKE SURE SOC IS WITHIN LIMITS - // '<S1>:1:226' if Xhat(1)>1 + // '<S1>:1:292' if Xhat(1)>1 if (EKF_DW.Xhat[0] > 1.0) { - // '<S1>:1:227' Xhat(1)=1; + // '<S1>:1:293' Xhat(1)=1; EKF_DW.Xhat[0] = 1.0; } - // '<S1>:1:230' if Xhat(1)<0 + // '<S1>:1:296' if Xhat(1)<0 if (EKF_DW.Xhat[0] < 0.0) { - // '<S1>:1:231' Xhat(1)=0; + // '<S1>:1:297' Xhat(1)=0; EKF_DW.Xhat[0] = 0.0; } @@ -1577,11 +1846,11 @@ // MATLAB Function: '<Root>/MATLAB Function' // OUTPUT THE VALUES - // '<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; + // '<S1>:1:301' SOC=Xhat(1); + // '<S1>:1:302' Q0=Qhat/3600; + // '<S1>:1:303' R0=R0_filt; + // '<S1>:1:304' PowerDisch=PowerDischHat; + // '<S1>:1:305' PowerCh=PowerChHat; EKF_Y.SOC = EKF_DW.Xhat[0]; // Outport: '<Root>/Q0' incorporates: @@ -1637,15 +1906,17 @@ }; // SystemInitialize for MATLAB Function: '<Root>/MATLAB Function' - EKF_DW.Xhat[0] = 0.85; + EKF_DW.Xhat[0] = 0.8; 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.Current_prev = 0.0; EKF_DW.Q = 1.0; + EKF_DW.R = 0.01; EKF_DW.Qhat = 190800.0; EKF_DW.XhatTh = 0.0; + EKF_DW.XhatTh_Update = 0.0; EKF_DW.CthPrev = 0.0; EKF_DW.iQ = 1.0; EKF_DW.SumCC = 0.0;