Main Content

Estimate Battery Model Parameters from HPPC Data

Since R2025a

This example shows how to estimate the model parameters for a battery equivalent circuit model (ECM) from hybrid pulse power characterization (HPPC) data using Simscape™ Battery™. HPPC is a valuable technique in the battery industry and is one of the most common battery tests performed both at single-cell level or at system level. This technique involves applying a series of constant current pulses to a battery and measuring its terminal voltage and temperature responses at different operating conditions. There are multiple key operating conditions, including the initial battery soak temperature, initial state of charge (SOC), current or load, current directionality such as charge or discharge, state of health (SOH) or remaining capacity, and load frequency. The measured voltage response from each current pulse contains valuable information regarding the internal resistance or impedance of the battery.

In this example, you first define an hppcTest object that allows you to visualize, tabulate, and manipulate the different constant current pulses inside your HPPC data. The HPPCTest object contains a summary of all the current pulses performed in a single HPPC test program. This object automatically identifies each constant current pulse and tabulates it for inspection and preparation for the parameter estimation process as an optional data pre-processing step. This HPPC test data must be in a MAT file format and must contain time, current, and voltage signals. Optionally, you can specify the temperature, charge, and SOC.

You then estimate the parameters for a battery ECM that best match the terminal voltage response of the battery. The key outputs from the parameter estimation process are 1-D, 2-D, or 3-D parameter look-up tables. You can use these tables for control, as part of battery management system (BMS) algorithms, or for simulation, as parameters for the Battery Equivalent Circuit block.

Finally, this example shows you how to automatically parameterize the Battery Equivalent Circuit block to run battery simulations.

Create and Visualize HPPCTest Objects

An HPPCTest object automatically identifies all individual constant current pulses inside an HPPC test file. To create an HPPCTest object, first load the HPPC data into the MATLAB® workspace.

load("testDataBAKcells/hppcDataBAKcell25degC.mat","hppcData")

To create an HPPCTest object, use the hppcTest function. By default, the HPPCTest object assumes that the time, voltage, and current columns are named "Time", "Voltage", and "Current", respectively. If these variables have different column name identifiers, you can specify them by using the optional name-value arguments.

hppcExp25degC = hppcTest(hppcData,...
    TimeVariable="time (s)", ...
    VoltageVariable="voltage (V)", ...
    CurrentVariable="current (A)", ...
    Capacity=2.84, ...
    InitialSOC=0.055);

The HPPCTest object automatically calculates the battery SOC at every time step across the experiment, according to the input current measurement. The object use these calculated SOC values to define the SOC breakpoints for every constant current pulse. The TestSummary property contains a summary of these SOC breakpoints as well as all other temperature and current breakpoints identified from the data. Optionally, to improve the accuracy of the calculation of the SOC, the hppcTest function allows you to specify the battery capacity, the test initial SOC, and these column vectors:

  • Charge — If you specify this column variable and the StateOfCharge variable is empty, the HPPCTest object uses the values in this column to calculate the SOC breakpoints.

  • StateOfCharge — if you specify this column variable, the HPPCTest object uses the values in this column to calculate the SOC breakpoints.

To visualize a summary of the test and the identified charge and discharge pulses, use the plot function.

plot(hppcExp25degC)

The function automatically identifies the charge and discharge constant current pulses from the data according to these properties:

  • ValidPulseDurationRange — Valid pulse duration range that indicates whether a pulse is valid and must be stored in the TestSummary property table. Decreasing the upper bound to values lower than 60 seconds ensures that very long discharges, such as capacity checks, are not included in the final list of pulses for estimation. Increasing the lower bound for this property to values greater than one or two seconds, ensures that the function excludes potential noise, outlier currents, or abnormally short pulses from the final list of pulses for estimation.

  • ValidVoltageRange — Valid battery voltage range that indicates whether a pulse is valid and must be stored in the TestSummary property table.

  • CurrentOnThreshold — Threshold current value that indicates whether a charge or a discharge is occurring. This value is important for experiments where the rest or baseline current is not equal to zero.

  • NumSamplesRequirement — Number of sequential points, specified as a scalar, at which the current must be greater than the CurrentOnThreshold value to signify the presence of a charge or discharge pulse.

You can customize these properties with your individual options to filter out or only select the pulses that you want to use for parameter estimation. Optionally, you can also remove pulses manually from the TestSummary table after object creation by using the removePulse function.

To view a summary of all the identified pulses, use the TestSummary property.

disp(hppcExp25degC.TestSummary)
    PulseID    Directionality      SOC           HPPCData         PulseDuration    PseudoOCV_V    MaximumVoltage    MinimumVoltage    Current_A    C_rate    PulseStartIndex    PulseEndIndex    Temperature_degC
    _______    ______________    ________    _________________    _____________    ___________    ______________    ______________    _________    ______    _______________    _____________    ________________

       1        "Discharge"        0.9866    {701×6 timetable}         30            4.1745           4.1745            3.7846         -6.1869     2.1785           354              1055               25       
       2        "Discharge"       0.87612    {701×6 timetable}         30            4.0837           4.0837            3.7479          -6.187     2.1785          2702              3403               25       
       3        "Discharge"       0.76566    {702×6 timetable}         30            4.0132           4.0132            3.6652         -6.1867     2.1784          5049              5751               25       
       4        "Discharge"       0.65521    {701×6 timetable}         30            3.9226           3.9226            3.5775         -6.1868     2.1784          7398              8099               25       
       5        "Discharge"       0.54476    {701×6 timetable}         30             3.846            3.846            3.4942         -6.1868     2.1784          9746             10447               25       
       6        "Discharge"       0.43431    {701×6 timetable}         30            3.7353           3.7353            3.4001         -6.1871     2.1785         12094             12795               25       
       7        "Discharge"       0.32386    {701×6 timetable}         30              3.65             3.65            3.3236         -6.1867     2.1784         14442             15143               25       
       8        "Discharge"        0.2134    {701×6 timetable}         30            3.6015           3.6015            3.2652         -6.1869     2.1785         16790             17491               25       
       9        "Discharge"       0.10295    {701×6 timetable}         30            3.5507           3.5507            3.1931         -6.1869     2.1785         19138             19839               25       
      10        "Charge"           0.9684    {502×6 timetable}         10            4.1158           4.3889            4.1158          4.6393     1.6336          1055              1557               25       
      11        "Charge"          0.85795    {502×6 timetable}         10             4.057           4.3001             4.057          4.6406      1.634          3403              3905               25       
      12        "Charge"          0.74749    {502×6 timetable}         10            3.9674           4.2113            3.9674          4.6394     1.6336          5751              6253               25       
      13        "Charge"          0.63704    {502×6 timetable}         10            3.8751           4.1175            3.8751          4.6396     1.6337          8099              8601               25       
      14        "Charge"          0.52659    {502×6 timetable}         10            3.7905           4.0355            3.7905          4.6396     1.6337         10447             10949               25       
      15        "Charge"          0.41614    {502×6 timetable}         10            3.6936           3.9339            3.6936          4.6405      1.634         12795             13297               25       
      16        "Charge"          0.30569    {502×6 timetable}         10            3.6224           3.8602            3.6224          4.6396     1.6337         15143             15645               25       
      17        "Charge"          0.19523    {502×6 timetable}         10            3.5695           3.8109            3.5695          4.6397     1.6337         17491             17993               25       
      18        "Charge"         0.084783    {502×6 timetable}         10            3.5098           3.7597            3.5098          4.6397     1.6337         19839             20341               25       

You can visualize the voltage response for specific pulses from the TestSummary table by using the plotPulse function. The plotPulse function optionally accepts a second argument that specifies the index for the pulses to be visualized and inspected for abnormalities. This index refers to the PulseID column in the TestSummary property table. You can specify this index as a scalar or vector.

Plot the first pulse in the HPPCTest object using the plotPulse function.

 plotPulse(hppcExp25degC)

This figure shows the different load and relaxation segments for a given constant current pulse. Typically, the battery ECM parameters are different depending on which segment you use for the parameter estimation process.

You can visualize the different pulses in a grid layout by defining a vector as the second argument of the plotPulse function.

 plotPulse(hppcExp25degC,1:4)

You can also remove individual pulses that behave abnormally or do not meet your requirements, including nonlinear voltage response, missing points, voltage outliers, or abnormal dispersion. In this HPPC dataset, the third pulse might be missing the initial rest voltage at the beginning of the pulse. Remove it from the parameter estimation process by using the removePulse function.

 removePulse(hppcExp25degC,3)

Inspect the updated TestSummary property. Notice that there are now only 17 pulses in the table.

disp(hppcExp25degC.TestSummary) 
    PulseID    Directionality      SOC           HPPCData         PulseDuration    PseudoOCV_V    MaximumVoltage    MinimumVoltage    Current_A    C_rate    PulseStartIndex    PulseEndIndex    Temperature_degC
    _______    ______________    ________    _________________    _____________    ___________    ______________    ______________    _________    ______    _______________    _____________    ________________

       1        "Discharge"        0.9866    {701×6 timetable}         30            4.1745           4.1745            3.7846         -6.1869     2.1785           354              1055               25       
       2        "Discharge"       0.87612    {701×6 timetable}         30            4.0837           4.0837            3.7479          -6.187     2.1785          2702              3403               25       
       3        "Discharge"       0.65521    {701×6 timetable}         30            3.9226           3.9226            3.5775         -6.1868     2.1784          7398              8099               25       
       4        "Discharge"       0.54476    {701×6 timetable}         30             3.846            3.846            3.4942         -6.1868     2.1784          9746             10447               25       
       5        "Discharge"       0.43431    {701×6 timetable}         30            3.7353           3.7353            3.4001         -6.1871     2.1785         12094             12795               25       
       6        "Discharge"       0.32386    {701×6 timetable}         30              3.65             3.65            3.3236         -6.1867     2.1784         14442             15143               25       
       7        "Discharge"        0.2134    {701×6 timetable}         30            3.6015           3.6015            3.2652         -6.1869     2.1785         16790             17491               25       
       8        "Discharge"       0.10295    {701×6 timetable}         30            3.5507           3.5507            3.1931         -6.1869     2.1785         19138             19839               25       
       9        "Charge"           0.9684    {502×6 timetable}         10            4.1158           4.3889            4.1158          4.6393     1.6336          1055              1557               25       
      10        "Charge"          0.85795    {502×6 timetable}         10             4.057           4.3001             4.057          4.6406      1.634          3403              3905               25       
      11        "Charge"          0.74749    {502×6 timetable}         10            3.9674           4.2113            3.9674          4.6394     1.6336          5751              6253               25       
      12        "Charge"          0.63704    {502×6 timetable}         10            3.8751           4.1175            3.8751          4.6396     1.6337          8099              8601               25       
      13        "Charge"          0.52659    {502×6 timetable}         10            3.7905           4.0355            3.7905          4.6396     1.6337         10447             10949               25       
      14        "Charge"          0.41614    {502×6 timetable}         10            3.6936           3.9339            3.6936          4.6405      1.634         12795             13297               25       
      15        "Charge"          0.30569    {502×6 timetable}         10            3.6224           3.8602            3.6224          4.6396     1.6337         15143             15645               25       
      16        "Charge"          0.19523    {502×6 timetable}         10            3.5695           3.8109            3.5695          4.6397     1.6337         17491             17993               25       
      17        "Charge"         0.084783    {502×6 timetable}         10            3.5098           3.7597            3.5098          4.6397     1.6337         19839             20341               25       

Modify SOC breakpoints

If you do not have information about the battery capacity, SOC, or charge, you can optionally modify the SOC breakpoint values inside the TestSummary property table by using the setChargeSOCs and setDischargeSOCs functions.

 setChargeSOCs(hppcExp25degC,[1,0.9,0.8,0.6,0.5,0.4,0.3,0.2,0.1]);
 setDischargeSOCs(hppcExp25degC,[1,0.9,0.7,0.5,0.4,0.3,0.2,0.1]);

Inspect the updated TestSummary property table. Notice that the functions modified the SOC breakpoints.

disp(hppcExp25degC.TestSummary)
    PulseID    Directionality    SOC        HPPCData         PulseDuration    PseudoOCV_V    MaximumVoltage    MinimumVoltage    Current_A    C_rate    PulseStartIndex    PulseEndIndex    Temperature_degC
    _______    ______________    ___    _________________    _____________    ___________    ______________    ______________    _________    ______    _______________    _____________    ________________

       1        "Discharge"        1    {701×6 timetable}         30            4.1745           4.1745            3.7846         -6.1869     2.1785           354              1055               25       
       2        "Discharge"      0.9    {701×6 timetable}         30            4.0837           4.0837            3.7479          -6.187     2.1785          2702              3403               25       
       3        "Discharge"      0.7    {701×6 timetable}         30            3.9226           3.9226            3.5775         -6.1868     2.1784          7398              8099               25       
       4        "Discharge"      0.5    {701×6 timetable}         30             3.846            3.846            3.4942         -6.1868     2.1784          9746             10447               25       
       5        "Discharge"      0.4    {701×6 timetable}         30            3.7353           3.7353            3.4001         -6.1871     2.1785         12094             12795               25       
       6        "Discharge"      0.3    {701×6 timetable}         30              3.65             3.65            3.3236         -6.1867     2.1784         14442             15143               25       
       7        "Discharge"      0.2    {701×6 timetable}         30            3.6015           3.6015            3.2652         -6.1869     2.1785         16790             17491               25       
       8        "Discharge"      0.1    {701×6 timetable}         30            3.5507           3.5507            3.1931         -6.1869     2.1785         19138             19839               25       
       9        "Charge"           1    {502×6 timetable}         10            4.1158           4.3889            4.1158          4.6393     1.6336          1055              1557               25       
      10        "Charge"         0.9    {502×6 timetable}         10             4.057           4.3001             4.057          4.6406      1.634          3403              3905               25       
      11        "Charge"         0.8    {502×6 timetable}         10            3.9674           4.2113            3.9674          4.6394     1.6336          5751              6253               25       
      12        "Charge"         0.6    {502×6 timetable}         10            3.8751           4.1175            3.8751          4.6396     1.6337          8099              8601               25       
      13        "Charge"         0.5    {502×6 timetable}         10            3.7905           4.0355            3.7905          4.6396     1.6337         10447             10949               25       
      14        "Charge"         0.4    {502×6 timetable}         10            3.6936           3.9339            3.6936          4.6405      1.634         12795             13297               25       
      15        "Charge"         0.3    {502×6 timetable}         10            3.6224           3.8602            3.6224          4.6396     1.6337         15143             15645               25       
      16        "Charge"         0.2    {502×6 timetable}         10            3.5695           3.8109            3.5695          4.6397     1.6337         17491             17993               25       
      17        "Charge"         0.1    {502×6 timetable}         10            3.5098           3.7597            3.5098          4.6397     1.6337         19839             20341               25       

Estimate Battery Model Parameters

The process of parameter estimation involves minimizing the error between the predicted voltage output of the ECM and the measured battery voltage response from the HPPC test. This table shows the most typical ECMs used to represent the impedance of a battery:

To minimize the error, you iteratively adjust the model parameters, such as R0, R1, and C1, until you achieve a satisfactory error between the measured voltage and a simulated voltage. There are several techniques in MATLAB that provide this functionality inside the Model-Based Calibration Toolbox™, System Identification Toolbox™, and Curve Fitting Toolbox™. In this example, you estimate the parameters of the battery model by using an optimization-based fitting method implemented in Simscape™ Battery™. This fitting method utilizes a custom implementation of the fminsearch function.

The battery ECM parameters for a specific operating point can be different depending on which segment or section of the current pulse you use for the parameter estimation process. The load-segment parameters suit most applications. However, the best estimation segment depends on the specific end application of the battery ECM. Some methods are better suited to estimate parameters for a given segment, for example the System Identification Toolbox tfest function works best for fitting load-only dynamics. This table contains a summary of the supported options for the FittingMethod and SegmentToFit arguments of the fitecm function, depending on the chosen toolbox or method.

Estimate Parameters for Single Current Pulse

There are a total of 17 constant current pulses inside the hppcExp25degC object. To estimate the ECM parameters for a specific constant current pulse profile in your test data, first define the index of the pulse you want to find the ECM parameters for. This index relates to a specific row in the TestSummary property table.

pulseIndex = 5;

To find the ECM parameters, use the fitECM function. This function requires the HPPC test data as input. The default value for the FittingMethod argument is "fminsearch", which is the optimization method implemented in Simscape Battery. The default value for the SegmentToFit argument focuses on the relaxation section of the constant current pulse. Different options for the FittingMethod argument of the fitECM function allow you to perform the parameter estimation process for different segments of the pulse.

batteryEcm = fitECM(hppcExp25degC.TestSummary.HPPCData{pulseIndex}(:,1:2), SegmentToFit="loadAndRelaxation"); 

The fitECM function returns an ecm object. View the ECM topology and other properties of the ECM object.

disp(batteryEcm)

You can define optional name-value arguments for the fitECM function. For example, the ECM name-value argument specifies the desired ECM circuit topology you want to use to fit the data. If you do not specify this argument, the fitECM function uses this 2-RC branch ECM topology:

Use the plot function to visualize the measured and the simulated battery ECM voltage response. The plot function calculates the simulated battery ECM voltage response by assuming a constant open-circuit voltage value. In most cases, including a dynamic open-circuit voltage curve during the simulation improves the accuracy of the verification plot.

 plot(batteryEcm)

Estimate Parameters for Sequence of Pulses

To estimate the ECM parameters for all the pulses inside a specific HPPCTest object, use the fitECM function and specify the entire HPPCTest object as input.

batteryEcm = fitECM(hppcExp25degC, SegmentToFit="loadAndRelaxation"); 

Display the parameters and estimation error by using the TestParameterTables property of the batteryEcm object.

disp(batteryEcm.TestParameterTables)
                TestBreakpoints: [1×1 struct]
       ChargeOpenCircuitVoltage: [3.5098 3.5695 3.6224 3.6936 3.7905 3.8751 3.9674 4.0570 4.1158]
                       ChargeR0: [0.0390 0.0382 0.0378 0.0392 0.0371 0.0369 0.0370 0.0397 0.0403]
                       ChargeR1: [0.0072 0.0067 0.0069 0.0049 0.0066 0.0065 0.0067 0.0052 0.0091]
                     ChargeTau1: [0.3751 0.3774 0.3982 0.3797 0.3286 0.3317 0.3874 0.3967 0.3551]
                       ChargeC1: [51.9419 56.5704 57.6792 76.7624 49.7476 51.0375 58.1648 76.3596 39.2237]
                       ChargeR2: [0.0103 0.0095 0.0644 0.0117 0.0129 0.0115 0.0114 0.0089 0.0154]
                     ChargeTau2: [9.5365 9.4661 24.1822 10.3457 8.3771 8.2633 8.6700 8.5273 9.3994]
                       ChargeC2: [921.5608 995.1325 375.6581 883.1525 649.5546 715.9945 761.9383 962.1568 612.1307]
                    ChargeFitPc: [2.3798e-05 2.1926e-05 8.9156e-05 2.5623e-05 2.9595e-05 2.7463e-05 2.9163e-05 2.8058e-05 3.7073e-05]
    DischargeOpenCircuitVoltage: [3.5507 3.6015 3.6500 3.7353 3.8460 3.9226 4.0837 4.1745]
                    DischargeR0: [0.0433 0.0418 0.0411 0.0408 0.0407 0.0406 0.0422 0.0407]
                    DischargeR1: [0.0017 0.0015 0.0016 0.0020 0.0024 0.0024 0.0023 0.0080]
                  DischargeTau1: [1.0136 1.0639 1.0778 1.1318 1.1306 1.1331 1.1418 0.6206]
                    DischargeC1: [587.1147 686.9393 670.4352 556.3512 467.1310 475.4616 489.4226 77.6454]
                    DischargeR2: [0.0180 0.0141 0.0122 0.0129 0.0146 0.0138 0.0108 0.0127]
                  DischargeTau2: [23.0014 21.2042 20.0352 20.7300 20.4551 19.9010 17.9218 15.9518]
                    DischargeC2: [1.2760e+03 1.5031e+03 1.6366e+03 1.6042e+03 1.3996e+03 1.4436e+03 1.6628e+03 1.2560e+03]
                 DischargeFitPc: [2.7466e-05 1.9487e-05 2.0726e-05 2.9118e-05 4.3007e-05 4.1371e-05 3.7379e-05 1.6776e-04]

The parameters inside the TestParameterTables property are different from the parameters inside the ModelParameterTables property. The ECM object determines the parameters inside the ModelParameterTables property by using the ECM object breakpoints you specify. The ECM object determines the parameters inside the TestParameterTables property by using the test conditions. View the model parameter tables by using the ModelParameterTables property.

disp(batteryEcm.ModelParameterTables)
       ChargeOpenCircuitVoltage: [3.5098 3.5098 3.5695 3.6224 3.6936 3.7905 3.8751 3.9674 3.9674 4.0570 4.1158]
                       ChargeR0: [0.0390 0.0390 0.0382 0.0378 0.0392 0.0371 0.0369 0.0370 0.0370 0.0397 0.0403]
                       ChargeR1: [0.0072 0.0072 0.0067 0.0069 0.0049 0.0066 0.0065 0.0067 0.0067 0.0052 0.0091]
                     ChargeTau1: [0.3751 0.3751 0.3774 0.3982 0.3797 0.3286 0.3317 0.3874 0.3874 0.3967 0.3551]
                       ChargeC1: [51.9419 51.9419 56.5704 57.6792 76.7624 49.7476 51.0375 58.1648 58.1648 76.3596 39.2237]
                       ChargeR2: [0.0103 0.0103 0.0095 0.0644 0.0117 0.0129 0.0115 0.0114 0.0114 0.0089 0.0154]
                     ChargeTau2: [9.5365 9.5365 9.4661 24.1822 10.3457 8.3771 8.2633 8.6700 8.6700 8.5273 9.3994]
                       ChargeC2: [921.5608 921.5608 995.1325 375.6581 883.1525 649.5546 715.9945 761.9383 761.9383 962.1568 612.1307]
                    ChargeFitPc: [2.3798e-05 2.3798e-05 2.1926e-05 8.9156e-05 2.5623e-05 2.9595e-05 2.7463e-05 2.9163e-05 2.9163e-05 2.8058e-05 3.7073e-05]
    DischargeOpenCircuitVoltage: [3.5507 3.5507 3.6015 3.6500 3.7353 3.8460 3.9226 3.9226 4.0837 4.0837 4.1745]
                    DischargeR0: [0.0433 0.0433 0.0418 0.0411 0.0408 0.0407 0.0406 0.0406 0.0422 0.0422 0.0407]
                    DischargeR1: [0.0017 0.0017 0.0015 0.0016 0.0020 0.0024 0.0024 0.0024 0.0023 0.0023 0.0080]
                  DischargeTau1: [1.0136 1.0136 1.0639 1.0778 1.1318 1.1306 1.1331 1.1331 1.1418 1.1418 0.6206]
                    DischargeC1: [587.1147 587.1147 686.9393 670.4352 556.3512 467.1310 475.4616 475.4616 489.4226 489.4226 77.6454]
                    DischargeR2: [0.0180 0.0180 0.0141 0.0122 0.0129 0.0146 0.0138 0.0138 0.0108 0.0108 0.0127]
                  DischargeTau2: [23.0014 23.0014 21.2042 20.0352 20.7300 20.4551 19.9010 19.9010 17.9218 17.9218 15.9518]
                    DischargeC2: [1.2760e+03 1.2760e+03 1.5031e+03 1.6366e+03 1.6042e+03 1.3996e+03 1.4436e+03 1.4436e+03 1.6628e+03 1.6628e+03 1.2560e+03]
                 DischargeFitPc: [2.7466e-05 2.7466e-05 1.9487e-05 2.0726e-05 2.9118e-05 4.3007e-05 4.1371e-05 4.1371e-05 3.7379e-05 3.7379e-05 1.6776e-04]

To view a complete summary of all the estimated parameter, use the ParameterSummary property of the batteryECM object.

disp(batteryEcm.ParameterSummary)
    ID    Directionality      SOC       Temperature_degC    Current_A    OpenCircuitVoltage       R0          R1         Tau1        C1         R2         Tau2       C2        FitPc   
    __    ______________    ________    ________________    _________    __________________    ________    _________    _______    ______    _________    ______    ______    __________

     1     "Discharge"        0.9866           25            -6.1869           4.1745          0.040675    0.0079921    0.62055    77.645       0.0127    15.952      1256    0.00016776
     2     "Discharge"       0.87612           25             -6.187           4.0837          0.042195    0.0023329     1.1418    489.42     0.010778    17.922    1662.8    3.7379e-05
     3     "Discharge"       0.65521           25            -6.1868           3.9226          0.040602    0.0023832     1.1331    475.46     0.013786    19.901    1443.6    4.1371e-05
     4     "Discharge"       0.54476           25            -6.1868            3.846          0.040721    0.0024203     1.1306    467.13     0.014615    20.455    1399.6    4.3007e-05
     5     "Discharge"       0.43431           25            -6.1871           3.7353          0.040839    0.0020343     1.1318    556.35     0.012923     20.73    1604.2    2.9118e-05
     6     "Discharge"       0.32386           25            -6.1867             3.65          0.041133    0.0016076     1.0778    670.44     0.012242    20.035    1636.6    2.0726e-05
     7     "Discharge"        0.2134           25            -6.1869           3.6015          0.041807    0.0015487     1.0639    686.94     0.014107    21.204    1503.1    1.9487e-05
     8     "Discharge"       0.10295           25            -6.1869           3.5507          0.043282    0.0017264     1.0136    587.11     0.018026    23.001      1276    2.7466e-05
     9     "Charge"           0.9684           25             4.6393           4.1158          0.040273    0.0090541    0.35513    39.224     0.015355    9.3994    612.13    3.7073e-05
    10     "Charge"          0.85795           25             4.6406            4.057          0.039702    0.0051946    0.39666     76.36    0.0088627    8.5273    962.16    2.8058e-05
    11     "Charge"          0.74749           25             4.6394           3.9674          0.036987    0.0066604     0.3874    58.165     0.011379      8.67    761.94    2.9163e-05
    12     "Charge"          0.63704           25             4.6396           3.8751          0.036877     0.006499    0.33169    51.037     0.011541    8.2633    715.99    2.7463e-05
    13     "Charge"          0.52659           25             4.6396           3.7905            0.0371    0.0066046    0.32856    49.748     0.012897    8.3771    649.55    2.9595e-05
    14     "Charge"          0.41614           25             4.6405           3.6936          0.039245    0.0049462    0.37968    76.762     0.011715    10.346    883.15    2.5623e-05
    15     "Charge"          0.30569           25             4.6396           3.6224          0.037844    0.0069032    0.39817    57.679     0.064373    24.182    375.66    8.9156e-05
    16     "Charge"          0.19523           25             4.6397           3.5695          0.038239    0.0066714     0.3774     56.57    0.0095124    9.4661    995.13    2.1926e-05
    17     "Charge"         0.084783           25             4.6397           3.5098          0.038967    0.0072218    0.37511    51.942     0.010348    9.5365    921.56    2.3798e-05

To verify the accuracy of the fit for each specific current pulse, use the plot function. The plot function optionally accepts a second argument that specifies the index of the pulse fit that you want to visualize. This index refers to the PulseID column inside the ParameterSummary property table. You can specify this index as a scalar or a vector.

Plot the fit for the first four discharge pulses.

plot(batteryEcm,1:4)

Plot the fit for the charge pulses 10, 11, 12, and 13.

plot(batteryEcm,10:13)

Once the you identify the ECM impedance parameters, to perform parameter verification, you can simulate the entire HPPCTest. The fitECM function only fits impedance and open-circuit voltage parameters in the data. If the test does not cover the full SOC range of a battery, the verification does not appear correct in these test areas.

To verify the resulting model against the HPPC test data, select only the portion of the test that contains the pulses.

data = hppcData((300:21475),:);
data.("time (s)") = data.("time (s)")-data.("time (s)")(1);
hppcExp25degCSim = hppcTest(data, ...
    TimeVariable="time (s)", ...
    VoltageVariable="voltage (V)", ...
    CurrentVariable="current (A)", ...
    Capacity=2.84, ...
    InitialSOC=1);

Visualize the model verification by using the simulateHPPCTest function.

simulateHPPCTest(batteryEcm,hppcExp25degCSim)

Alternatively, you can try different ECM topologies to achieve a better fit. Create an ECM object and specify the required number of parallel resistor-capacitor pairs.

battery3RCECM = ecm(3);

To estimate the model parameters for this ECM object, use the fitECM function.

battery3RCECM = fitECM(hppcExp25degC,ECM=battery3RCECM, ...
    SegmentToFit="loadAndRelaxation"); 

To verify the accuracy of the fit for each specific current pulse, use the plot function.

plot(battery3RCECM,1:4)

Single Resistor or Direct Current Internal Resistance (DCIR) tables

The battery industry widely uses DCIR tables. Create an ECM object with no parallel resistor-capacitor pairs. This topology represents a single resistor.

batteryECMSingleRes = ecm(0);

Estimate the model parameters for this ECM by using the fitECM function.

batteryECMSingleRes = fitECM(hppcExp25degC,ECM=batteryECMSingleRes);

The ECM automatically populates with the DCIRs at different time frames depending on the pulse duration. The fitECM function uses these time frames: 2 seconds, 5 seconds, 10 seconds, 30 seconds, 60 seconds. For example, If the pulse duration is less than 60 seconds, the fitECM function does not include this DCIR value in the output table.

To view all the DCIR tables, use the TestParameterTables property of the batteryECMSingleRes object.

disp(batteryECMSingleRes.TestParameterTables)
                TestBreakpoints: [1×1 struct]
       ChargeOpenCircuitVoltage: [3.5098 3.5695 3.6224 3.6936 3.7905 3.8751 3.9674 4.0570 4.1158]
                   ChargeDCIR2s: [0.0482 0.0467 0.0461 0.0458 0.0460 0.0458 0.0461 0.0470 0.0513]
                   ChargeDCIR5s: [0.0507 0.0491 0.0483 0.0484 0.0490 0.0487 0.0490 0.0495 0.0545]
                       ChargeR0: [0.0507 0.0491 0.0483 0.0484 0.0490 0.0487 0.0490 0.0495 0.0545]
                    ChargeFitPc: [100 100 100 100 100 100 100 100 100]
    DischargeOpenCircuitVoltage: [3.5507 3.6015 3.6500 3.7353 3.8460 3.9226 4.0837 4.1745]
                DischargeDCIR2s: [0.0463 0.0448 0.0442 0.0450 0.0459 0.0456 0.0467 0.0525]
                DischargeDCIR5s: [0.0484 0.0467 0.0460 0.0470 0.0483 0.0480 0.0486 0.0552]
                    DischargeR0: [0.0484 0.0467 0.0460 0.0470 0.0483 0.0480 0.0486 0.0552]
                 DischargeFitPc: [100 100 100 100 100 100 100 100]

Estimate Parameters for Suite of HPPCTest Objects

You can perform battery HPPC testing at many different conditions, including temperature, SOC, current, and remaining capacity. You can then store these tests in more than one file. Simscape™ Battery™ refers to several HPPC test files as a HPPC test suite. HPPC test suites are typically categorized depending on the battery temperature at the start of each current pulse, which remains constant across different SOC values and load currents. In other cases, the initial temperature of the battery can also vary inside a given test file depending on the test settings and thermal environment.

In Simscape™ Battery™, you can estimate multi-dimensional parameter tables for a suite of HPPC tests by merging different battery ECM objects or by using an hppcTestSuite object.

Merge Battery ECM Objects

You can perform parameter estimation for different HPPCTest objects at different temperatures, SOC values, or currents, and subsequently merge the resulting parameters into a single ECM object with a single set of multi-dimensional parameter tables. In this section, you estimate the ECM parameters for an HPPC test conducted at 0°C. First load the HPPC data.

load("testDataBAKcells/hppcDataBAKcell0degC.mat")

Create the HPPCTest object by using the hppcTest function.

hppcExp0degC = hppcTest( hppcData,... 
    TimeVariable="time (s)",...
    VoltageVariable="voltage (V)",...
    CurrentVariable="current (A)",...
    Temperature=zeros(numel(hppcData(:,1)),1));

Estimate the ECM parameters by using the fitECM function.

batteryECM0degC = fitECM(hppcExp0degC, ...
    SegmentToFit="loadAndRelaxation");

The batteryEcm object you created before represents the ECM at 25°C. You can add or merge the 0 °C HPPC test parameters to the 25 °C model by using the mergeModelParameters function.

batteryEcm = mergeModelParameters(batteryEcm,batteryECM0degC);

Visualize the test parameter tables of the merged model.

disp(batteryEcm.TestParameterTables)
                       TestBreakpoints: [1×1 struct]
       ChargeOpenCircuitVoltageThermal: [2×14 double]
                       ChargeR0Thermal: [2×14 double]
                       ChargeR1Thermal: [2×14 double]
                     ChargeTau1Thermal: [2×14 double]
                       ChargeC1Thermal: [2×14 double]
                       ChargeR2Thermal: [2×14 double]
                     ChargeTau2Thermal: [2×14 double]
                       ChargeC2Thermal: [2×14 double]
                    ChargeFitPcThermal: [2×14 double]
    DischargeOpenCircuitVoltageThermal: [2×15 double]
                    DischargeR0Thermal: [2×15 double]
                    DischargeR1Thermal: [2×15 double]
                  DischargeTau1Thermal: [2×15 double]
                    DischargeC1Thermal: [2×15 double]
                    DischargeR2Thermal: [2×15 double]
                  DischargeTau2Thermal: [2×15 double]
                    DischargeC2Thermal: [2×15 double]
                 DischargeFitPcThermal: [2×15 double]

Verify that the test breakpoints are 0°C and 25°C as expected.

disp(batteryEcm.TestParameterTables.TestBreakpoints.ResistanceTemperatureBreakpoints)
     0
    25

Inspect the ChargeR0Thermal parameter values of the TestParameterTables property.

disp(batteryEcm.TestParameterTables.ChargeR0Thermal)
    0.0496    0.0502    0.0509    0.0501    0.0510    0.0501    0.0500    0.0502    0.0507    0.0491    0.0501    0.0459    0.0490    0.0403
    0.0384    0.0383    0.0383    0.0383    0.0384    0.0384    0.0382    0.0385    0.0390    0.0390    0.0400    0.0400    0.0403    0.0403

Use HPPCTestSuite Objects

To estimate multi-dimensional parameter tables for a suite of HPPC tests, first load HPPC files for experiments conducted at 10 °C, 35 °C, and 45 °C, and then create different HPPCTest objects.

load("testDataBAKcells/hppcDataBAKcell10degC.mat")
hppcExp10degC = hppcTest(hppcData, ...
    TimeVariable="time (s)", ...
    VoltageVariable="voltage (V)", ...
    CurrentVariable="current (A)", ...
    Temperature=repmat(10,numel(hppcData(:,1)),1));
load("testDataBAKcells/hppcDataBAKcell35degC.mat")
hppcExp35degC = hppcTest(hppcData, ...
    TimeVariable="time (s)", ...
    VoltageVariable="voltage (V)", ...
    CurrentVariable="current (A)", ...
    Temperature=repmat(35,numel(hppcData(:,1)),1));
load("testDataBAKcells/hppcDataBAKcell45degC.mat")
hppcExp45degC = hppcTest(hppcData, ...
    TimeVariable="time (s)", ...
    VoltageVariable="voltage (V)", ...
    CurrentVariable="current (A)", ...
    Temperature=repmat(45,numel(hppcData(:,1)),1));

To create an HPPCTestSuite object, use the hppcTestSuite function.

hppcSuite = hppcTestSuite([hppcExp0degC;hppcExp10degC;hppcExp25degC;hppcExp35degC;hppcExp45degC], ...
    Temperature=[0;10;25;35;45]);
disp(hppcSuite.SuiteSummary)
    TestID                      Test                      Temperature    NumPulses
    ______    ________________________________________    ___________    _________

      1       1×1 simscape.battery.parameters.HPPCTest         0            18    
      2       1×1 simscape.battery.parameters.HPPCTest        10            18    
      3       1×1 simscape.battery.parameters.HPPCTest        25            17    
      4       1×1 simscape.battery.parameters.HPPCTest        35            18    
      5       1×1 simscape.battery.parameters.HPPCTest        45            19    

To estimate the model parameters for an HPPCTestSuite object with the default ECM, use the fitECM function.

batteryEcm = fitECM(hppcSuite);

The fitECM function estimates the parameters for each pulse and stores the resulting parameters in the TestParameterTables property.

disp(batteryEcm.TestParameterTables)
                       TestBreakpoints: [1×1 struct]
       ChargeOpenCircuitVoltageThermal: [5×25 double]
                       ChargeR0Thermal: [5×25 double]
                       ChargeR1Thermal: [5×25 double]
                     ChargeTau1Thermal: [5×25 double]
                       ChargeC1Thermal: [5×25 double]
                       ChargeR2Thermal: [5×25 double]
                     ChargeTau2Thermal: [5×25 double]
                       ChargeC2Thermal: [5×25 double]
                    ChargeFitPcThermal: [5×25 double]
    DischargeOpenCircuitVoltageThermal: [5×25 double]
                    DischargeR0Thermal: [5×25 double]
                    DischargeR1Thermal: [5×25 double]
                  DischargeTau1Thermal: [5×25 double]
                    DischargeC1Thermal: [5×25 double]
                    DischargeR2Thermal: [5×25 double]
                  DischargeTau2Thermal: [5×25 double]
                    DischargeC2Thermal: [5×25 double]
                 DischargeFitPcThermal: [5×25 double]

These parameter tables can be different to the final model parameters that you use in Simscape Battery. The difference resides in the breakpoint properties that you specify for the ECM object. View the ModelParameterTables properties.

disp(batteryEcm.ModelParameterTables)
       ChargeOpenCircuitVoltageThermal: [3×11 double]
                       ChargeR0Thermal: [3×11 double]
                       ChargeR1Thermal: [3×11 double]
                     ChargeTau1Thermal: [3×11 double]
                       ChargeC1Thermal: [3×11 double]
                       ChargeR2Thermal: [3×11 double]
                     ChargeTau2Thermal: [3×11 double]
                       ChargeC2Thermal: [3×11 double]
                    ChargeFitPcThermal: [3×11 double]
    DischargeOpenCircuitVoltageThermal: [3×11 double]
                    DischargeR0Thermal: [3×11 double]
                    DischargeR1Thermal: [3×11 double]
                  DischargeTau1Thermal: [3×11 double]
                    DischargeC1Thermal: [3×11 double]
                    DischargeR2Thermal: [3×11 double]
                  DischargeTau2Thermal: [3×11 double]
                    DischargeC2Thermal: [3×11 double]
                 DischargeFitPcThermal: [3×11 double]

You can manually change the resistance breakpoints by updating the ResistanceTemperatureBreakpoints property of the batteryECM object.

batteryEcm.ResistanceTemperatureBreakpoints = simscape.Value([0,10,25,35,45]+273.15,"K");

View the updated ModelParameterTables property.

disp(batteryEcm.ModelParameterTables)
       ChargeOpenCircuitVoltageThermal: [3×11 double]
                       ChargeR0Thermal: [5×11 double]
                       ChargeR1Thermal: [5×11 double]
                     ChargeTau1Thermal: [5×11 double]
                       ChargeC1Thermal: [5×11 double]
                       ChargeR2Thermal: [5×11 double]
                     ChargeTau2Thermal: [5×11 double]
                       ChargeC2Thermal: [5×11 double]
                    ChargeFitPcThermal: [5×11 double]
    DischargeOpenCircuitVoltageThermal: [3×11 double]
                    DischargeR0Thermal: [5×11 double]
                    DischargeR1Thermal: [5×11 double]
                  DischargeTau1Thermal: [5×11 double]
                    DischargeC1Thermal: [5×11 double]
                    DischargeR2Thermal: [5×11 double]
                  DischargeTau2Thermal: [5×11 double]
                    DischargeC2Thermal: [5×11 double]
                 DischargeFitPcThermal: [5×11 double]

View the model parameters by using the plotModelParameters function.

batteryEcm.plotModelParameters();

Parameterize Battery Equivalent Circuit Block

You can parameterize the Battery Equivalent Circuit block as a final step in the parameterization workflow. This parameterization allows you to run battery simulations in Simulink®. To create a new Simulink battery model and add the Battery Equivalent Circuit block, use the createBatteryModel script.

if ~exist("batteryModel", 'file')
run("createBatteryModel.m")
end

Before parameterizing the block, you must obtain the block handle by using the getSimulinkBlockHandle function.

batteryBlockHandle = getSimulinkBlockHandle('batteryModel/Battery01');

To automatically parameterize the Battery Equivalent Circuit block, use the parameterizeEquivalentCircuitBlock function.

batteryEcm.parameterizeEquivalentCircuitBlock(batteryBlockHandle,...
    ParameterizePseudoOCV=true)

Open the Battery Equivalent Circuit block mask to verify that the final model contains the correct parameter tables.

See Also

| | | | | | | | | | | | |

Topics