from scipy.interpolate import interp1d #интерполяция/экстраполяция
import numpy as np #работа с массивами
Для примера возьмём насос Grundfos CR 3-3 напорная характеристика которого выглядит следующим образом (жирная линия - рабочий диапазон):
#Возьмём несколько точек с напорной характеристики (включая две крайних)
Qs = np.array([1.19, 2, 3, 4, 4.43])
Hs = np.array([18.01, 16.55, 13.64, 8.91, 6.14])
#Набор значений Q для построения графиков
Qs_int = np.linspace(Qs[0], Qs[-1], 51)
Воссоздадим по имеющимся точкам с помощью класса interp1d из библиотеки scipy.interpolate напорную характеристику, применив линейную, квадратичную и кубическую интерполяцию.
import matplotlib.pyplot as plt #библотека для построения графиков
plt.rcParams['figure.figsize'] = [14, 7]
plt.rcParams.update({'font.size': 14})
plt.plot(Qs, Hs,'o', label = "Точки напорной характеристики")
plt.plot(Qs_int, interp1d(Qs, Hs, kind='linear')(Qs_int), label = "Линейная интерполяция")
plt.plot(Qs_int, interp1d(Qs, Hs, kind='quadratic')(Qs_int), label = "Квадратичная интерполяция")
plt.plot(Qs_int, interp1d(Qs, Hs, kind='cubic')(Qs_int), label = "Кубическая интерполяция")
plt.xlabel('$Q, м^3/ч$')
plt.ylabel('$H, м$')
plt.xlim(Qs[0],Qs[-1]); plt.ylim(Hs[-1],Hs[0])
plt.xlim(1, 4.6); plt.ylim(0, 20)
plt.xticks(np.arange(1, 4.61, 0.2)); plt.yticks(np.arange(0, 21, 2))
plt.legend(); plt.grid()
Остановимся на кубической интерполяции c возможностью производить экстраполяцию (задав параметру fill_value класса interp1d значение "extrapolate"). Для применения кубической интерполяции необходимо задать не менее четырёх точек напорной характеристики, для квадратичной - не менее трёх. Экстраполяция понадобится при определении границы производственного допуска по подаче насоса (см. ниже).
#Напорная характеристика насоса
f_pump = interp1d(Qs, Hs, kind = 'cubic', fill_value = "extrapolate")
Qs_extr = np.linspace(0, 5.2, 51) #данные, включающие в себя значения Q, выходящие за пределы рабочего диапазона
plt.plot(Qs, Hs, "o") #точки, по которым осуществляется интерполяция/экстраполяция
plt.plot(Qs_extr, f_pump(Qs_extr)) #линия левее и правее крайних точек - это результат экстраполяции
plt.xlim(0, 5.2); plt.ylim(0,)
plt.xlabel('$Q, м^3/ч$'); plt.ylabel('$H, м$')
plt.grid()
Согласно ГОСТ ISO 9906-2015 производственные допуски по насосам мощностью не более 10 кВт составляют:
для подачи $\pm$10%,
для напора $\pm$8%.
tau_Q_u = 0.1 #Допуск по подаче, отклонение вверх
tau_Q_l = -0.1 #Допуск по подаче, отклонение вниз
tau_H_u = 0.08 #Допуск по напору, отклонение вверх
tau_H_l = -0.08 #Допуск по напору, отклонение вниз
H_Q_u = f_pump(Qs / (1 + tau_Q_u)) #напор при подаче левее Q на величину допуска вверх по подаче
H_Q_l = f_pump(Qs / (1 + tau_Q_l)) #напор при подаче правее Q на величину допуска вниз по подаче
#Объекты для построения границ производственных допусков
f_Q_u = interp1d(Qs, H_Q_u, kind='cubic') #верхняя по Q
f_Q_l = interp1d(Qs, H_Q_l, kind='cubic') #нижняя по Q
f_H_u = interp1d(Qs, Hs * (1 + tau_H_u), kind='cubic') #верхняя по H
f_H_l = interp1d(Qs, Hs * (1 + tau_H_l), kind='cubic') #нижняя по H
plt.plot(Qs_int, f_pump(Qs_int), label = "Номинальная напорная характеристика")
plt.plot(Qs_int, f_Q_u(Qs_int), label = "Верхняя граница допуска по подаче")
plt.plot(Qs_int, f_Q_l(Qs_int), label = "Нижняя граница допуска по подаче")
plt.plot(Qs_int, f_H_u(Qs_int), label = "Верхняя граница допуска по напору")
plt.plot(Qs_int, f_H_l(Qs_int), label = "Нижняя граница допуска по напору")
plt.xlabel('$Q, м^3/ч$'); plt.ylabel('$H, м$')
plt.xlim(1, 4.6); plt.ylim(0, 20)
plt.xticks(np.arange(1, 4.61, 0.2)); plt.yticks(np.arange(0, 21, 2))
plt.legend(); plt.grid()
Из вышеприведённого графика видно, что при малых Q значения допусков по напору больше допусков по подаче. Начиная с какого-то значения Q допуски по подаче становятся больше допусков по напору. Для определения границы допусков следует брать максимальное из двух значений для верхней границы и минимальное - для нижней. Создадим функции для верхней и нижней границ допусков.
#Верхняя и нижняя границы производственных допусков
#Верхняя граница
def f_border_u(Q):
#Q - массив значений подач или одно значение
if hasattr(Q, "__len__"): #если массив
#сравнивает допуск по Q и допуск по H и помещает в ответ-массив большее значение
return np.array(list(map(max, f_Q_u(Q), f_H_u(Q))))
else: #если одно значение
return max(f_Q_u(Q), f_H_u(Q))
#Нижняя граница
def f_border_l(Q):
#Q - массив значений подач или одно значение
if hasattr(Q, "__len__"): #если массив
#сравнивает допуск по Q и допуск по H и помещает в ответ-массив меньшее значение
return np.array(list(map(min, f_Q_l(Q), f_H_l(Q))))
else: #если одно значение
return min(f_Q_l(Q), f_H_l(Q))
plt.plot(Qs_int, f_pump(Qs_int), label = "Номинальная напорная характеристика")
plt.plot(Qs_int, f_border_u(Qs_int), label = "Верхняя граница производственных допусков")
plt.plot(Qs_int, f_border_l(Qs_int), label = "Нижняя граница производственных допусков")
plt.xlabel('$Q, м^3/ч$'); plt.ylabel('$H, м$')
plt.xlim(1, 4.6); plt.ylim(0, 20)
plt.xticks(np.arange(1, 4.61, 0.2)); plt.yticks(np.arange(0, 21, 2))
plt.legend(); plt.grid()
С течением времени рабочие характеристики насоса ухудшаются, происходит деградация напорной характеристики. Это означает, что при том же гидравлическом сопротивлении сети насос будет обеспечивать меньшее значение подачи. Предположим, что к концу срока службы деградация напорной характеристики насоса составила 10%, т.е. номинальную подачу насос может обеспечить при условии снижения сопротивления сети на 10%. Данное условие означает, что для каждого значения подачи $Q$ значение напора составит $H = H_{ном} \cdot 0.9$, где $H_{ном}$ - напор нового насоса при подаче $Q$.
Нижней границей рабочего диапазона насоса в течение всего срока службы является скорректированная на степень деградации нижняя граница производственных допусков нового насоса.
degr = 0.9 #степень деградации напорной характеристики
plt.plot(Qs_int, f_pump(Qs_int), label = "Номинальная напорная характеристика")
plt.plot(Qs_int, f_border_u(Qs_int), label = "Верхняя граница производственных допусков нового насоса")
plt.plot(Qs_int, f_border_l(Qs_int) * degr, label = "Нижняя граница производственных допусков изношенного насоса")
plt.xlabel('$Q, м^3/ч$'); plt.ylabel('$H, м$')
plt.xlim(1, 4.6); plt.ylim(0, 20)
plt.xticks(np.arange(1, 4.61, 0.2)); plt.yticks(np.arange(0, 21, 2))
plt.legend(); plt.grid()
Инженерные расчёты на Python, С.В. Медведев, 2020
Использование Python и Jupyter Notebook для инженерных расчётов, С.В. Медведев, 2020