我正在根据
hour_rates
、capacities
和 currents
之间的关系来插值电池容量数据。这是我的数据示例:
import numpy as np
import pandas as pd
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
# Data from Rolls S-480 flooded battery
capacity_data = [
[1, 135, 135], [2, 191, 95.63], [3, 221, 73.75],
[4, 244, 60.94], [5, 263, 52.5], [6, 278, 46.25],
[8, 300, 37.5], [10, 319, 31.88], [12, 334, 27.81],
[15, 352, 23.45], [20, 375, 18.75], [24, 386, 16.09],
[50, 438, 8.76], [72, 459, 6.38], [100, 486, 4.86]
]
capacity = pd.DataFrame(capacity_data, columns=['hour_rates', 'capacities', 'currents'])
各列的关系如下:
hour_rates (h) = capacities (Ah) / currents (A)
capacities (Ah) = hour_rates (h) * currents (A)
currents (A) = capacities (Ah) / hour_rates (h)
目标:我想使用对数缩放对
capacities
和 hour_rates
进行插值以获取一系列 currents
值,以提高准确性。
自定义插值类和函数来实现此目的。代码如下:
from typing import Union
class interpolate1d(interp1d):
"""Extend scipy interp1d to interpolate/extrapolate per axis in log space"""
def __init__(self, x, y, *args, xspace='linear', yspace='linear', **kwargs):
self.xspace = xspace
self.yspace = yspace
if self.xspace == 'log': x = np.log10(x)
if self.yspace == 'log': y = np.log10(y)
super().__init__(x, y, *args, **kwargs)
def __call__(self, x, *args, **kwargs):
if self.xspace == 'log': x = np.log10(x)
if self.yspace == 'log':
return 10**super().__call__(x, *args, **kwargs)
else:
return super().__call__(x, *args, **kwargs)
def interpolate_cap_by_current(df: list,
current_values: list,
kind: Union[str, int] = 'linear',
hr_limit: int = 600
):
"""
Interpolate Battery Capacity Values From Current list values
"""
result = 0
if isinstance(np_data, np.ndarray):
# Create interpolation functions for hour rates and capacities
# Setting kind='cubic' for better fitting to nonlinear data
hour_rate_interp_func = interpolate1d(
df['currents'],
df['hour_rates'],
xspace='log',
yspace='log',
fill_value="extrapolate",
kind=kind
)
capacity_interp_func = interpolate1d(
df['currents'],
df['capacities'],
xspace='log',
yspace='log',
fill_value="extrapolate",
kind=kind
) # , kind='cubic'
# Calculate interpolated values for new currents
hour_rate_interpolated = hour_rate_interp_func(current_values)
capacity_interpolated = capacity_interp_func(current_values)
# Create a DataFrame for the results
real_cap = current_values * hour_rate_interpolated
real_hr = capacity_interpolated / current_values
result = pd.DataFrame({
'currents': current_values,
'hour_rates': hour_rate_interpolated,
'capacities': capacity_interpolated,
'calc_cap': real_cap,
'diff_cap': capacity_interpolated - real_cap,
'calc_hr': real_hr,
'diff_hr': hour_rate_interpolated - real_hr,
})
result = result[result['hour_rates'] < hr_limit]
return result
def plot_grid(major_ticks: list,
minor_ticks: list,
):
"""Set X Grid ticks"""
ax=plt.gca()
ax.grid(True)
ax.set_xticks(major_ticks)
ax.set_xticks(minor_ticks, minor=True)
ax.grid(which='minor', alpha=0.2)
ax.grid(which='major', alpha=0.5)
currents_list = np.array([
0.1, 0.2, 0.4, 0.5, 0.6, 0.8, 1, 1.5, 1.7, 2, 2.2, 2.5,
3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 17, 20, 22, 25, 27, 30, 32,
35, 37, 40, 60, 80, 120, 150, 180, 220, 250
])
capacities = interpolate_cap_by_current(
df=capacity,
current_values=currents_list,
kind='quadratic'
)
# linear, nearest, nearest-up, zero, slinear, quadratic, cubic, previous, or next. zero, slinear, quadratic and cubic
plt.figure(figsize=(18, 15))
plt.subplot(3, 1, 1)
plt.plot(capacities['hour_rates'], capacities['capacities'], label='Interpolated Capacitiy')
plt.plot(capacities['hour_rates'], capacities['calc_cap'], label='Calculated Capacitiy')
plt.plot(capacity['hour_rates'], capacity['capacities'], label='Capacitiy')
plt.ylabel('Capacity (A/h)')
plt.xlabel('Hour Rate (h)')
plt.title('Battery Hour Rate / Capacity relationship')
plt.legend()
max_tick = capacities['hour_rates'].max() + 10
plot_grid(
major_ticks=np.arange(0, max_tick, 20),
minor_ticks=np.arange(0, max_tick, 5)
)
plt.subplot(3, 1, 2)
plt.plot(capacities['hour_rates'], capacities['currents'], label='Interpolated Current (A)')
plt.plot(capacity['hour_rates'], capacity['currents'], label='Current (A)')
plt.ylabel('Current (A)')
plt.xlabel('Hour Rate (h)')
plt.title('Battery Hour Rate / Current relationship')
plt.legend()
plot_grid(
major_ticks=np.arange(0, max_tick, 20),
minor_ticks=np.arange(0, max_tick, 5)
)
plt.subplot(3, 1, 3)
plt.plot(capacities['currents'], capacities['capacities'], label='Interpolated capacity / current')
plt.plot(capacities['currents'], capacities['calc_cap'], label='Calculated capacity / current')
plt.plot(capacity['currents'], capacity['capacities'], label='capacity / current')
plt.ylabel('Capacity (A/h)')
plt.xlabel('Current (A)')
plt.title('Battery Current / Capacity relationship')
plt.xscale('linear')
plt.yscale('linear')
plt.legend()
max_tick = capacities['currents'].max() + 10
plot_grid(
major_ticks=np.arange(0, max_tick, 20),
minor_ticks=np.arange(0, max_tick, 5)
)
尽管我已经在对数空间中配置了插值,但根据提供的关系进行验证时,插值值仍然与计算值不匹配。我在下图中说明了这种差异,其中我通过将原始关系应用于插值结果来计算差异。
plt.figure(figsize=(18, 15))
plt.subplot(3, 1, 1)
plt.plot(capacities['hour_rates'], capacities['diff_cap'], label='Diff Capacity')
plt.plot(capacities['hour_rates'], capacities['diff_hr'], label='Diff Hour Rate')
plt.ylabel('Diff Interpolated / Calculated')
plt.xlabel('Hour Rate (h)')
plt.title('Interpolation Data Relationship By Hour Rate')
plt.legend()
max_tick = capacities['hour_rates'].max() + 10
plot_grid(
major_ticks=np.arange(0, max_tick, 20),
minor_ticks=np.arange(0, max_tick, 5)
)
plt.subplot(3, 1, 2)
plt.plot(capacities['capacities'], capacities['diff_cap'], label='Diff Capacity')
plt.plot(capacities['capacities'], capacities['diff_hr'], label='Diff Hour Rate')
plt.ylabel('Diff Interpolated / Calculated')
plt.xlabel('Capacity (A/h)')
plt.title('Interpolation Data Relationship By Capacity')
plt.legend()
max_tick = capacities['capacities'].max() + 10
plot_grid(
major_ticks=np.arange(0, max_tick, 20),
minor_ticks=np.arange(0, max_tick, 5)
)
plt.subplot(3, 1, 3)
plt.plot(capacities['currents'], capacities['diff_cap'], label='Diff Capacity')
plt.plot(capacities['currents'], capacities['diff_hr'], label='Diff Hour Rate')
plt.ylabel('Diff Interpolated / Calculated')
plt.xlabel('Current (A)')
plt.title('Interpolation Data Relationship By Current')
plt.legend()
max_tick = capacities['currents'].max() + 10
plot_grid(
major_ticks=np.arange(0, max_tick, 20),
minor_ticks=np.arange(0, max_tick, 5)
)
有没有办法提高这种类型的数据关系的对数尺度插值的准确性?据我了解,超出(4.86 A、135 A)范围的电流值可能会因外推而导致结果不准确。
查看您的货币数据描述的关系:
hour_rates (h) = capacities (Ah) / currents (A)
capacities (Ah) = hour_rates (h) * currents (A)
currents (A) = capacities (Ah) / hour_rates (h)
您提供的数据中没有明确满足这些要求。我创建的数据与所呈现的结果完全相同:
capacity_data_corr = capacity[['hour_rates', 'capacities']]
capacity_data_corr['currents'] = capacity_data_corr['capacities']/capacity_data_corr['hour_rates']
插值几乎是理想的
这意味着,获得的插值可能很好,但数据不满足假设的关系。如果这些关系只是近似的,那么在如此长的时间范围内,像这样的错误应该不会像看起来那么糟糕。