Main Content

Battery Second-life Application State of Health (SoH) Estimation of Li-ion Batteries

Traction batteries (such as EV batteries) have very specific energy and power requirements. The batteries must meet performance standards such as maintaining 80 percent of total usable capacity and a resting self-discharge rate of only about 5 percent over a 24-hour period. The batteries are subjected to extreme operating temperatures, large number of partial cycles, and changing discharge rates. These conditions cause significant battery degradation during the first few years of operation. To ensure safe operation, traction battery applications include expensive data collection and health monitoring systems which can compute capacity and state of health (SoH) accurately. When the battery can no longer meet these performance requirements, they are deemed to have reached End-of-Life status for the traction application.

However, a battery that has end-of-life status for the traction application can have a "second life" in less demanding applications such as smart grid (stationary) or low power electric vehicles such as golf carts. Second-life applications do not typically have access to an extensive measurement and monitoring infrastructure, but some level of monitoring is still necessary to prevent catastrophic failures.

This example shows an approach to monitoring second-life performance by estimating SoH using the measurements taken during first-life and only terminal voltage during second life. The approach uses a support vector regression (SVR) model to learn the relationship between extracted features and the discharge capacity of the battery during its first life. During its second life, the trained model is then used to estimate the SoH. For this example, SoH is defined to be energy focused and not for power delivery. When the SoH is low, the battery may not be able to provide enough charge for certain operations, and this may lead to application failure. Incorporating this SoH estimate can improve the accuracy of remaining useful life (RUL) predictions and provide more reliable estimation of a battery’s remaining capacity.

Dataset

NASA's battery aging data is used in this example. The dataset contains measurements from commercially available Li-ion 18650 sized rechargeable batteries with rated capacity of 2 Ah at room temperature. The batteries are subjected to charge, constant current discharge, and electrochemical impedance spectroscopy cycles. These repeated charge and discharge cycles result in accelerated aging of the batteries while impedance measurements provide insight into the internal battery parameters that change as aging progresses. A total of 168 charging cycles are performed for battery cells B0005, B0006 and B0007. However, measurements for some cycles are incomplete, either because of incomplete measurement or repeated charging cycles without discharge. Measurements related to such incomplete cycles are removed before analysis. The data used in this example has been processed to contain only measurements related to normal cycles and those relevant to the features being extracted, such as, battery terminal voltage during charge/discharge of cycles. The original full dataset with detailed description can be accessed here [2].

The dataset contains measurements for three batteries titled B0005, B0006 and B0007. For this example, the data is assumed to represent batteries that are used for second life application. Measurements for the first 100 cycles is assumed to represent the first-life usage of the batteries. The remaining cycles are assumed to represent the measurements during their second-life application. Load the data from the MathWorks support files site (about ~47 MB):

url = 'https://ssd.mathworks.com/supportfiles/predmaint/batteryagingdata/nasa/BatteryAgingData.zip';
websave('BatteryAgingData.zip',url);
unzip('BatteryAgingData.zip')
load('B0005.mat')
load('B0006.mat')
load('B0007.mat')

Extract the voltage measurements corresponding to charge, discharge cycle and capacity for each cycle for battery B0005 dataset.

[B5_d, B5_c, C_B05] = hExtractChargeDischargeCycles(B0005);

To see the degradation of the battery's charge, discharge performance across cycles, plot the voltage over cycle numbers for charge cycle. The spread in the curves indicates that as the battery ages, the time taken to go from beginning of charge to 4.2 V increases. Similarly, the time taken for the battery to discharge decreases.

num_partial_cycles = 163;
figure; tiledlayout(2,1)
nexttile;
hold on
for i = 1:num_partial_cycles-1
plot(B5_c(i).t,B5_c(i).measuredV)
end
title('B0005 Voltage during Charging')
xlabel('Time [s]')
ylabel('Voltage')

nexttile
hold on;
for i = 1:num_partial_cycles-1
plot(B5_d(i).t,B5_d(i).measuredV)
end
title('B0005 Voltage during Discharging')
xlabel('Time [s]')
ylabel('Voltage')

Figure contains 2 axes objects. Axes object 1 with title B0005 Voltage during Charging, xlabel Time [s], ylabel Voltage contains 162 objects of type line. Axes object 2 with title B0005 Voltage during Discharging, xlabel Time [s], ylabel Voltage contains 162 objects of type line.

Split the data into the first and second life related measurements using the hDataSplitter and hCapacitySplitter helper functions:

num_cycles_FirstLife = 100;
[B5_d_first, B5_c_first, B5_d_second, B5_c_second] = hDataSplitter(B5_d, B5_c, num_cycles_FirstLife);
[C_B05_first, C_B05_second] = hCapacitySplitter(C_B05, num_cycles_FirstLife);

Feature Extraction and State of Health

Measurement of maximum deliverable capacity for batteries in operation is difficult because the cells are not likely to be fully charged or discharged during operation. For such applications, two features that function as health indicators (HI) are computed with partial information are defined as:

  • Time Interval of an Equal Charging Voltage Difference (TIECVD) and

  • Time Interval of an Equal Discharging Voltage Difference (TIEDVD)

The selected features also fade with battery ageing, following the trend displayed by capacity fade. For charging voltage measurements, TIECVD is computed as the time interval taken to charge from 3.5 V to 4.2 V. For discharge voltage measurement, TIEDVD is computed as the time taken to discharge from 3.8 V and 3.6 V [1]. It is important to note that, for this data, the discharge is under constant current, which allows for TIEDVD to be a useful health indicator. If this is not the case, and discharge is based on a dynamic current profile instead, TIECVD alone must be used as a health indicator for SOH estimation, providing that the charge protocol is mostly fixed.

Compute the TIECVD/TIEDVD features for each battery using the helper function hFeatureExtraction. The helper function identifies the exact time instances, using interpolation, for each voltage value in the charge and discharge cycle and computes the features using the time stamps.

[TIECVD_B5_first, TIEDVD_B5_first] = hFeatureExtraction(B5_d_first, B5_c_first);

The definition of battery's SoH used in this example is:

SoH=CiC0

where Ci is the nominal capacity of the ith cycle and C0 is the initial (rated) nominal capacity. The rated capacity of the cells in this dataset is 2 Ah.

rated_C = 2;
SoH_B05_first = C_B05_first/rated_C;

Plot the computed features (TIECVD, TIEDVD) and the SoH of the batteries during their first life to visualize their trends.

figure;
nexttile;
title('Computed Features');
cyc_num = 1:num_cycles_FirstLife; 
yyaxis left
plot(cyc_num,TIECVD_B5_first); hold on;
ylabel('TIECVD');
yyaxis right
plot(cyc_num,TIEDVD_B5_first, '-.');
ylabel('TIEDVD');
xlabel('Cycle Number')

nexttile
plot(cyc_num,SoH_B05_first);
ylabel('SoH')
xlabel('Cycle Number')

Figure contains 2 axes objects. Axes object 1 with title Computed Features, xlabel Cycle Number, ylabel TIEDVD contains an object of type line. Axes object 2 with xlabel Cycle Number, ylabel SoH contains an object of type line.

As seen in the plot, the curves of TIECVD/TIEDVD share similar characteristics with SoH with respect to the decreasing trend over cycle number. Given the similarity in trend and their ability to be computed online, these two HIs are suitable for battery health monitoring.

Model Development: Battery B0005

To develop and test the model, start by using only the measurements for battery B0005. Training data is defined to be the features computed for the first-life as predictors and SoH as response variable. Define predictors_first to be a 100x2 array with features and response_first to be the corresponding SoH values.

%% Partition of training dataset
predictors_first = [TIECVD_B5_first, TIEDVD_B5_first];
response_first = SoH_B05_first;

Support vector regression (SVR) model is considered to be a nonparametric model that works well for estimation, especially when the size of the training dataset is limited. Fit an SVR model with a Gaussian kernel to build a nonlinear model for this regression problem and set the standardize option to be true to remove bias due to feature range differences. To further improve the fit, enable hyper parameter optimization as a part of the fit with five-fold cross validation and an iteration limit of 1000. Addtionally, vary the KernelFunction, NumGridDivisions, Kfold and IterationLimit to optimize the model training if required:

rng 'default'  % For reproducibility

sohEstimator = fitrsvm(predictors_first, response_first,...
    'KernelFunction', 'gaussian', ...
    'Standardize', true, ...
    'OptimizeHyperparameters', {'BoxConstraint','KernelScale','Epsilon'}, ...
    'HyperparameterOptimizationOptions', ...
    struct('AcquisitionFunctionName', 'expected-improvement-plus', ... 
    'NumGridDivisions', 2,...
    'Repartition',true, ... 
    'Kfold', 5), ...
    'IterationLimit', 1000,...
     'Verbose', 0)
|====================================================================================================================|
| Iter | Eval   | Objective:  | Objective   | BestSoFar   | BestSoFar   | BoxConstraint|  KernelScale |      Epsilon |
|      | result | log(1+loss) | runtime     | (observed)  | (estim.)    |              |              |              |
|====================================================================================================================|
|    1 | Best   |  1.5539e-05 |     0.10516 |  1.5539e-05 |  1.5539e-05 |        389.3 |       265.43 |    0.0028433 |
|    2 | Accept |   0.0040668 |     0.03304 |  1.5539e-05 |   0.0010534 |    0.0054226 |       442.27 |     0.011337 |
|    3 | Accept |   0.0037582 |    0.033999 |  1.5539e-05 |  1.5937e-05 |     0.067844 |       65.331 |       6.9157 |
|    4 | Accept |    0.003956 |    0.040473 |  1.5539e-05 |   1.585e-05 |    0.0023879 |     0.028332 |    0.0052383 |
|    5 | Accept |  7.7651e-05 |    0.057992 |  1.5539e-05 |  1.7284e-05 |        996.4 |        17.83 |    0.0026153 |
|    6 | Accept |   0.0037452 |    0.049594 |  1.5539e-05 |  1.6816e-05 |       134.97 |       672.99 |       6.9407 |
|    7 | Accept |   7.598e-05 |    0.055592 |  1.5539e-05 |  1.7073e-05 |       222.81 |      0.22209 |   0.00037215 |
|    8 | Accept |       3e-05 |    0.042924 |  1.5539e-05 |  1.8492e-05 |       448.06 |       638.11 |    0.0010905 |
|    9 | Accept |  0.00043334 |    0.053488 |  1.5539e-05 |  2.3524e-06 |       64.485 |     0.084699 |   0.00093171 |
|   10 | Best   |  1.3095e-05 |    0.059267 |  1.3095e-05 | -1.2851e-06 |       995.78 |       80.314 |   8.6299e-05 |
|   11 | Accept |  2.4137e-05 |    0.037968 |  1.3095e-05 |  1.3126e-05 |       987.57 |       822.39 |   0.00035152 |
|   12 | Accept |  2.9806e-05 |    0.055035 |  1.3095e-05 |   1.392e-05 |       423.02 |       0.4131 |    8.501e-05 |
|   13 | Accept |   2.094e-05 |    0.054654 |  1.3095e-05 |  1.3832e-05 |       607.61 |        35.93 |   0.00018044 |
|   14 | Accept |   0.0037051 |    0.051225 |  1.3095e-05 |   1.459e-05 |       948.96 |    0.0011719 |     8.66e-05 |
|   15 | Accept |  6.3913e-05 |    0.049671 |  1.3095e-05 |  1.4559e-05 |       51.692 |       1.4492 |   0.00029729 |
|   16 | Best   |  1.2642e-05 |     0.05355 |  1.2642e-05 |  9.6273e-06 |       983.46 |       159.08 |   0.00091218 |
|   17 | Accept |   0.0018647 |    0.046543 |  1.2642e-05 | -6.1872e-05 |       990.53 |       2.2723 |   0.00020367 |
|   18 | Accept |  2.8865e-05 |    0.053312 |  1.2642e-05 |  1.1849e-05 |       185.39 |       14.014 |    9.338e-05 |
|   19 | Accept |  0.00032776 |    0.060783 |  1.2642e-05 | -4.4338e-05 |       187.57 |       4.0932 |   0.00052237 |
|   20 | Accept |  2.2385e-05 |    0.061404 |  1.2642e-05 |  1.1545e-05 |       315.97 |       29.712 |   8.9045e-05 |
|====================================================================================================================|
| Iter | Eval   | Objective:  | Objective   | BestSoFar   | BestSoFar   | BoxConstraint|  KernelScale |      Epsilon |
|      | result | log(1+loss) | runtime     | (observed)  | (estim.)    |              |              |              |
|====================================================================================================================|
|   21 | Best   |  1.1046e-05 |    0.054684 |  1.1046e-05 |  1.0888e-05 |       43.682 |        18.38 |    0.0023825 |
|   22 | Accept |  1.4636e-05 |    0.053322 |  1.1046e-05 |   1.089e-05 |       61.404 |      0.35571 |   8.9047e-05 |
|   23 | Accept |  2.1806e-05 |    0.050161 |  1.1046e-05 |  1.0903e-05 |        120.8 |       258.78 |   8.8732e-05 |
|   24 | Accept |  1.4471e-05 |    0.045448 |  1.1046e-05 |  1.1249e-05 |       208.85 |       20.219 |    0.0049899 |
|   25 | Accept |  1.4229e-05 |    0.062038 |  1.1046e-05 |   1.137e-05 |       15.671 |       6.5133 |   0.00011363 |
|   26 | Accept |  2.2702e-05 |    0.045938 |  1.1046e-05 |  1.1396e-05 |       26.456 |       3.8853 |    0.0067623 |
|   27 | Accept |  0.00045901 |    0.049269 |  1.1046e-05 |  1.1387e-05 |       704.89 |     0.071033 |   8.4727e-05 |
|   28 | Accept |  1.2937e-05 |    0.044548 |  1.1046e-05 |  1.1283e-05 |       689.61 |       325.67 |   0.00012739 |
|   29 | Accept |  1.4657e-05 |    0.045165 |  1.1046e-05 | -1.7121e-05 |       60.999 |       9.7962 |   0.00066073 |
|   30 | Accept |  1.1635e-05 |    0.046303 |  1.1046e-05 | -1.0894e-05 |       108.14 |       71.316 |   0.00041087 |

__________________________________________________________
Optimization completed.
MaxObjectiveEvaluations of 30 reached.
Total function evaluations: 30
Total elapsed time: 9.1739 seconds
Total objective function evaluation time: 1.5526

Best observed feasible point:
    BoxConstraint    KernelScale     Epsilon 
    _____________    ___________    _________

       43.682           18.38       0.0023825

Observed objective function value = 1.1046e-05
Estimated objective function value = 2.4834e-05
Function evaluation time = 0.054684

Best estimated feasible point (according to models):
    BoxConstraint    KernelScale     Epsilon  
    _____________    ___________    __________

       60.999          9.7962       0.00066073

Estimated objective function value = -1.0894e-05
Estimated function evaluation time = 0.051692

Figure contains an axes object. The axes object with title Min objective vs. Number of function evaluations, xlabel Function evaluations, ylabel Min objective contains 2 objects of type line. These objects represent Min observed objective, Estimated min objective.

sohEstimator = 
  RegressionSVM
                         ResponseName: 'Y'
                CategoricalPredictors: []
                    ResponseTransform: 'none'
                                Alpha: [63×1 double]
                                 Bias: 0.8078
                     KernelParameters: [1×1 struct]
                                   Mu: [2.7856e+03 788.3715]
                                Sigma: [393.9771 112.4298]
                      NumObservations: 100
    HyperparameterOptimizationResults: [1×1 BayesianOptimization]
                       BoxConstraints: [100×1 double]
                      ConvergenceInfo: [1×1 struct]
                      IsSupportVector: [100×1 logical]
                               Solver: 'SMO'


  Properties, Methods

After fitting the model on data from the first life, validate the model performance for second life.

[TIECVD_B5_second, TIEDVD_B5_second] = hFeatureExtraction(B5_d_second, B5_c_second);

predictors_second = [TIECVD_B5_second, TIEDVD_B5_second];
SoH_B05_second = C_B05_second/rated_C;
cycles_second = num_cycles_FirstLife+1:numel(C_B05);

% Store the predicted signal
SoH_B05_second_estimate = predict(sohEstimator,predictors_second);

Performance evaluation of the trained model

To evaluate the result, predict and compute the RMSE of the estimated SoH.

RMSE_B05 = rmse(SoH_B05_second, SoH_B05_second_estimate);

Visualize the predicted vs. actual cycle life plot for the test data.

plot(cycles_second, SoH_B05_second)
hold on
plot(cycles_second, SoH_B05_second_estimate)
legend('Actual','Estimated')
title('SoH Estimation Plot')
xlabel('Cycle Number')
ylabel('SoH')

Figure contains an axes object. The axes object with title SoH Estimation Plot, xlabel Cycle Number, ylabel SoH contains 2 objects of type line. These objects represent Actual, Estimated.

The plot indicates that SoH during the second life application of the cell can be estimated with reasonable accuracy by using the TIECVD/TIEDVD features and the SVR model trained on measurements from the first life application. Apply this approach to the data measured from batteries B0006 and B0007 to estimate its robustness.

Datasets B0006 and B0007

Use the hTrainandEstimateSoH helper function to estimate the SoH for the second life application of batteries B0006 and B0007. The helper function implements the algorithm used above to:

  • Split the data into the first 100 cycles corresponding to the first life application

  • Compute first life features and SoH

  • Train SVR model

  • Compute second life features

  • Use the trained SVR model to estimate SoH for second life

[SoH_B06_second_estimate, SoH_B06_second] = hTrainandEstimateSoH(B0006, rated_C, num_cycles_FirstLife);
|====================================================================================================================|
| Iter | Eval   | Objective:  | Objective   | BestSoFar   | BestSoFar   | BoxConstraint|  KernelScale |      Epsilon |
|      | result | log(1+loss) | runtime     | (observed)  | (estim.)    |              |              |              |
|====================================================================================================================|
|    1 | Best   |  0.00024122 |    0.033801 |  0.00024122 |  0.00024122 |        389.3 |       265.43 |    0.0046115 |
|    2 | Accept |   0.0097686 |    0.034029 |  0.00024122 |   0.0007434 |    0.0054226 |       442.27 |     0.018387 |
|    3 | Accept |   0.0095499 |     0.03261 |  0.00024122 |  0.00024217 |     0.067844 |       65.331 |       11.217 |
|    4 | Accept |   0.0092904 |    0.041413 |  0.00024122 |  0.00024195 |    0.0023879 |     0.028332 |    0.0084959 |
|    5 | Accept |  0.00043162 |    0.052396 |  0.00024122 |  0.00024479 |        996.4 |        17.83 |    0.0042417 |
|    6 | Accept |   0.0094303 |    0.040545 |  0.00024122 |  0.00024438 |       116.36 |     0.074558 |       13.431 |
|    7 | Accept |   0.0006513 |    0.043623 |  0.00024122 |  0.00024495 |       197.41 |       2.0914 |   0.00068973 |
|    8 | Accept |  0.00041452 |    0.057163 |  0.00024122 |  0.00026162 |       379.79 |       11.905 |    0.0021695 |
|    9 | Accept |   0.0086021 |    0.044688 |  0.00024122 |  0.00026052 |       5.2894 |    0.0042352 |    0.0001373 |
|   10 | Accept |   0.0088877 |    0.049162 |  0.00024122 |  0.00024338 |       997.82 |    0.0010322 |    0.0001659 |
|   11 | Best   |  0.00023035 |    0.042445 |  0.00023035 |  0.00022936 |       732.36 |       341.03 |   0.00015764 |
|   12 | Accept |  0.00051901 |    0.052522 |  0.00023035 |  0.00023147 |       812.46 |       11.425 |   0.00013759 |
|   13 | Accept |  0.00023619 |     0.03848 |  0.00023035 |  0.00023285 |       982.58 |       707.43 |    0.0014581 |
|   14 | Accept |  0.00023873 |    0.050167 |  0.00023035 |   0.0002301 |       801.69 |       143.45 |   0.00099428 |
|   15 | Accept |  0.00094575 |    0.047346 |  0.00023035 |  0.00016785 |       162.76 |       802.42 |   0.00017887 |
|   16 | Accept |   0.0094081 |    0.041377 |  0.00023035 |  0.00023272 |       965.93 |       939.91 |      0.33062 |
|   17 | Accept |  0.00036641 |    0.055211 |  0.00023035 |  0.00023481 |       770.72 |       39.744 |   0.00031545 |
|   18 | Accept |  0.00024109 |    0.052571 |  0.00023035 |  0.00022796 |       887.66 |       175.28 |    0.0031477 |
|   19 | Accept |  0.00025107 |     0.04792 |  0.00023035 |  0.00022907 |       220.11 |       199.87 |    0.0021109 |
|   20 | Accept |  0.00023522 |    0.040778 |  0.00023035 |  0.00022808 |        857.2 |        476.1 |   0.00038583 |
|====================================================================================================================|
| Iter | Eval   | Objective:  | Objective   | BestSoFar   | BestSoFar   | BoxConstraint|  KernelScale |      Epsilon |
|      | result | log(1+loss) | runtime     | (observed)  | (estim.)    |              |              |              |
|====================================================================================================================|
|   21 | Accept |  0.00027771 |    0.045855 |  0.00023035 |  0.00023091 |       98.475 |       22.845 |    0.0059835 |
|   22 | Accept |  0.00027277 |    0.052248 |  0.00023035 |  0.00023465 |       125.74 |      0.56051 |    0.0089088 |
|   23 | Accept |  0.00040274 |    0.047114 |  0.00023035 |  0.00023595 |       120.09 |       2.1842 |    0.0057211 |
|   24 | Accept |   0.0088286 |    0.049481 |  0.00023035 |  0.00023147 |       295.49 |     0.011784 |     0.039554 |
|   25 | Accept |  0.00054269 |    0.067053 |  0.00023035 |  0.00023092 |       685.63 |      0.67395 |    0.0032532 |
|   26 | Accept |  0.00045828 |    0.045606 |  0.00023035 |  0.00023048 |       295.15 |       1.3094 |     0.026687 |
|   27 | Accept |  0.00041202 |    0.048876 |  0.00023035 |  0.00022908 |       21.398 |        1.643 |     0.031707 |
|   28 | Accept |  0.00077543 |    0.055748 |  0.00023035 |  0.00022952 |       949.56 |      0.70361 |    0.0001414 |
|   29 | Accept |  0.00024446 |    0.055679 |  0.00023035 |  0.00022869 |       845.44 |       137.77 |    0.0001848 |
|   30 | Best   |  0.00022781 |    0.053171 |  0.00022781 |  0.00022324 |       260.76 |        57.95 |    0.0045156 |

__________________________________________________________
Optimization completed.
MaxObjectiveEvaluations of 30 reached.
Total function evaluations: 30
Total elapsed time: 8.727 seconds
Total objective function evaluation time: 1.4191

Best observed feasible point:
    BoxConstraint    KernelScale     Epsilon 
    _____________    ___________    _________

       260.76           57.95       0.0045156

Observed objective function value = 0.00022781
Estimated objective function value = 0.00022324
Function evaluation time = 0.053171

Best estimated feasible point (according to models):
    BoxConstraint    KernelScale     Epsilon 
    _____________    ___________    _________

       260.76           57.95       0.0045156

Estimated objective function value = 0.00022324
Estimated function evaluation time = 0.047391

Figure contains an axes object. The axes object with title Min objective vs. Number of function evaluations, xlabel Function evaluations, ylabel Min objective contains 2 objects of type line. These objects represent Min observed objective, Estimated min objective.

[SoH_B07_second_estimate, SoH_B07_second] = hTrainandEstimateSoH(B0007, rated_C, num_cycles_FirstLife);
|====================================================================================================================|
| Iter | Eval   | Objective:  | Objective   | BestSoFar   | BestSoFar   | BoxConstraint|  KernelScale |      Epsilon |
|      | result | log(1+loss) | runtime     | (observed)  | (estim.)    |              |              |              |
|====================================================================================================================|
|    1 | Best   |  2.4601e-05 |    0.047072 |  2.4601e-05 |  2.4601e-05 |        389.3 |       265.43 |    0.0027997 |
|    2 | Accept |   0.0032604 |    0.034948 |  2.4601e-05 |   0.0014541 |    0.0054226 |       442.27 |     0.011163 |
|    3 | Accept |   0.0030991 |     0.05007 |  2.4601e-05 |  2.4922e-05 |     0.067844 |       65.331 |       6.8095 |
|    4 | Accept |   0.0029705 |     0.05383 |  2.4601e-05 |  2.4806e-05 |    0.0023879 |     0.028332 |    0.0051578 |
|    5 | Accept |  5.2746e-05 |    0.054267 |  2.4601e-05 |   2.505e-05 |        996.4 |       15.544 |    0.0025751 |
|    6 | Accept |  3.5745e-05 |    0.052041 |  2.4601e-05 |  2.3309e-05 |       52.845 |       14.102 |    0.0034189 |
|    7 | Accept |   0.0031275 |    0.049478 |  2.4601e-05 |  2.0678e-05 |       127.71 |       510.88 |     0.087961 |
|    8 | Accept |  7.4493e-05 |    0.054498 |  2.4601e-05 |  2.0114e-05 |        69.42 |      0.85521 |    0.0009477 |
|    9 | Accept |   0.0030308 |    0.050419 |  2.4601e-05 |  2.0292e-05 |       961.74 |    0.0026502 |   8.3102e-05 |
|   10 | Accept |  9.1477e-05 |    0.054972 |  2.4601e-05 |  2.1693e-05 |       45.116 |      0.25624 |    0.0017802 |
|   11 | Accept |  4.8515e-05 |     0.05162 |  2.4601e-05 |  2.1409e-05 |        926.6 |       42.623 |    0.0011035 |
|   12 | Accept |   0.0030225 |    0.058967 |  2.4601e-05 |  2.4562e-05 |       953.35 |    0.0010618 |    0.0059343 |
|   13 | Accept |  2.7871e-05 |    0.055337 |  2.4601e-05 |  2.4953e-05 |       31.406 |       17.681 |    0.0016673 |
|   14 | Accept |  6.1961e-05 |    0.049176 |  2.4601e-05 |  2.4775e-05 |       174.31 |        6.681 |    0.0018788 |
|   15 | Accept |   3.628e-05 |    0.061646 |  2.4601e-05 |  2.3117e-05 |       9.3114 |        1.018 |    0.0013094 |
|   16 | Accept |  3.4254e-05 |    0.049149 |  2.4601e-05 |  2.6973e-05 |        453.3 |       942.24 |   0.00083669 |
|   17 | Accept |  3.1404e-05 |    0.045256 |  2.4601e-05 |  2.4808e-05 |       975.92 |       688.71 |    0.0012879 |
|   18 | Accept |  0.00081064 |    0.050075 |  2.4601e-05 |  2.4954e-05 |       18.836 |       430.35 |   0.00010342 |
|   19 | Accept |   3.509e-05 |    0.042428 |  2.4601e-05 |  2.5856e-05 |       220.11 |       199.87 |    0.0012815 |
|   20 | Accept |  3.4456e-05 |    0.042978 |  2.4601e-05 |  2.5229e-05 |       895.99 |       275.71 |   0.00038828 |
|====================================================================================================================|
| Iter | Eval   | Objective:  | Objective   | BestSoFar   | BestSoFar   | BoxConstraint|  KernelScale |      Epsilon |
|      | result | log(1+loss) | runtime     | (observed)  | (estim.)    |              |              |              |
|====================================================================================================================|
|   21 | Accept |  5.1706e-05 |    0.043456 |  2.4601e-05 |   2.516e-05 |        86.97 |       66.556 |   0.00050549 |
|   22 | Accept |  3.2292e-05 |    0.048995 |  2.4601e-05 |  2.4576e-05 |       696.46 |       69.584 |    0.0026005 |
|   23 | Accept |  3.9151e-05 |     0.06844 |  2.4601e-05 |  2.6652e-05 |       24.438 |        2.466 |    0.0021864 |
|   24 | Accept |   0.0033616 |    0.040459 |  2.4601e-05 |  1.8726e-05 |       1.7454 |       886.17 |   0.00061265 |
|   25 | Accept |   0.0020726 |    0.042408 |  2.4601e-05 |  2.7012e-05 |        6.057 |     0.021235 |   0.00030232 |
|   26 | Accept |  2.7764e-05 |    0.041223 |  2.4601e-05 |  2.7968e-05 |       248.69 |       229.43 |   8.4266e-05 |
|   27 | Accept |  3.5062e-05 |    0.059547 |  2.4601e-05 |  2.7844e-05 |       57.962 |       13.197 |   8.7989e-05 |
|   28 | Accept |  3.7653e-05 |     0.05177 |  2.4601e-05 |  2.7815e-05 |       15.028 |       4.3661 |   0.00032307 |
|   29 | Accept |  9.1413e-05 |    0.039422 |  2.4601e-05 |  2.7841e-05 |       604.98 |      0.61956 |     0.011303 |
|   30 | Accept |  0.00038373 |    0.043325 |  2.4601e-05 |  2.7882e-05 |       30.222 |      0.27698 |     0.021983 |

__________________________________________________________
Optimization completed.
MaxObjectiveEvaluations of 30 reached.
Total function evaluations: 30
Total elapsed time: 8.5604 seconds
Total objective function evaluation time: 1.4873

Best observed feasible point:
    BoxConstraint    KernelScale     Epsilon 
    _____________    ___________    _________

        389.3          265.43       0.0027997

Observed objective function value = 2.4601e-05
Estimated objective function value = 2.978e-05
Function evaluation time = 0.047072

Best estimated feasible point (according to models):
    BoxConstraint    KernelScale     Epsilon  
    _____________    ___________    __________

       248.69          229.43       8.4266e-05

Estimated objective function value = 2.7882e-05
Estimated function evaluation time = 0.041223

Figure contains an axes object. The axes object with title Min objective vs. Number of function evaluations, xlabel Function evaluations, ylabel Min objective contains 2 objects of type line. These objects represent Min observed objective, Estimated min objective.

Performance evaluation of the trained model

Plot the predicted vs. actual SoH plot from validation data. The SoH data was predicted using the model trained from the first 100 cycles from dataset.

Next, compute the SoH estimation RMSE for each battery to qualify the robustness of the approach.

figure;
subplot(3,1,1);
plot(SoH_B05_second)
hold on
plot(SoH_B05_second_estimate)
legend('Actual','Estimated');
title('SoH Estimation Plot for B0005')
xlabel('Cycle Number')
ylabel('SoH')

subplot(3,1,2); 
plot(SoH_B06_second)
hold on
plot(SoH_B06_second_estimate)
legend('Actual','Estimated');
title('SoH Estimation Plot for B0006')
xlabel('Cycle Number')
ylabel('SoH')

subplot(3,1,3); 
plot(SoH_B07_second)
hold on
plot(SoH_B07_second_estimate)
legend('Actual','Estimated');
title('SoH Estimation Plot for B0007')
xlabel('Cycle Number')
ylabel('SoH')

Figure contains 3 axes objects. Axes object 1 with title SoH Estimation Plot for B0005, xlabel Cycle Number, ylabel SoH contains 2 objects of type line. These objects represent Actual, Estimated. Axes object 2 with title SoH Estimation Plot for B0006, xlabel Cycle Number, ylabel SoH contains 2 objects of type line. These objects represent Actual, Estimated. Axes object 3 with title SoH Estimation Plot for B0007, xlabel Cycle Number, ylabel SoH contains 2 objects of type line. These objects represent Actual, Estimated.

Compute the SOH estimation RMSE for each battery to qualify the robustness of the approach.

RMSE_B06 = rmse(SoH_B06_second, SoH_B06_second_estimate)
RMSE_B06 = 0.0158
RMSE_B07 = rmse(SoH_B07_second, SoH_B07_second_estimate)
RMSE_B07 = 0.0042

Conclusion

This example illustrates the estimation of Li-ion battery State of Health estimation for second-life applications. The estimation is based on two health indicators (HI), TIEDVD and TIECVD and an SVR model trained with first-life data. The selected HIs share a similar characteristic with battery capacity degradation over cycle number. Further, the HIs can be computed online thereby enabling online SoH estimation with relatively low complexity. This approach was robust across different batteries because the model was trained individually on each battery’s first-life measurements:

BattName = {'B0005';'B0006';'B0007'};
RMSE = [RMSE_B05;RMSE_B06;RMSE_B07];
table(string(BattName), RMSE, 'VariableNames', {'BattName', 'RMSE'})
ans=3×2 table
    BattName      RMSE   
    ________    _________

    "B0005"     0.0012047
    "B0006"      0.015814
    "B0007"     0.0042338

Temperature is also assumed to be constant across cycles in this example. However, temperature would vary from cycle to cycle during charge and this will impact the selected health indicators.To address this, temperature as an additional predictor can be explored.

References

[1] Zhao, Qi, Xiaoli Qin, Hongbo Zhao, and Wenquan Feng. "A novel prediction method based on the support vector regression for the remaining useful life of lithium-ion batteries." Microelectronics Reliability 85 (2018): 99-108.

[2] https://data.nasa.gov/dataset/Li-ion-Battery-Aging-Datasets/uj5r-zjdb

Supporting Functions

function [SoH_estimate, SoH_second] = hTrainandEstimateSoH(Batt_data, rated_C, num_cycles_FirstLife)
% HTRAINANDESTIMATESOH function accepts battery measurements in the form of
% a structure, rated capacity to compute SoH, and number of cycles related
% to first life usage of the cell. The two health indicators TIECVD, and TIEDVD are computed and an 
% support vector regression model is trained to estimate the SoH. 

% Use the hExtractChargeDischargeCycles helper function to extract charge
% and discharge segments, and discharge capacity for each cycle.
[B_d, B_c, C_B] = hExtractChargeDischargeCycles(Batt_data);

% Call hDataSplitter helper function to split the charge and discharge data
% between the first and second life measurements
[B_d_first, B_c_first, B_d_second, B_c_second] = hDataSplitter(B_d, B_c, num_cycles_FirstLife);

% Split capacity measurements as well
[C_first, C_second] = hCapacitySplitter(C_B, num_cycles_FirstLife);

% Call hFeatureExtraction helper function to compute TIECVD and TIEDVD
[TIECVD_first, TIEDVD_first] = hFeatureExtraction(B_d_first, B_c_first);

% Compute SoH for first and second lives
SoH_first = C_first/rated_C;
SoH_second = C_second/rated_C;

[TIECVD_second, TIEDVD_second] = hFeatureExtraction(B_d_second, B_c_second);
predictors_second = [TIECVD_second, TIEDVD_second];

% Set up predictors and response to train the SVR model using first life
% measurements
predictors = [TIECVD_first, TIEDVD_first];
response = SoH_first;


%% SVR training
rng 'default'  % For reproducibility

regressionSVM = fitrsvm(predictors, response,...
    'KernelFunction', 'gaussian', ...
    'Standardize', true, ...
    'OptimizeHyperparameters', {'BoxConstraint','KernelScale','Epsilon'}, ...
    'HyperparameterOptimizationOptions', ...
    struct('AcquisitionFunctionName', 'expected-improvement-plus', ... 
    'NumGridDivisions', 2,...
    'Repartition',true, ...
    'Kfold', 5), ...
    'IterationLimit', 1000,...
     'Verbose', 0);

% Estimate SoH for second life measurements
SoH_estimate = predict(regressionSVM,predictors_second);

end

function [B_d_first, B_c_first, B_d_second, B_c_second] = hDataSplitter(B_d, B_c, num_cycles_FirstLife)
% Function to split charge and discharge voltage measurements vector into
% two segments using the num_cycles_FirstLife value
    B_d_first  = B_d(1:num_cycles_FirstLife);
    B_c_first  = B_c(1:num_cycles_FirstLife);
    B_d_second = B_d(num_cycles_FirstLife+1:end);
    B_c_second = B_c(num_cycles_FirstLife+1:end);
end

function [C_first, C_second] = hCapacitySplitter(C, num_cycles_FirstLife)
% Function to split capacity measurements into two segments using the
% num_cycles_FirstLife value
    C_first = C(1:num_cycles_FirstLife);
    C_second = C(num_cycles_FirstLife+1:end);
end