Вопрос или проблема
Я работаю над интерполяцией данных емкости батареи на основе взаимосвязей между hour_rates
, capacities
и currents
. Вот образец моих данных:
import numpy as np
import pandas as pd
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
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.9],
[50, 438, 8.76], [72, 459, 6.38], [100, 486, 4.86]
]
capacity = pd.DataFrame(capacity_data, columns=['hour_rates', 'capacities', 'currents'])
Столбцы соотносятся следующим образом:
hour_rates (ч) = capacities (Ah) / currents (A)
capacities (Ah) = hour_rates (ч) * currents (A)
currents (A) = capacities (Ah) / hour_rates (ч)
Цель: Я хочу интерполировать capacities
и hour_rates
для диапазона значений currents
с использованием логарифмической шкалы для лучшей точности.
Код
Пользовательский класс интерполяции и функция для достижения этой цели. Вот код:
from typing import Union
class interpolate1d(interp1d):
"""Расширение scipy interp1d для интерполяции/экстраполяции по осям в логарифмическом пространстве"""
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
):
"""
Интерполировать значения емкости батареи из списка значений тока
"""
result = 0
if isinstance(np_data, np.ndarray):
# Создание функций интерполяции для часовых норм и емкостей
# Установка kind='cubic' для лучшего соответствия нелинейным данным
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'
# Вычисление интерполированных значений для новых токов
hour_rate_interpolated = hour_rate_interp_func(current_values)
capacity_interpolated = capacity_interp_func(current_values)
# Создание DataFrame для результатов
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,
):
"""Установка основных меток сетки по оси X"""
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="Интерполированная емкость")
plt.plot(capacities['hour_rates'], capacities['calc_cap'], label="Вычисленная емкость")
plt.plot(capacity['hour_rates'], capacity['capacities'], label="Емкость")
plt.ylabel('Емкость (А/ч)')
plt.xlabel('Часовая норма (ч)')
plt.title('Взаимосвязь часовой нормы/емкости батареи')
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="Интерполированный ток (А)")
plt.plot(capacity['hour_rates'], capacity['currents'], label="Ток (А)")
plt.ylabel('Ток (А)')
plt.xlabel('Часовая норма (ч)')
plt.title('Взаимосвязь часовой нормы/тока батареи')
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="Интерполированная емкость / ток")
plt.plot(capacities['currents'], capacities['calc_cap'], label="Вычисленная емкость / ток")
plt.plot(capacity['currents'], capacity['capacities'], label="емкость / ток")
plt.ylabel('Емкость (А/ч)')
plt.xlabel('Ток (А)')
plt.title('Взаимосвязь тока/емкости батареи')
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="Разница в емкости")
plt.plot(capacities['hour_rates'], capacities['diff_hr'], label="Разница в часовой норме")
plt.ylabel('Разница интерполированного / вычисленного')
plt.xlabel('Часовая норма (ч)')
plt.title('Взаимосвязь данных интерполяции по часовой норме')
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="Разница в емкости")
plt.plot(capacities['capacities'], capacities['diff_hr'], label="Разница в часовой норме")
plt.ylabel('Разница интерполированного / вычисленного')
plt.xlabel('Емкость (А/ч)')
plt.title('Взаимосвязь данных интерполяции по емкости')
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="Разница в емкости")
plt.plot(capacities['currents'], capacities['diff_hr'], label="Разница в часовой норме")
plt.ylabel('Разница интерполированного / вычисленного')
plt.xlabel('Ток (А)')
plt.title('Взаимосвязь данных интерполяции по току')
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 А, 135 А) могут привести к неточным результатам из-за экстраполяции. Тем не менее, я замечаю неточности в пределах диапазона, особенно между 5 А и 25 А. Почему интерполированные значения в этом диапазоне могут быть неправильными?
Ответ или решение
Интерполяция данных ёмкости аккумуляторов с использованием логарифмической шкалы в Python
Работа с данными ёмкости аккумуляторов требует точности и аккуратности, особенно при интерполяции значений, основанных на соотношениях между такими переменными, как hour_rates (часы разряда), capacities (ёмкость) и currents (токи). В данном случае возникли проблемы, связанные с тем, что интерполированные значения не совпадают с рассчитанными, даже с использованием логарифмической шкалы. Давайте подробно рассмотрим эту задачу и предложим возможные пути её решения.
Исходные данные
Ваши исходные данные представлены в таком формате:
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.9],
[50, 438, 8.76], [72, 459, 6.38], [100, 486, 4.86]
]
Переменные данных и их отношения
- hour_rates (h): показывает, как долго аккумулятор разряжается.
- capacities (Ah): ёмкость аккумулятора.
- currents (A): ток, при котором происходит разрядка.
Используя эти данные, можно вывести формулы, которые связывают эти переменные:
hour_rates = capacities / currents
capacities = hour_rates * currents
currents = capacities / hour_rates
Цель
Основная цель заключается в интерполяции значений capacities и hour_rates для заданного диапазона значений currents с использованием логарифмической шкалы для повышения точности.
Код интерполяции
Для выполнения этой задачи вы создали расширенный класс interpolate1d
, который помогает интерполировать значения в логарифмическом пространстве, вот как выглядит часть важного кода:
class interpolate1d(interp1d):
"""Расширенный класс interp1d для интерполяции в логарифмическом пространстве"""
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)
Проблема с интерполяцией
Несмотря на использование логарифмической шкалы, некоторые интерполированные значения не совпадают с рассчитанными. Это может быть связано с несколькими причинами:
-
Неправильный выбор метода интерполяции: Попробуйте использовать другие методы интерполяции, такие как
cubic
илиquadratic
, поскольку ваши данные могут быть нелинейными в этом диапазоне. -
Проблемы с экстраполяцией: Убедитесь, что значения токов не выходят за пределы диапазона ваших исходных данных. Экстраполяция может привести к несоответствиям.
-
Неверная логика в расчетах: Проверьте, достаточно ли точно вы рассчитываете capacities и hour_rates из интерполированных значений, используя исходные соотношения.
Рекомендации по улучшению точности интерполяции
-
Преобразование данных: Перед интерполяцией убедитесь, что данные нормализованы. Это может улучшить эффективность интерполяции.
-
Проверка диапазона данных: Ограничьте значения токов, которые вы интерполируете, теми, которые находятся в пределах вашего набора данных.
-
Анализ ошибок: После интерполяции проводите анализ ошибок между интерполированными и рассчитанными значениями. Это поможет вам понять, в каких конкретных областях возникают проблемы.
-
Графическое представление: Визуализация ваших данных может помочь выявить области слабой точности и улучшить настройки интерполяции.
Заключение
Точность интерполяции данных ёмкости аккумуляторов в логарифмическом масштабе зависит от множества факторов, включая выбор метода интерполяции и корректность расчетов. Следуя предложенным рекомендациям и проводя детальный анализ ошибок, вы сможете значительно улучшить результаты вашей работы.