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:

    (1),

    where:

    - gas pressure;

    - molar volume;

    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 depends on the volume of gas V and the number of moles of gas in this volume:

    (2)

    It is also known that

    (3),

    where: m is the mass of gas, M is the molar mass of gas.

    Considering (2) and (3), we rewrite (1) in the form:

    (4).

    As is known, the density of a substance

    is equal to:

    (5).

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

    :

    (6)

    and introduce the parameter designation

    , which depends on the molar mass of the gas mixture:

    (7).

    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:,

    g / mol.

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



    Now, knowing the value of the constant

    , we can calculate the air density using the formula (7) taking into account the measured values

    and t :



    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 and absolute pressure :

    (9).

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

    (10).

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

    :

    (11).

    In equations (10) and (11), we use the values ​​of the air parameters , T and P from equation (8), obtained under operating conditions.

    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:

    1. Arduino (Uno, ...) - use as a programmer;
    2. ATmega328P-PU microcontroller - a microcontroller of the future platform;
    3. a 16 MHz crystal oscillator and a pair of ceramic capacitors of 12-22 pF each (as recommended by the manufacturer);
    4. clock button to reset the microcontroller and pull-up plus power to the RESET pin of the microcontroller 1 kΩ resistor;
    5. BMP180 - temperature and pressure measuring transducer with I2C interface;
    6. TTL / USB interface converter;
    7. 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.

    References to sources of information


    1. GOST 8.586.5-2005. URL
    2. GOST R 8.740 - 2011. URL
    3. Ideal gas law. URL
    4. Standard conditions for temperature and pressure. URL

    Also popular now: