通过使用Arduino传感器测量压力和温度的结果确定气体密度

引言


测量气体混合物参数的任务在工业和商业中很普遍。 使用技术手段测量气态介质状态参数及其特性时获得可靠信息的问题已通过标准(MVI)中采用的测量程序解决,例如,使用标准压缩设备[1]或使用涡轮测量气体的流量和气体量时,旋转流量计和涡街流量计及计数器[2]。

定期的气体分析使我们能够在实际分析的混合物及其模型之间建立对应关系,据此,在MVI中考虑了气体的理化参数:混合气的组成和标准条件下的气体密度。
此外,MVI还考虑了气体的热物理特性:工作条件下的密度(测量其流量或体积的气体压力和温度),粘度,系数和可压缩系数。

实时测量的气体状态参数包括:压力(差压),温度,密度。 为了分别测量这些参数,使用了以下测量设备:压力计(差压计),温度计,密度计。 气态介质的密度的测量可以通过直接或间接的测量方法来测量。 直接和间接测量方法的结果都取决于测量仪器的误差和方法学误差。 在操作条件下,测量信息信号可能会受到明显噪声的影响,其均方差可能会超出仪器误差。 在这种情况下,紧迫的任务是有效过滤测量信息信号。

本文讨论了使用卡尔曼滤波器在工作和标准条件下间接测量气体密度的方法。

确定气体密度的数学模型


让我们回顾经典并回顾理想气体的状态方程[3]。 我们有:

1.门捷列夫-克拉珀龙方程:

(1)

其中:

-气压;

-摩尔体积;

R是通用气体常数

;

T是绝对温度, T = 273.16K。

2.两个测量参数:

p-气压,Pa
t是气体温度,℃。

众所周知,摩尔体积 取决于气体V的体积和气体的摩尔数 在此卷中:

(2)

也知道

(3)

其中:m是气体的质量,M是气体的摩尔质量。

给定(2)和(3),我们以以下形式重写(1):

(4)。

众所周知,物质的密度

等于:

(5)。

从(4)和(5)我们推导气体密度方程



(6)

并介绍参数的表示法

,这取决于混合气体的摩尔质量:

(7)。

如果混合气体的成分不变,则参数k为常数。
因此,为了计算气体的密度,必须计算气体混合物的摩尔质量。

物质混合物的摩尔质量定义为各个物质的混合物中包括的质量分数的摩尔质量的算术平均值。

我们采用混合气体-空气中的已知物质成分,该成分包括:

  • 重量百分比为23%的氧分子
  • 氮分子重量占76%
  • 重量百分比为1%的氩原子

这些空气物质的摩尔质量将分别等于:

,克/摩尔。

我们计算空气的摩尔质量为算术平均加权:



现在,知道常数的值

,我们可以根据公式(7)计算出空气密度

t



使气体密度达到正常的标准条件


实际上,在不同的物理条件下进行气体特性的测量,并且为了确保不同数据集之间的比较,必须建立标准条件集[4]。

温度和压力的标准条件是由标准建立的物理条件,与这些条件相关的物质的特性与之相关。

各个组织建立了标准条件,例如:国际纯粹与应用化学联合会(IUPAC)在化学领域确定了标准温度和压力(STP)的定义:温度0°C(273.15 K),绝对压力1 bar(Pa); 美国国家标准技术研究所(NIST)将温度设置为20°C(293.15 K),绝对压力设置为1 atm(101.325 kPa),该标准称为常温和压力(NTP); 国际标准化组织(ISO)制定了天然气的标准条件(ISO 13443:1996,2013年确认):温度15.00°C,绝对压力101.325 kPa。

因此,在工业和商业中,必须指出温度和压力的标准条件,并据此进行必要的计算。

我们在温度和压力的工作条件下根据方程式(8)计算空气密度。 根据(6),我们写出标准条件下空气密度的方程:温度 和绝对压力

(9)。

我们对减少到标准条件的空气密度进行计算。 我们将方程式(9)除以方程式(6),并将此关系写为

(10)。

同样,我们得到一个方程,用于计算减少到正常条件下的空气密度:温度 和绝对压力



(11)。

在公式(10)和(11)中,我们使用空气参数的值 TP由工作条件下的公式(8)得出。

执行测量通道压力和温度


为了解决获取信息的许多问题,取决于它们的复杂性,方便的是基于Arduino,Nucleo,Teensy等微控制器平台之一来创建未来系统的原型。

有什么会更容易? 让我们创建一个用于解决特定问题的微控制器平台-创建一个用于测量压力和温度的系统,减少开支,并尽可能减少资金投入,并利用Arduino软件(IDE)环境中软件开发的所有优势。

为此,在硬件级别,我们将需要以下组件:

  1. Arduino(Uno,...)-用作程序员;
  2. 微控制器ATmega328P-PU-未来平台的微控制器;
  3. 一个16 MHz石英谐振器和一对每个12-22 pF的陶瓷电容器(根据制造商的建议);
  4. 时钟按钮用于复位微控制器,并为微控制器的1 kOhm电阻的RESET引脚提供上拉加电源;
  5. BMP180-具有I2C接口的温度和压力变送器;
  6. 接口转换器TTL / USB;
  7. 消耗品-电线,焊料,电路板等

该平台的示意图,其中考虑了必要的接口:标准串行接口I2C,仅此而已,如图1所示。 1。


1-用于实现测量压力和温度的系统的微控制器平台的示意图

现在考虑执行任务的各个阶段。

1.首先,我们需要一个程序员。 我们将Arduino(Uno,...)连接到计算机。 在Arduno Software环境中,从菜单转到File-> Examples-> 11。 ArdunoISP我们找到了在Arduino中缝制的程序员ArduinoArduinoISP。 首先,从“工具”菜单中分别选择板,处理器,装载程序,端口。 将ArduinoISP程序下载到开发板上后,我们的Arduino变成了程序员,并准备用于其预期目的。 为此,在Arduno软件环境中的“ 工具”菜单上,选择“ 程序员”:“ Arduino as ISP ”。

2.通过SPI接口将ATmega328P从属微控制器连接到Arduino主编程器(Uno,...),图。 2.应该注意,以前ATmega328P微控制器的低熔丝字节寄存器的位被设置为未编程状态。 转到Arduno软件环境,然后从“ 工具”菜单中选择“ 刻录机”项。 刷新ATmega328P微控制器。


2-微控制器与编程器的连接图

3.成功固件后,ATmega328P微控制器可以安装在已开发的微控制器平台(图3)以及成熟的Arduino(Uno,...)上,可以进行安装。 清单1显示了压力和温度变送器的轮询程序。


3压力和温度测量系统

清单1-压力和温度传感器的轮询程序
#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程序,用于按温度和压力通道过滤并获取结果


清单2显示了用于通过压力和温度测量确定气体密度的方法的Python程序。来自测量系统的信息将实时显示。

清单2-通过压力和温度测量确定气体密度
 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 = 0 while 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() 


计算结果由清单和图表示。 4 5 6

用户界面和计算结果表
   : 33    : 6  : COM6 : n -  , ; P - , ; Pf -   P, ; T - , . ; Tf -   T, . ; ro -  , /^3;     n P Pf T Tf ro 0 101141.000 101141.000 28.120 28.120 1295.574 1 101140.000 101140.099 28.190 28.183 1295.574 2 101140.000 101140.000 28.130 28.136 1295.574 3 101141.000 101140.901 28.100 28.103 1295.574 4 101140.000 101140.099 28.100 28.100 1295.574 5 101141.000 101140.901 28.110 28.109 1295.574 6 101141.000 101141.000 28.100 28.101 1295.574 7 101139.000 101139.217 28.100 28.100 1295.574 8 101138.000 101138.099 28.090 28.091 1295.574 9 101137.000 101137.099 28.100 28.099 1295.574 10 101151.000 101149.028 28.100 28.100 1295.574 11 101136.000 101138.117 28.110 28.109 1295.574 12 101143.000 101142.052 28.110 28.110 1295.574 13 101139.000 101139.500 28.100 28.101 1295.574 14 101150.000 101148.463 28.110 28.109 1295.574 15 101154.000 101153.500 28.120 28.119 1295.574 16 101151.000 101151.354 28.110 28.111 1295.574 17 101141.000 101142.391 28.130 28.127 1295.574 18 101141.000 101141.000 28.120 28.121 1295.574 19 101142.000 101141.901 28.110 28.111 1295.574 20 101141.000 101141.099 28.120 28.119 1295.574 21 101142.000 101141.901 28.110 28.111 1295.574 22 101146.000 101145.500 28.120 28.119 1295.574 23 101144.000 101144.217 28.130 28.129 1295.574 24 101142.000 101142.217 28.130 28.130 1295.574 25 101142.000 101142.000 28.140 28.139 1295.574 26 101142.000 101142.000 28.130 28.131 1295.574 27 101146.000 101145.500 28.150 28.147 1295.574 28 101142.000 101142.500 28.190 28.185 1295.574 29 101146.000 101145.500 28.230 28.225 1295.574 30 101146.000 101146.000 28.230 28.230 1295.574 31 101146.000 101146.000 28.220 28.221 1295.574 32 101150.000 101149.500 28.210 28.211 1295.574   : 6.464, c   : 0.201998, c     68_count.txt 



4-压力的测量结果(红色)和过滤(蓝色)


5-温度的测量结果(红色)和过滤(蓝色)


6-降低到标准条件下的空气密度的计算结果(温度273.15 K;绝对压力101.325 kPa)

结论


已经开发出一种使用Arduino传感器和Python软件通过压力和温度测量确定气体密度的技术。

信息来源链接


  1. GOST 8.586.5-2005。 网址
  2. GOST R 8.740-2011。URL
  3. 理想气体定律。 网址
  4. 温度和压力的标准条件。 网址

Source: https://habr.com/ru/post/zh-CN412915/


All Articles