Batteries are a critical part of any satellite’s power system.
They are used to provide power:
- During launch and after the launch of the satellite till the solar panels are deployed
- To the spacecraft, its equipment, and payload during the shadow phase
- For communication and data transfer
- To maintain the electronics at a specific temperature
Batteries with higher gravimetric(higher mass) and volumetric(higher volume) energy densities lead to lesser mass and volume for the power systems and thereby increase payload and mission capabilities.
A Saft space battery pack comprised of VES180SA space cells. Credit: SpaceNews |
That is why Lithium-ion batteries are so extensively used in satellites as power systems. A NiCD(nickel-cadmium) battery pack has as much as 50% less energy density as Li-ion batteries.
Batteries tend to degrade after continuous charge and discharge cycles. There is a need to develop an accurate remaining useful life(RUL) estimation system for Li-ion batteries. The estimated RUL can provide useful information to the ‘health management and maintenance’ and the ‘ground reliability assessment’ team. From this information, the maintenance team can plan the maintenance task schedule.
The approach of Lithium-ion battery RUL estimation
- Model-based approach
- Data-driven approach
The model-based approach makes use of battery characteristics and physical structure. The data-driven approach is not based on accurately modeling the physics of a system like the model-based approach but instead estimates RUL based on historical data.
I will be using the data-driven approach for this project.
The Dataset
The dataset used for this project can be downloaded here. This data has been collected from prognostics testbed at the NASA Ames Prognostics Center of Excellence (PCoE). The experiments were conducted until a 30% drop in the battery capacity(from 2 A·h to 1.4 A·h) was observed. This time-series data can be used for the development of prognostic algorithms that can accurately predict the RUL of Li-ion batteries.
Data Structure:
cycle: top level structure array containing the charge, discharge and impedance operations
type: operation type, can be charge, discharge or impedance
ambient_temperature: ambient temperature (degree C)
time: the date and time of the start of the cycle, in MATLAB date vector format
data: data structure containing the measurements
for charge the fields are:
Voltage_measured: Battery terminal voltage (Volts)
Current_measured: Battery output current (Amps)
Temperature_measured: Battery temperature (degree C)
Current_charge: Current measured at charger (Amps)
Voltage_charge: Voltage measured at charger (Volts)
Time: Time vector for the cycle (secs)
for discharge the fields are:
Voltage_measured: Battery terminal voltage (Volts)
Current_measured: Battery output current (Amps)
Temperature_measured: Battery temperature (degree C)
Current_charge: Current measured at load (Amps)
Voltage_charge: Voltage measured at load (Volts)
Time: Time vector for the cycle (secs)
Capacity: Battery capacity (Ahr) for discharge till 2.7V
for impedance the fields are:
Sense_current: Current in sense branch (Amps)
Battery_current: Current in battery branch (Amps)
Current_ratio: Ratio of the above currents
Battery_impedance: Battery impedance (Ohms) computed from raw data
Rectified_impedance: Calibrated and smoothed battery impedance (Ohms)
Re: Estimated electrolyte resistance (Ohms)
Rct: Estimated charge transfer resistance (Ohms)
Exploratory data analysis The battery data was provided in .mat format, I wrote a python script that parses .mat files and converts them into JSON objects.
def create_correspondence_data(self):
dom = PyQuery(self.url)
writer = csv.writer(open('correspondence.csv', 'wb'))
for i, img in enumerate(dom('img').items()):
img_src = img.attr['src']
print("%d => %s" % (i + 1, img_src))
writer.writerow([i + 1, img_src])
For visualization, I used the Matplotlib library.
Let us take a look at the battery capacity degradation at different ambient temperatures.
From the above diagrams, it can be noted that the capacity is not always continuously decreasing with every discharge cycle. Sometimes the capacity increases(eg cycle no 90 for the ambient temperature 24° C) resulting in distinctive spikes.
This is because of the self-charging effect of lithium-ion batteries. The explanation for this effect is during battery use chemical reactions take place, and the electrodes are deposited with chemical products, resulting in reduced chemical reactions. In order to melt the chemical products deposited, The battery requires a short rest period. The capacity of the battery increases suddenly owing to an increase in the available capacity in the next cycle.
Comparison of capacity degradation at different ambient temperature |
Plotting the capacity degradation data of the different ambient temperatures on a single plot we can see that the optimum temperature for the best performance of the battery is when the ambient temperature is 24°C since the capacity is higher than the battery maintained at 4°C and the degradation rate is lesser compared to the battery maintained at 43°C.
Charging performance
Let us now visualize the data and take a look at the charging profile of batteries at different temperatures.
The different columns of plots are:
- Voltage vs Time
- Current vs Time
- Temperature(Battery not Ambient temperature) vs Time
Voltage vs Time
The voltage increases non linearly until a point and then becomes constant. This is because the rated voltage of the battery is 4.2 so the voltage of the battery becomes constant at that point. This phase where the voltage increases non linearly is called the constant current phase here constant current is supplied to the battery till it becomes 4.2 volts. The phase where the voltage is constant is called the constant voltage phase since the voltage maintained here is constant.
Current vs Time
As mentioned previously, the constant current phase is a place where a constant current is supplied to the battery. During the constant voltage phase, the current declines non linearly in order to maintain a constant voltage. This is known as Trickle charging, where the fully charged battery is charged under load at a rate equal to its self-discharge rate, thus enabling the battery to remain at its fully charged level.
Temperature vs Time
Temperature is the highest at the point where the phase transitions from the constant current phase to the constant voltage phase.
Findings
- It can be seen that the batteries maintained at a lower temperature seem to reach the maximum voltage a lot sooner.
- As the cycle number increases the battery charging time increases with the exception of the battery maintained at 43°C. Further analysis of this is needed.
After looking at the graphs it can be seen that this is indeed true. The higher the clock number, the lesser is the charging time for the battery maintained at an ambient temperature of 43°C.
Discharge performance
Similarly, let us look at the discharge performance of batteries at different temperatures.
The different columns of plots are:
- Voltage vs Time
- Current vs Time
- Temperature(Battery not Ambient temperature) vs Time
Voltage vs Time
During a discharge cycle, the voltage discharges non linearly until the voltage becomes 0. After the voltage becomes 0, the voltage increases suddenly for a brief moment. This is due to the self-charging effect which was discussed earlier that increases the capacity of the battery for the next cycle.
Current vs Time
During a discharge cycle, a constant current is provided by the battery until the battery voltage becomes 0.
Temperature vs Time
Temperature is the highest when the battery voltage just reaches 0. After this phase, Self-charging phenomenon takes place due to the melting of deposits on the electrodes in the absence of chemical reactions.
Findings
- It can be seen that the batteries maintained at an ambient temperature of 24°C last a lot longer during the discharge cycle compared to the other two ambient temperature.
- As the cycle number increases the battery charging time decreases with the exception of the battery maintained at 4°C. Further analysis of this is needed.
After looking at the graphs it can be seen that this isn’t the case for all the cycles. The higher the clock number, the lesser is the discharging time, This makes sense as the capacity of the battery is known to decrease along with usage not increase. The capacity at cycle 0 was low because it was a new battery.
Model building
Now let us build a model to fit the data but first, we need to identify and remove outliers to increase prediction performance.
The outliers were detected using the rolling standard deviation method. Below is the python implementation of the rolling standard deviation method to identify outliers in the data.
def moving_average(data, window_size):
""" Computes moving average using discrete linear convolution of two one dimensional sequences.
Args:
-----
data (pandas.Series): independent variable
window_size (int): rolling window size
Returns:
--------
ndarray of linear convolution
API Reference: https://docs.scipy.org/doc/numpy/reference/generated/numpy.convolve.html"""
window = np.ones(int(window_size))/float(window_size)
return np.convolve(data, window, 'same')
def rollingAverage(x_stuff, y_stuff):
""" Helps in exploring the anamolies using rolling standard deviation
Args:
-----
x_stuff (pandas.Series): X variable
y_stuff (pandas.Series): Y variable
Returns:
--------
lst_x: List of X values where an outier was identified
lst_y: List of y values where an outier was identified
"""
window_size = 10 #rolling window size
sigma=1.0 #value for standard deviation
avg = moving_average(y_stuff, window_size)
avg_list = avg.tolist()
residual = y_stuff - avg
# Calculate the variation in the distribution of the residual
testing_std = residual.rolling(window_size).std()
testing_std_as_df = pd.DataFrame(testing_std)
rolling_std = testing_std_as_df.replace(np.nan,
testing_std_as_df.iloc[window_size - 1]).round(3).iloc[:,0].tolist()
rolling_std
std = np.std(residual)
lst=[]
lst_index = 0
lst_count = 0
for i in y_stuff.index:
if (y_stuff[i] > avg_list[lst_index] + (1.5 * rolling_std[lst_index])) | (y_stuff[i] < avg_list[lst_index] - (1.5 * rolling_std[lst_index])):
lt=[i,x_stuff[i], y_stuff[i],avg_list[lst_index],rolling_std[lst_index]]
lst.append(lt)
lst_count+=1
lst_index+=1
lst_x = []
lst_y = []
for i in range (0,len(lst)):
lst_x.append(lst[i][1])
lst_y.append(lst[i][2])
return lst_x, lst_y
The plot of capacity degradation along with identified outliers.
Identifying whether to use a linear model vs a non-linear model for RUL estimation
Residual plots can be useful to identify if a linear model is to be used or a non-linear.
The plot pattern that we obtain from the data is not random(U-shaped). This pattern indicates that a non-linear model is a better choice than a linear model to fit this data. For more information regarding residual plots visit this link.
Support vector regression
Support vector machines can not only be used for the classification problem but also for regression. The kernel used is RBF(radial basis function).
Python implementation of the code can be found below.
# Import the library
from sklearn.svm import SVR
# Create a support vector regression model
svr = SVR(C=20, epsilon=0.0001, gamma=0.00001, cache_size=200,
kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
svr.fit(X_train,y_train) # Fit the model
y_pred = svr.predict(X_test) # Perform prediction
Once the model is fit, The model can be used to estimate the capacity by taking cycle no as the input. The values of hyperparameters like C, epsilon, and gamma to obtain the best performance can be found out by using grid search and other parameter optimization techniques.
Now let us compare the model by fitting it to different batteries with different train size.
Battery 05
Battery 06
Battery 07
Battery 18
Conclusion
Support vector regression can be used to build an accurate and effective RUL estimation system for Li-ion batteries, given that the hyperparameters of the SVR are properly chosen.
All the code and Jupyter notebook implementation of this project can be found on my GitHub here.