Determination of gas density from the results of measuring pressure and temperature with Arduino sensors
Introduction
The task of measuring the parameters of a gas mixture is widespread in industry and commerce. The problem of obtaining reliable information when measuring the parameters of the state of the gas environment and its characteristics with the help of technical means is resolved by standard measurement techniques (MVI), for example, when measuring the flow and amount of gases using standard narrowing devices [1], or using turbine, rotary and vortex flowmeters and counters [2].
Periodic gas analysis allows to establish the correspondence between the actual mixture being analyzed and its model, according to which the physicochemical parameters of the gas are taken into account in the MVI: the composition of the gas mixture and the density of the gas under standard conditions.
MVI also takes into account the thermophysical characteristics of the gas: the density at the operating conditions (pressure and temperature of the gas at which measurement of its flow or volume is performed), viscosity, factor and compressibility factor.
The parameters of gas state measured in real time include pressure (pressure differential), temperature, density. Means of measuring equipment are used to measure these parameters: manometers (differential pressure gauges), thermometers, and density meters. Measurement of the density of the gas medium can be measured directly or indirectly by measurement methods. The results of both direct and indirect measurement methods depend on the error of the measuring instrument and the methodical error. Under operating conditions, the measurement information signals may be subject to significant noise, the standard deviation of which may exceed the instrumental error. In this case, the actual task is the effective filtering of measurement information signals.
This article discusses the method of indirect measurement of gas density under operating and standard conditions using the Kalman filter.
Mathematical model for determining gas density
Let us turn to the classics and recall the equation of state of an ideal gas [3]. We have:
1. The Mendeleev-Clapeyron equation:

where:


The R - universal gas constant

T is the absolute temperature, T = 273.16 K.
2. Two measured parameters:
p is the gas pressure, Pa
t is the gas temperature, ° C.
It is known that the molar volume



It is also known that

where: m is the mass of gas, M is the molar mass of gas.
Considering (2) and (3), we rewrite (1) in the form:

As is known, the density of a substance


From (4) and (5), we derive the equation for the gas density


and introduce the parameter designation


If the composition of the gas mixture does not change, then the parameter k is constant.
So, to calculate the gas density, it is necessary to calculate the molar mass of the gas mixture.
The molar mass of the mixture of substances is determined as the arithmetic average weighted molar mass of the mass fractions included in the mixture of individual substances.
We take the known composition of substances in the gas mixture - in the air, which consists of:
- 23% by weight of oxygen molecules
- 76% by weight of nitrogen molecules
- 1% by weight of argon atoms
The molar masses of these air substances will be respectively equal:,

We calculate the molar mass of air as the weighted arithmetic average:

Now, knowing the value of the constant



Reducing gas density to normal, standard conditions
In practice, measurements of the properties of gases are carried out in different physical conditions, and standard sets of conditions should be established to provide a comparison between different data sets [4].
Standard conditions for temperature and pressure are the physical conditions established by the standard to which properties of substances are correlated, depending on these conditions.
Various organizations set their standard conditions, for example: the International Union of Pure and Applied Chemistry (IUPAC), established the definition of standard temperature and pressure (STP) in the field of chemistry: temperature 0 ° C (273.15 K), absolute pressure 1 bar (Pa); The National Institute of Standards and Technology (NIST) sets a temperature of 20 ° C (293.15 K) and an absolute pressure of 1 atm (101.325 kPa), and this standard is called the normal temperature and pressure (NTP); The International Organization for Standardization (ISO) establishes standard conditions for natural gas (ISO 13443: 1996, confirmed in 2013): a temperature of 15.00 ° C and an absolute pressure of 101.325 kPa.
Therefore, in industry and commerce it is necessary to specify the standard conditions for temperature and pressure, relative to which and to carry out the necessary calculations.
We calculate the air density by equation (8) under the working conditions of temperature and pressure. In accordance with (6), we write the equation for air density under standard conditions: temperature



We calculate the air density, reduced to standard conditions. We divide equation (9) by equation (6) and write this relation for


In a similar way, we obtain the equation for calculating the density of air, reduced to normal conditions: temperature



In equations (10) and (11), we use the values of the air parameters

The implementation of the measuring channel pressure and temperature
To solve many problems of obtaining information, depending on their complexity, it is convenient to create a prototype of a future system based on one of the microcontroller platforms such as Arduino, Nucleo, Teensy, etc.
What could be simpler? Let's make a microcontroller platform for solving a specific task - creating a system for measuring pressure and temperature, spending less, possibly, means, and using all the advantages of developing software in the Arduino Software (IDE) environment.
For this, at the hardware level, we need the components:
- Arduino (Uno, ...) - use as a programmer;
- ATmega328P-PU microcontroller - a microcontroller of the future platform;
- a 16 MHz crystal oscillator and a pair of ceramic capacitors of 12-22 pF each (as recommended by the manufacturer);
- clock button to reset the microcontroller and pull-up plus power to the RESET pin of the microcontroller 1 kΩ resistor;
- BMP180 - temperature and pressure measuring transducer with I2C interface;
- TTL / USB interface converter;
- consumables - wires, solder, circuit board, etc.
A schematic diagram of the platform, taking into account the necessary interfaces: standard serial interface, I2C, and nothing more, is presented in Fig. 1.

Fig. 1 - Schematic diagram of the microcontroller to implement the platform system pressure and temperature measurements
Now consider steps of our problem.
1. First, we need a programmer. We connect Arduino (Uno, ...) to the computer. In the Arduno Software environment, from the menu along File-> Examples-> 11. ArdunoISP get to the programmer programmer ArduinoISP, which we sew in Arduino. Previously, from the Tools menu, select, respectively, the board, processor, bootloader, port. After Downloads Program ArduinoISPin charge, our Arduino turns into a programmer and is ready for use as intended. To do this, in the Arduno Software environment, in the Tools menu, select the Programmer item : “Arduino as ISP ”.
2. We connect via the SPI interface the slave microcontroller ATmega328P to the Arduino master programmer (Uno, ...), fig. 2. It should be noted that the pre-bits of the ATmega328P microcontroller's Low Fuse Byte register were set to the unprogrammed state. Go to the Arduno Software environment and from the Tools menu, select the Write Loader item . We are flashing the ATmega328P microcontroller.

Fig. 2 - Wiring diagram of the microcontroller to the programmer
3. After successful firmware, the ATmega328P microcontroller is ready for installation on the developed microcontroller platform (Fig. 3), which we program as well as the full Arduino (Uno, ...). A survey program for a pressure and temperature transmitter is shown in Listing 1.

Fig. 3 Pressure and temperature measurement system
Listing 1 - Interrogator of the pressure and temperature transmitter
#include <SFE_BMP180.h>
SFE_BMP180 pressure;
double T,P;
void setup()
{
Serial.begin(9600);
pressure.begin();
}
void loop()
{
P = getPressure();
Serial.println(P+0.5, 2);
Serial.println(T+0.54, 2);
delay(1000);
}
double getPressure(){
char status;
status = pressure.startTemperature();
if (status != 0){
delay(status); // ожидание замера температуры
status = pressure.getTemperature(T);
if (status != 0){
status = pressure.startPressure(3);
if (status != 0){
delay(status); // ожидание замера давления
status = pressure.getPressure(P,T);
if (status != 0){
return(P);
}
}
}
}
}
Python program for filtering by temperature and pressure channels, and getting results
The Python program for determining gas density from pressure and temperature measurements is shown in Listing 2. Information from the measurement system is displayed in real time.
Listing 2 - Determination of gas density from pressure and temperature measurements
import numpy as np
import matplotlib.pyplot as plt
import serial
from drawnow import drawnow
import datetime, time
from pykalman import KalmanFilter
#вводим матрицу перехода и матрицу наблюдений
transition_matrix = [[1, 1, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 1],
[0, 0, 0, 1]]
observation_matrix = [[1, 0, 0, 0],
[0, 0, 1, 0]]
#вводим и инициируем матрицу измерений
initial_state_mean = [101000,
0,
28,
0]
#параметры уравнения состояния идеального газа:#универсальная газовая постоянная R, [Дж/(моль*К)]
R = 8.314459848#молярная масса воздуха M, [г/моль]
M = 29.04#коэффициент k = M/R, [г/(Дж*К)]
k = M / R
#абсолютная температура, [K]
K = 273.16#стандартное (нормальное) давление, [Па]
Pn = 101325#определяем количество измерений# общее количество измерений
str_m = input("введите количество измерений: ")
m = eval(str_m)
# количество элементов выборки
mw = 16#настроить параметры последовательного порта
ser = serial.Serial()
ser.baudrate = 9600
port_num = input("введите номер последовательного порта: ")
ser.port = 'COM' + port_num
ser
#открыть последовательный портtry:
ser.open()
ser.is_open
print("соединились с: " + ser.portstr)
except serial.SerialException:
print("нет соединения с портом: " + ser.portstr)
raise SystemExit(1)
#определяем списки
l1 = [] # для значений 1-го параметра
l2 = [] # для значений 2-го параметра
t1 = [] # для моментов времени
lw1 = [] # для значений выборки 1-го параметра
lw2 = [] # для значений выборки 2-го параметра
n = [] # для значений моментов времени
nw = [] # для значений выборки моментов времени
l1K = [] # для фильтрованных значений 1-го параметра
l2K = [] # для фильтрованных значений 2-го параметра
ro = [] # для плотности газовой среды#подготовить файлы на диске для записи
filename = 'count.txt'
in_file = open(filename,"r")
count = in_file.read()
count_v = eval(count) + 1
in_file.close()
in_file = open(filename,"w")
count = str(count_v)
in_file.write(count)
in_file.close()
filename = count + '_' + filename
out_file = open(filename,"w")
#вывод информации для оператора на консоль
print("\nпараметры:\n")
print("n - момент времени, с;")
print("P - давление, Па;")
print("Pf - отфильтрованное значение P, Па;")
print("T - температура, град. С;")
print("Tf - отфильтрованное значение T, град. С;")
print("ro - плотность воздуха, г/м^3;")
print("\nизмеряемые значения величин параметров\n")
print('{0}{1}{2}{3}{4}{5}\n'.format('n'.rjust(3),'P'.rjust(10),'Pf'.rjust(10),
'T'.rjust(10),'Tf'.rjust(10),'ro'.rjust(10)))
#считываение данных из последовательного порта#накопление списков#формирование текущей выборки
i = 0while i < m:
n.append(i)
nw.append(n[i])
if i >= mw:
nw.pop(0)
ser.flushInput() #flush input buffer, discarding all its contents
line1 = ser.readline().decode('utf-8')[:-1]
line2 = ser.readline().decode('utf-8')[:-1]
t1.append(time.time())
if line1:
l = eval(line1)
#l = np.random.normal(l,100.0)
l1.append(l)
lw1.append(l1[i])
if i >= mw:
lw1.pop(0)
if line2:
l = eval(line2)
#l = np.random.normal(l,1.5)
l2.append(l)
lw2.append(l2[i])
if i >= mw:
lw2.pop(0)
#-------------------------
initial_state_mean = [l1[i],0,l2[i],0]
kf1 = KalmanFilter(transition_matrices = transition_matrix,
observation_matrices = observation_matrix,
initial_state_mean = initial_state_mean)
if i == 0:
measurements = np.array( [ [l1[i], l2[i]],
[initial_state_mean[0], initial_state_mean[2]] ] )
measurements = np.array( [ [l1[i], l2[i]],
[l1[i-1], l2[i-1]] ] )
kf1 = kf1.em(measurements, n_iter=2)
(smoothed_state_means, smoothed_state_covariances) = kf1.smooth(measurements)
l1K.append(smoothed_state_means[0, 0])
l2K.append(smoothed_state_means[0, 2])
#плотность воздуха в рабочих условиях#ro.append( k * l1K[i]/( l2K[i] + K) )#плотность воздуха, приведенная к стандартным условиям
ro.append( (k * l1K[i]/( l2K[i] + K)) * (Pn*(l2K[i]+K)/K/l1K[i]) )
#плотность воздуха, приведенная к нормальным условиям#ro.append( (k * l1K[i]/( l2K[i] + K)) * (Pn*(l2K[i]+K)/(K+20)/l1K[i]) )
print('{0:3d} {1:10.3f} {2:10.3f} {3:10.3f} {4:10.3f} {5:10.3f}'.
format(n[i],l1[i],l1K[i],l2[i],l2K[i],ro[i]))
i += 1
ser.close()
time_tm = t1[m - 1] - t1[0]
print("\nпродолжительность времени измерений: {0:.3f}, c".format(time_tm))
Ts = time_tm / (m - 1)
print("\nпериод опроса датчика: {0:.6f}, c".format(Ts))
#запись таблицы в файл
print("\nтаблица находится в файле {}\n".format(filename))
for i in np.arange(0,len(n),1):
out_file.write('{0:3d} {1:10.3f} {2:10.3f} {3:10.3f} {4:10.3f} {5:10.3f}\n'.
format(n[i],l1[i],l1K[i],l2[i],l2K[i],ro[i]))
#закрыть файл с таблицей
out_file.close()
now = datetime.datetime.now() #получаем дату и время#выводим графики
plt.figure('давление')
plt.plot( n, l1, "b-", n, l1K, "r-")
plt.ylabel(r'$давление, Па$')
plt.xlabel(r'$номер \ измерения$' +
'; (период опроса датчика: {:.6f}, c)'.format(Ts))
plt.title("BMP180\n(" +
now.strftime("%d-%m-%Y %H:%M") + ")")
plt.grid(True)
plt.figure('температура')
plt.plot( n, l2, "b-", n, l2K, "r-")
plt.ylabel(r'$температура, \degree С$')
plt.xlabel(r'$номер \ измерения$' +
'; (период опроса датчика: {:.6f}, c)'.format(Ts))
plt.title("BMP180\n(" +
now.strftime("%d-%m-%Y %H:%M") + ")")
plt.grid(True)
plt.figure('плотность воздуха')
plt.plot( n, ro, "r-")
plt.ylabel(r'$плотность воздуха, г/м^3$')
plt.xlabel(r'$номер \ измерения$' +
'; (период опроса датчика: {:.6f}, c)'.format(Ts))
plt.title("BMP180\n(" +
now.strftime("%d-%m-%Y %H:%M") + ")")
plt.grid(True)
plt.show()
The calculation results are presented in listing and fig. 4, 5, 6.
User interface and calculation results table
введите количество измерений: 33
введите номер последовательного порта: 6
соединились с: COM6
параметры:
n - момент времени, с;
P - давление, Па;
Pf - отфильтрованное значение P, Па;
T - температура, град. С;
Tf - отфильтрованное значение T, град. С;
ro - плотность воздуха, г/м^3;
измеряемые значения величин параметров
n P Pf T Tf ro
0101141.000101141.00028.12028.1201295.5741101140.000101140.09928.19028.1831295.5742101140.000101140.00028.13028.1361295.5743101141.000101140.90128.10028.1031295.5744101140.000101140.09928.10028.1001295.5745101141.000101140.90128.11028.1091295.5746101141.000101141.00028.10028.1011295.5747101139.000101139.21728.10028.1001295.5748101138.000101138.09928.09028.0911295.5749101137.000101137.09928.10028.0991295.57410101151.000101149.02828.10028.1001295.57411101136.000101138.11728.11028.1091295.57412101143.000101142.05228.11028.1101295.57413101139.000101139.50028.10028.1011295.57414101150.000101148.46328.11028.1091295.57415101154.000101153.50028.12028.1191295.57416101151.000101151.35428.11028.1111295.57417101141.000101142.39128.13028.1271295.57418101141.000101141.00028.12028.1211295.57419101142.000101141.90128.11028.1111295.57420101141.000101141.09928.12028.1191295.57421101142.000101141.90128.11028.1111295.57422101146.000101145.50028.12028.1191295.57423101144.000101144.21728.13028.1291295.57424101142.000101142.21728.13028.1301295.57425101142.000101142.00028.14028.1391295.57426101142.000101142.00028.13028.1311295.57427101146.000101145.50028.15028.1471295.57428101142.000101142.50028.19028.1851295.57429101146.000101145.50028.23028.2251295.57430101146.000101146.00028.23028.2301295.57431101146.000101146.00028.22028.2211295.57432101150.000101149.50028.21028.2111295.574
продолжительность времени измерений: 6.464, c
период опроса датчика: 0.201998, c
таблица находится в файле 68_count.txt

Fig. 4 - results of measurement (red) and filtration (blue) of pressure

. 5 - measurement results (red) and filtration (blue) of temperature

. 6 - results of calculation of air density, reduced to standard conditions (temperature 273.15 K; absolute pressure 101.325 kPa)
findings
A method has been developed for determining the density of a gas from the results of pressure and temperature measurements using Arduino sensors and Python software.