воздух_сух_мас = {'N2': 0.75512, 'O2': 0.2315, 'Ar': 0.01292, 'CO2': 0.00046}
#воздух_сух_мас = {'N2': 0.7685, 'O2': 0.2315, 'Ar': 0., 'CO2': 0.}
sum(воздух_сух_мас.values())
1.0
# Молярные массы компонентов воздуха
H = 1; C = 12; N = 14; O = 16; Ar = 40
молярные_массы = {'N2': N*2, 'O2': O*2, 'Ar': Ar, 'CO2': C+O*2, 'H2O': H*2+O}
def определение_долей(смесь):
"""
Определение долей комппонентов в смеси
смесь: состав смеси, словарь вида {'компонент': количество, ...}
return: словарь вида {'компонент': доля, ...}
"""
сум = sum(смесь.values())
смесь_доли = {}
for компонент in смесь.keys():
смесь_доли[компонент] = смесь[компонент] / сум
return смесь_доли
def массовые_доли_в_объёмные_доли(смесь_мас):
"""
Перевод массовых долей компонентов смеси в объёмные
смесь: состав смеси, словарь вида {'компонент': массовая доля, ...}
return: словарь вида {'компонент': объёмная доля, ...}
"""
смесь_об = {}
for компонент in смесь_мас.keys():
смесь_об[компонент] = смесь_мас[компонент] / молярные_массы[компонент]
return определение_долей(смесь_об)
def объёмные_доли_в_массовые_доли(смесь_об):
"""
Перевод объёмных долей компонентов смеси в массовые
смесь: состав смеси, словарь вида {'компонент': объёмная доля, ...}
return: словарь вида {'компонент': массовая доля, ...}
"""
смесь_мас = {}
for компонент in смесь_об.keys():
смесь_мас[компонент] = смесь_об[компонент] * молярные_массы[компонент]
return определение_долей(смесь_мас)
воздух_сух_об = массовые_доли_в_объёмные_доли(воздух_сух_мас)
воздух_сух_об
{'N2': 0.7808738220538345, 'O2': 0.20947101597067996, 'Ar': 0.0093524510629501, 'CO2': 0.0003027109125356773}
объёмные_доли_в_массовые_доли(воздух_сух_об)
{'N2': 0.75512, 'O2': 0.2315, 'Ar': 0.012920000000000001, 'CO2': 0.00046}
# Нормальные условия для ГТУ (ГОСТ Р 52200-2004 (ИСО 3977-2:1997))
RH = 0.6 # относительная влажность 60%
p = 101300 # атмосферное давление, Па
t = 15 # температура окружающей среды, С
import sys
sys.path.append("../0009_Теплофизические_свойства_воды_и_ВП/")
from wsprops import SaturationCurve # см. [1]
sc = SaturationCurve()
ps = sc.p_t(t)
ps # давление насыщения = парциальное давление водяных паров при RH=100%, Па
1705.7448743923737
p_H2O = RH * ps # парциальное давление водяных паров при заданном RH
H2O_об_доля = p_H2O / p # объёмная доля водяных паров в воздухе
H2O_об_доля
0.010103128574880792
def добавить_компоненты(смесь, компоненты):
"""
Добавление новых компонентов в смесь
смесь: словарь вида {'компонент': доля в смеси без учёта добавляемых компонентов, ...}
компоненты: добавляемые компоненты - словарь вида {'компонент': доля в смеси, ...}
return: словарт {'компонент': доля в смеси, ...}
"""
смесь_новая = {}
k = 1 - sum(компоненты.values())
for компонент in смесь.keys():
смесь_новая[компонент] = смесь[компонент] * k
for компонент in компоненты.keys():
смесь_новая[компонент] = компоненты[компонент]
return смесь_новая
воздух_об = добавить_компоненты(воздух_сух_об, {'H2O': H2O_об_доля})
воздух_об
{'N2': 0.772984553428866, 'O2': 0.20735470336361728, 'Ar': 0.009257962047370834, 'CO2': 0.00029965258526530987, 'H2O': 0.010103128574880792}
воздух_мас = объёмные_доли_в_массовые_доли(воздух_об)
воздух_мас
{'N2': 0.7503591478682237, 'O2': 0.2300404475202535, 'Ar': 0.012838542470676784, 'CO2': 0.0004570998093275015, 'H2O': 0.006304762331518536}
sum(воздух_мас.values())
1.0
import pandas as pd # библиотека для создания таблиц
вещество = {'N2': 'Азот', 'O2': 'Кислород', 'Ar': 'Аргон',
'CO2': 'Углекислый газ', 'H2O': 'Водяной пар'}
обозначение = {'N2': 'N2', 'O2': 'O2', 'Ar': 'Ar',
'CO2': 'CO2', 'H2O': 'H2O'}
df = pd.DataFrame({'Вещество': вещество,'Обозначение': обозначение,
'Доля по массе': воздух_мас, 'Доля по объёму': воздух_об},
index = ['N2', 'O2', 'Ar', 'CO2', 'H2O'])
df = df.sort_values(by='Доля по массе', ascending = False) # сортировка по убыванию массовых долей
formatters={
'Доля по массе': '{:.2%}'.format,
'Доля по объёму': '{:.2%}'.format,
}
# Отображение таблицы в формате HTML
output = df.to_html(index=False, decimal=',', formatters = formatters)
def _format_output(s):
"""
Замена десятичного разделителя '.' на ',' и добавление тэгов для отображения нижних индексов
"""
for x, y in zip(('.', 'N2', 'O2', 'H2O', 'CO2'),
(',', 'N<sub>2</sub>', 'O<sub>2</sub>','H<sub>2</sub>O', 'CO<sub>2</sub>')):
s = s.replace(x, y)
return s
from IPython.core.display import HTML
display(HTML(_format_output(output)))
Вещество | Обозначение | Доля по массе | Доля по объёму |
---|---|---|---|
Азот | N2 | 75,04% | 77,30% |
Кислород | O2 | 23,00% | 20,74% |
Аргон | Ar | 1,28% | 0,93% |
Водяной пар | H2O | 0,63% | 1,01% |
Углекислый газ | CO2 | 0,05% | 0,03% |
Вещество | Обозначение | Доля по массе | Реакция окисления |
---|---|---|---|
Метан | CH4 | 97,3% | CH4 + 2O2 $\to$ CO2 + 2H2O |
Этан | C2H6 | 2,0% | 2C2H6 + 7O2 $\to$ 4CO2 + 6H2O |
Пропан | C3H8 | 0,5% | C3H8 + 5O2 $\to$ 3CO2 + 4H2O |
Бутан | C4H10 | 0,2% | 2C4H10 + 13O2 $\to$ 8CO2 + 10H2O |
# Добавим молярные массы компонентов топлива
молярные_массы.update({'CH4': C+H*4, 'C2H6': C*2+H*6, 'C3H8': C*3+H*8, 'C4H10': C*4+H*10})
молярные_массы
{'N2': 28, 'O2': 32, 'Ar': 40, 'CO2': 44, 'H2O': 18, 'CH4': 16, 'C2H6': 30, 'C3H8': 44, 'C4H10': 58}
топливо_мас = {'CH4': 0.973, 'C2H6': 0.02, 'C3H8': 0.005, 'C4H10': 0.002}
#топливо_мас = {'CH4': 1.}
топливо_об = массовые_доли_в_объёмные_доли(топливо_мас)
sum(топливо_мас.values()), sum(топливо_об.values())
(1.0, 0.9999999999999999)
топливо_об
{'CH4': 0.9867788143110114, 'C2H6': 0.010817719101730856, 'C3H8': 0.0018439293923404867, 'C4H10': 0.0005595371949171133}
# 'O2' - количество моль кислорода, необходимое для реакции окисления одного моля вещества
# 'CO2', 'H2O' - количество моль углекислого газа и воды, выделяемых в результате
# окисления одного моля вещества
окисление = {'CH4': {'O2': 2, 'CO2': 1, 'H2O': 2},
'C2H6': {'O2': 3.5, 'CO2': 2, 'H2O': 3},
'C3H8': {'O2': 5, 'CO2': 3, 'H2O': 4},
'C4H10': {'O2': 6.5, 'CO2': 4, 'H2O': 5}}
def мол_мас_смеси(смесь_об):
"""
Определение молярной массы смеси
смесь_об: состав смеси, словарь {компонент: объёмная_доля, ...}
return: масса одного моля смеси, г
"""
мол_мас = 0.
for компонент in смесь_об:
мол_мас += смесь_об[компонент] * молярные_массы[компонент]
return мол_мас
def мол_объём_смеси(смесь_мас):
"""
Определение молярного объёма смеси
смесь_мас: словарь {компонент: массовая_доля, ...}
return: количество моль в одном грамме смеси
"""
мол_об = 0.
for компонент in смесь_мас:
мол_об += смесь_мас[компонент] / молярные_массы[компонент]
return мол_об
def необх_кол_окисл_об(окислитель_об, топливо_об):
"""
Опредение минимального количеста моль окислителя, необходимое
для полного сжигания одного моля топлива
окислитель_об: состав окислителя, словарь {компонент: объёмная_доля, ...}
топливо_об: состав топлива, словарь {компонент: объёмная_доля, ...}
return: количество моль окислителя необходимое для полного сгорания одного моля топлива
"""
моль_кислорода = 0
for компонент in топливо_об.keys():
if компонент not in окисление.keys(): continue
моль_кислорода += топливо_об[компонент] * окисление[компонент]['O2']
return моль_кислорода / окислитель_об["O2"]
def необх_кол_окисл_мас(окислитель_мас, топливо_мас):
"""
Опредение минимального количества массы окислителя, необходимое
для полного сжигания одной единицы массы топлива
окислитель_мас: словарь {компонент: массовая_доля, ...}
топливо_мас: словарь {компонент: массовая_доля, ...}
return: количество грамм окислителя необходимое для полного сгорания одного грамма топлива
"""
топливо_об = массовые_доли_в_объёмные_доли(топливо_мас)
окислитель_об = массовые_доли_в_объёмные_доли(окислитель_мас)
необх_кол_окислит_об = необх_кол_окисл_об(окислитель_об, топливо_об)
мол_мас_топл = мол_мас_смеси(топливо_об)
мол_мас_окисл = мол_мас_смеси(окислитель_об)
return необх_кол_окислит_об * мол_мас_окисл / мол_мас_топл
моль_O2_на_моль_топл = необх_кол_окисл_об({'O2': 1}, топливо_об)
print(f'Для сжигания 1 моля топлива требуется {round(моль_O2_на_моль_топл,2)} моль кислорода ' +
f'или {round(моль_O2_на_моль_топл/воздух_об["O2"],2)} моль воздуха')
Для сжигания 1 моля топлива требуется 2.02 моль кислорода или 9.76 моль воздуха
мол_мас_топл = мол_мас_смеси(топливо_об); мол_мас_возд = мол_мас_смеси(воздух_об)
мол_мас_топл, мол_мас_возд
(16.22657865259628, 28.84427751363836)
кг_O2_на_кг_топл = моль_O2_на_моль_топл * молярные_массы["O2"]/мол_мас_топл
print(f'Для сжигания 1 кг топлива требуется {round(кг_O2_на_кг_топл,5)} кг кислорода ' +
f'или {round(кг_O2_на_кг_топл/воздух_мас["O2"],2)} кг воздуха')
Для сжигания 1 кг топлива требуется 3.99202 кг кислорода или 17.35 кг воздуха
необх_кол_окисл_мас({'O2': 1}, топливо_мас)
3.9920208986415884
воздух_мас
{'N2': 0.7503591478682237, 'O2': 0.2300404475202535, 'Ar': 0.012838542470676784, 'CO2': 0.0004570998093275015, 'H2O': 0.006304762331518536}
def кнт_изб_окисл(окисл_мас, топливо_мас, окисл_колич, топливо_колич):
"""
Определение коэффициент избытка окислителя
окисл_мас: состав окислителя, словарь {компонент: массовая_доля, ...}
топливо_мас: состав топлива, словарь {компонент: массовая_доля, ...}
окисл_колич: количество окислителя, кг или кг/с
топливо_колич: количество топлива, кг или кг/с
return: коэффициент избытка окислителя
"""
необх_кол_окисл = необх_кол_окисл_мас(окисл_мас, топливо_мас)
return окисл_колич / (необх_кол_окисл * топливо_колич)
def горение_выхл_газы_кнт_изб_окисл(окисл_мас, топливо_мас, кнт_изб_окисл):
"""
Определение массовой концентрации веществ в выхлопных газах
окисл_мас: состав окислителя, словарь {компонент: массовая_доля, ...}
топливо_мас: состав топлива, словарь {компонент: массовая_доля, ...}
кнт_изб_окисл: коэффициент избытка окислителя
return: состав выхлопных газов, словарь {компонент: массовая_доля, ...}
"""
# расчёт для 1 моль топлива
окисл_об = массовые_доли_в_объёмные_доли(окисл_мас)
топливо_об = массовые_доли_в_объёмные_доли(топливо_мас)
необх_кол_молей_окисл = необх_кол_окисл_об(окисл_об, топливо_об)
состав_выхл_газов = (окисл_об.keys() | {'CO2', 'H2O'})
выхл_газы = {key: 0. for key in состав_выхл_газов}
выхл_газы['O2'] = (кнт_изб_окисл - 1) * окисл_об['O2'] * необх_кол_молей_окисл
for компонент in (окисл_об.keys() - {'O2'}):
#if компонент == 'O2': continue
выхл_газы[компонент] = окисл_об[компонент] * кнт_изб_окисл * необх_кол_молей_окисл
for компонент in топливо_об.keys():
if компонент not in окисление.keys():
# для негорючих элементов
выхл_газы[компонент] += топливо_об[компонент]
else:
# химическая реакция окисления
выхл_газы['CO2'] += топливо_об[компонент] * окисление[компонент]['CO2']
выхл_газы['H2O'] += топливо_об[компонент] * окисление[компонент]['H2O']
return объёмные_доли_в_массовые_доли(определение_долей(выхл_газы))
def горение_выхл_газы (окисл_мас, топливо_мас, окисл_колич, топливо_колич):
"""
Определение массовой концентрации веществ в выхлопных газах
окисл_мас: состав окислителя, словарь {компонент: массовая_доля, ...}
топливо_мас: состав топлива, словарь {компонент: массовая_доля, ...}
окисл_колич: количество окислителя, кг или кг/с
топливо_колич: количество топлива, кг или кг/с
return: состав выхлопных газов, словарь {компонент: массовая_доля, ...}
"""
кнт_избыт_ок = кнт_изб_окисл(окисл_мас, топливо_мас, окисл_колич, топливо_колич)
return топливо_колич * горение_выхл_газы_кнт_изб_окисл(окисл_мас, топливо_мас, кнт_избыт_ок)
выхл_газы = горение_выхл_газы_кнт_изб_окисл(воздух_мас, топливо_мас, 4)
выхл_газы
{'CO2': 0.03958311186305883, 'Ar': 0.012656213699283958, 'O2': 0.1700801163729239, 'H2O': 0.03797776482918392, 'N2': 0.7397027932355494}
sum(выхл_газы.values())
1.0
# Формирование данных для таблицы
состав_мас = {}; состав_об = {}
кнт_изб_возд = [1, 2, 3, 4, 5]
for alfa in кнт_изб_возд:
состав_мас[str(alfa)] = горение_выхл_газы_кнт_изб_окисл(воздух_мас, топливо_мас, alfa)
состав_об[str(alfa)] = массовые_доли_в_объёмные_доли(состав_мас[str(alfa)])
состав_мас['Воздух'] = воздух_мас
состав_об['Воздух'] = воздух_об
formatters={
'1': '{:.2%}'.format,
'2': '{:,.2%}'.format,
'3': '{:,.2%}'.format,
'4': '{:,.2%}'.format,
'5': '{:,.2%}'.format,
'Воздух': '{:,.2%}'.format
}
# Все три нижеприведённых способа объединения словарей работоспособны
#data = dict(list({'Вещество': вещество,'Обозначение': обозначение}.items()) \
#+ list(состав_мас.items()))
#data = {**{'Вещество': вещество,'Обозначение': обозначение}, **состав_мас}
data = {'Вещество': вещество,'Обозначение': обозначение}
data.update(состав_мас)
df = pd.DataFrame(data, index = ['N2', 'O2', 'Ar', 'CO2', 'H2O'])
output = df.to_html(index = False, formatters=formatters)
output = output.replace('.', ',')
display(HTML(_format_output(output)))
# Состав выхлопных газов (по массе) при различных значениях коэффициента избытка воздуха
Вещество | Обозначение | 1 | 2 | 3 | 4 | 5 | Воздух |
---|---|---|---|---|---|---|---|
Азот | N2 | 70,95% | 72,93% | 73,62% | 73,97% | 74,18% | 75,04% |
Кислород | O2 | 0,00% | 11,18% | 15,05% | 17,01% | 18,19% | 23,00% |
Аргон | Ar | 1,21% | 1,25% | 1,26% | 1,27% | 1,27% | 1,28% |
Углекислый газ | CO2 | 15,06% | 7,76% | 5,24% | 3,96% | 3,18% | 0,05% |
Водяной пар | H2O | 12,78% | 6,88% | 4,83% | 3,80% | 3,17% | 0,63% |
data.update(состав_об)
df = pd.DataFrame(data, index = ['N2', 'O2', 'Ar', 'CO2', 'H2O'])
output = df.to_html(index = False, formatters=formatters)
output = output.replace('.', ',')
display(HTML(_format_output(output)))
# Состав выхлопных газов (по объёму) при различных значениях коэффициента избытка воздуха
Вещество | Обозначение | 1 | 2 | 3 | 4 | 5 | Воздух |
---|---|---|---|---|---|---|---|
Азот | N2 | 70,06% | 73,50% | 74,73% | 75,35% | 75,73% | 77,30% |
Кислород | O2 | 0,00% | 9,86% | 13,36% | 15,16% | 16,25% | 20,74% |
Аргон | Ar | 0,84% | 0,88% | 0,89% | 0,90% | 0,91% | 0,93% |
Углекислый газ | CO2 | 9,46% | 4,98% | 3,38% | 2,57% | 2,07% | 0,03% |
Водяной пар | H2O | 19,64% | 10,78% | 7,63% | 6,02% | 5,04% | 1,01% |
import numpy as np
n = len(состав_мас)
ind = np.arange(n)
elems = ['N2', 'O2', 'CO2', 'H2O', 'Ar']
colors = ['c', 'g', 'k', 'b', 'y']
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize = (9, 5))
btm = np.array(n*[0.])
p = n*[None]
ax.set_xticks(ind)
ax.set_xticklabels(['1', '2', '3', '4', '5', 'Воздух'])
ax.set_ylim(0,100)
for i, elem in enumerate(elems):
values = np.array([el[elem] for el in состав_мас.values()]) * 100
p[i] = ax.bar(ind, values, label=elem, color=colors[i], bottom = btm)
btm += values
ax.set_xlabel('Коэффициент избытка воздуха'); ax.set_ylabel('Доли по массе, %')
ax.legend(); ax.yaxis.grid(True, color = 'grey')
plt.show()
fig, ax = plt.subplots(figsize = (9, 5))
btm = np.array(n*[0.])
p = n*[None]
ax.set_xticks(ind)
ax.set_xticklabels(['1', '2', '3', '4', '5', 'Воздух'])
ax.set_ylim(0,100)
for i, elem in enumerate(elems):
values = np.array([el[elem] for el in состав_об.values()]) * 100
p[i] = ax.bar(ind, values, label=elem, color=colors[i], bottom = btm)
btm += values
ax.set_xlabel('Коэффициент избытка воздуха'); ax.set_ylabel('Доли по объёму, %')
ax.legend(); ax.yaxis.grid(True, color = 'grey')
plt.show()
Инженерные расчёты на Python, С.В. Медведев, 2020-2024
Использование Python и Jupyter Notebook для инженерных расчётов, С.В. Медведев, 2020-2024