我正在使用python从一系列空气质量监视器中读取数据。
目前,我正在关注计算平均值。我认为必须有一种更好的方法来使用类来实现这一点,因为大多数代码都会重复,以使其更加普遍适用和高效。
另一个问题是我有许多不同类型的显示器,它们主要以相同的原理运行,但变量略有不同。下面给出的代码是一个真正的噩梦,转移到一个新的监视器,因为我必须编辑每一行。
麻烦的是,当我搜索课程和平均时,我似乎得到的是在学校课堂上平均学生成绩,而不是使用软件类来计算多个变量的平均值。
基本上显示器只读一秒钟,但我只需要1分钟的平均值,所以我会一直播放,直到分钟翻身。
感激地收到任何建议。
目前我正在这样做:
while minute unchanged:
## read serial port
readData = SER.read()
## Split comma delimited data into dust, flow, temperature, relative humidity, pressure
## for example data comes in as 000.007,2.0,+21.7,046,1010.0
measData = readData[0].split(',')
dustReading = measData[0].strip()
flowReading = measData[1]
flowReading = flowReading.strip()
tempReading = measData[2]
tempReading = tempReading.strip()
rhReading = measData[3]
rhReading = rhReading.strip()
pressReading = measData[4]
pressReading = pressReading.strip()
######### Dust #######
try :
nReading = nReading+1
dustReading = float(dustReading)
sumDustReading = sumDustReading + dustReading
meanDustReading = sumReading/float(nReading)
except :
pass
####### Flow ##########
try :
flowReading = float(flowReading)
sumFlowReading = sumFlowReading+flowReading
meanFlowReading = float(sumFlowReading)/float(nReading)
except :
pass
######## Temperature #########
try:
tempReading = float(tempReading)
sumTempReading = sumTempReading+tempReading
meanTempReading = float(sumTempReading)/float(nReading)
except :
pass
######### RH ########
try :
rhReading = float(rhReading)
sumRhReading = sumRhReading+rhReading
meanRhReading = float(sumRhReading)/float(nReading)
except :
pass
###### Pressure Reading ######
try :
pressReading = float(pressReading)
sumPressReading = sumPressReading+pressReading
meanPressReading = float(sumPressReading)/float(nReading)
except :
pass
理想情况下,我希望能够得到像
这样的东西flow.mean
flow.numberOfReads
flow.sum
万分感谢。
答案 0 :(得分:2)
您现有的代码有点奇怪&所有try:...except
块都很危险。它很危险,因为它忽略了真正应该不被忽略的各种错误。例如:尝试使用未定义变量的值,除以零错误和完全语法错误。
你可以在课堂上做你想做的事,但对于这样的事情,我更有可能使用简单的dict
。我会发布两种方法的代码,以帮助您决定(或增加您的困惑:))。
显然,我没有将监控硬件连接到我的串口,所以为了测试这段代码,我编写了一个简单的生成器函数来创建随机假数据。希望您能够轻松修改我的代码。
首先,使用保存当前总数和读数的类的代码;此类还有一个按需计算平均值的属性。因此,如果您愿意,可以执行print dust.total, flow.mean
之类的操作。
from random import seed, random
#A generator to make simulated data
def fake_data(n):
for i in range(n):
d = 0.005 + 0.005 * random()
f = 1.5 + random()
t = 20.0 + 5.0 * random()
h = int(40 + 10.0 * random())
p = 1005.0 + 10.0 * random()
s = '%07.3f,%3.1f,%-4.1f,%03d,%6.1f' % (d, f, t, h, p)
yield [s]
class Data(object):
def __init__(self, name):
self.name = name
self.total = 0
self.numberOfReads = 0
def __repr__(self):
fmt = "Data(name='%s', total=%f, number=%d, mean=%f)"
return fmt % (self.name, self.total, self.numberOfReads, self.mean)
def __str__(self):
fmt = '%s\nmean: %f\nnumber: %d\ntotal: %f\n'
return fmt % (self.name, self.mean, self.numberOfReads, self.total)
def add(self, value):
self.total += value
self.numberOfReads += 1
@property
def mean(self):
try:
return float(self.total) / float(self.numberOfReads)
except ZeroDivisionError:
return None
#Seed the randomiser
seed(1)
#Initialise the Data instances
dust = Data('Dust')
flow = Data('Flow')
temp = Data('Temperature')
rh = Data('Relative Humidity')
press = Data('Pressure')
for readData in fake_data(10):
## Split comma delimited data into dust, flow, temperature, relative humidity, pressure
## for example data comes in as 000.007,2.0,+21.7,046,1010.0
print readData
measData = readData[0].split(',')
#Convert data strings to floats
dustR, flowR, tempR, rhR, pressR = [float(s) for s in measData]
#Add new data to current totals
dust.add(dustR)
flow.add(flowR)
temp.add(tempR)
rh.add(rhR)
press.add(pressR)
print
for a in (dust, flow, temp, rh, press):
print a
<强>输出强>
['000.006,2.3,23.8,042,1010.0']
['000.007,2.2,23.9,040,1005.3']
['000.009,1.9,23.8,040,1009.5']
['000.009,1.7,24.7,049,1005.3']
['000.005,2.0,24.7,043,1007.2']
['000.007,1.5,21.1,044,1010.0']
['000.006,1.7,21.1,044,1007.9']
['000.005,2.3,22.8,046,1006.9']
['000.010,2.4,20.6,043,1012.2']
['000.009,2.4,22.1,048,1011.7']
Dust
mean: 0.007300
number: 10
total: 0.073000
Flow
mean: 2.040000
number: 10
total: 20.400000
Temperature
mean: 22.860000
number: 10
total: 228.600000
Relative Humidity
mean: 43.900000
number: 10
total: 439.000000
Pressure
mean: 1008.600000
number: 10
total: 10086.000000
这是使用dict
的版本。我已将随机数种子设置为相同的值,以便假数据与之前版本相同。
from random import seed, random
#A generator to make simulated data
def fake_data(n):
for i in range(n):
d = 0.005 + 0.005 * random()
f = 1.5 + random()
t = 20.0 + 5.0 * random()
h = int(40 + 10.0 * random())
p = 1005.0 + 10.0 * random()
s = '%07.3f,%3.1f,%-4.1f,%03d,%6.1f' % (d, f, t, h, p)
yield [s]
#Seed the randomiser
seed(1)
#data field names
fields = ('Dust', 'Flow', 'Temp', 'rh', 'press')
#initialise the data dictionary
data = dict.fromkeys(fields, 0.0)
nReading = 0
for readData in fake_data(10):
nReading += 1
## Split comma delimited data into dust, flow, temperature, relative humidity, pressure
## for example data comes in as 000.007,2.0,+21.7,046,1010.0
print nReading, readData
measData = readData[0].split(',')
#Convert data strings to floats
floatData = [float(s) for s in measData]
#Add new data to current totals
for key, value in zip(fields, floatData):
data[key] += value
print '\nNumber of readings = %d\n' % nReading
nReading = float(nReading)
for key in fields:
total = data[key]
mean = total / nReading
print '%s\nmean: %f\ntotal: %f\n' % (key, mean, total)
<强>输出强>
1 ['000.006,2.3,23.8,042,1010.0']
2 ['000.007,2.2,23.9,040,1005.3']
3 ['000.009,1.9,23.8,040,1009.5']
4 ['000.009,1.7,24.7,049,1005.3']
5 ['000.005,2.0,24.7,043,1007.2']
6 ['000.007,1.5,21.1,044,1010.0']
7 ['000.006,1.7,21.1,044,1007.9']
8 ['000.005,2.3,22.8,046,1006.9']
9 ['000.010,2.4,20.6,043,1012.2']
10 ['000.009,2.4,22.1,048,1011.7']
Number of readings = 10
Dust
mean: 0.007300
total: 0.073000
Flow
mean: 2.040000
total: 20.400000
Temp
mean: 22.860000
total: 228.600000
rh
mean: 43.900000
total: 439.000000
press
mean: 1008.600000
total: 10086.000000
以下是使用try:... except
验证输入数据的简单示例。
data = [
'1.1 2.2 3.3',
'4 5',
'6 garbage bytes',
'7 8 9 10',
'11 12 13',
]
for i, line in enumerate(data):
print '\nLine %d: %r' % (i, line)
row = line.split()
if len(row) != 3:
print 'Bad row length. Should be 3 not', len(row)
continue
try:
a, b, c = [float(s) for s in row]
except ValueError as err:
print 'Conversion error:', err
continue
print 'Data %d: a=%f, b=%f, c=%f' % (i, a, b, c)
<强>输出强>
Line 0: '1.1 2.2 3.3'
Data 0: a=1.100000, b=2.200000, c=3.300000
Line 1: '4 5'
Bad row length. Should be 3 not 2
Line 2: '6 garbage bytes'
Conversion error: invalid literal for float(): garbage
Line 3: '7 8 9 10'
Bad row length. Should be 3 not 4
Line 4: '11 12 13'
Data 4: a=11.000000, b=12.000000, c=13.000000
答案 1 :(得分:1)
如果将数据保存在列表中,则更容易计算平均值和其他统计属性。诸如列表长度和总和之类的东西都是内置的。
首先制作一些清单。
dust, flow, temp, rh, pressure = [], [], [], [], []
我将使用以下数据作为示例。
readData = '000.007,2.0,+21.7,046,1010.0'
让我们把它分开;
newdust, newflow, newtemp, newrh, newpressure = [float(n) for n in readData.split(',')]
dust.append(newdust)
...
pressure.append(newpressure)
计算平均值:
sum(pressure)/len(pressure)
<强>更新强>:
很难给出处理不同类型仪器的建议,而不会看到它们产生的数据。
例如,您可以为每种不同类型的传感器编写数据转换函数,该函数从串行端口读取一行并返回tuple
或namedtuple
数据,并且不支持测量由特定设备None
。
假设您知道您连接的传感器可以选择正确的功能,以便在程序开头调用;
from collections import namedtuple
Instrumentrecord = namedtuple('Instrumentrecord',
['dust', 'flow', 'temp', 'humidity',
'pressure', 'windspeed', 'winddir'])
def foo_sensor(dataline):
dust, flow, temp, rh, pressure = [float(n) for n in dataline.split(',')]
return Instrumentrecord(dust, flow, temp, rh, pressure, None, None)
def main(argv):
....
if sensortype == 'foo':
current_sensor = foo_sensor
...
data = []
while keep_going:
line = SER.read()
data.append(current_sensor(line))