-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit
- Loading branch information
Showing
6 changed files
with
743 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
[connection] | ||
port = /dev/ttyACM0 | ||
baudrate = 9600 | ||
timeout = 0.1 | ||
|
||
[data] | ||
interval = 300 | ||
|
||
[device] | ||
model = TC1 | ||
latitude = 32.865468 | ||
longitude = -117.253436 | ||
altitude = 11 | ||
network = IRI | ||
station = SOCA | ||
channel = BHZ | ||
location = 00 | ||
samplerate = 18.78 | ||
dataquality = D | ||
|
||
[file] | ||
datapath = /srv/tc1/data/ | ||
|
||
[logging] | ||
logpath = /srv/tc1/log/ | ||
|
||
[calibration] | ||
samplelimit = 405648 | ||
offset = 34432 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
|
||
import serial, sys, time, os.path, datetime | ||
from time import strftime | ||
import numpy as np | ||
import ConfigParser as cp | ||
|
||
def printStats(alldata, alladj, counts, etime): | ||
numsam = len(alldata) | ||
(numpos, numneg, numzer) = counts | ||
pospct = (numpos/(numsam-numzer))*100 | ||
negpct = (numneg/(numsam-numzer))*100 | ||
zerpct = (numzer/numsam)*100 | ||
print("\n-----------------------------------------------------------------------------") | ||
print "Running time seconds: %d" % etime | ||
print "# of samples: %d" % numsam | ||
print " Max/Adjusted max: %d / %d" % (np.amax(alldata),np.amax(alladj)) | ||
print " Min/Adjusted min: %d / %d" % (np.amin(alldata),np.amin(alladj)) | ||
print " Avg/Adjusted avg: %d / %d" % (np.mean(alldata),np.mean(alladj)) | ||
print " # of positive: %d (%.2f%%)" % (numpos,pospct) | ||
print " # of negative: %d (%.2f%%)" % (numneg,negpct) | ||
print " # of zeroes: %d (%.2f%%)" % (numzer,zerpct) | ||
print "System check completed." | ||
|
||
def msg(txt): | ||
sys.stdout.write(txt) | ||
sys.stdout.flush() | ||
|
||
def main(): | ||
# Check if the data logger is running. If so, stop. | ||
# We can't risk locking out the serial port from the data logger. | ||
|
||
if os.path.exists('/srv/tc1/run/seis_data_logger.pid'): | ||
print "Error: Data Logger is already running! Exiting..." | ||
exit(0) | ||
|
||
alldata = [] | ||
alladj = [] | ||
numpos = 0 | ||
numneg = 0 | ||
numzer = 0 | ||
|
||
config = cp.RawConfigParser() | ||
config.read("/srv/tc1/conf/datalogger.props.cfg") | ||
|
||
port = config.get ("connection", "port") | ||
baud = config.getint ("connection", "baudrate") | ||
tout = config.getfloat("connection", "timeout") | ||
offset = config.getint ("calibration","offset") | ||
limit = config.getint ("calibration","samplelimit") | ||
model = config.get ("device", "model") | ||
srate = config.getfloat("device", "samplerate") | ||
|
||
ttlsec = limit / srate | ||
m, s = divmod(ttlsec, 60) | ||
h, m = divmod(m, 60) | ||
now = datetime.datetime.now() | ||
ftime = now + datetime.timedelta(hours=h, minutes=m, seconds=s) | ||
(fhr,fmn,fsc) = (ftime.time().hour,ftime.time().minute,ftime.time().second) | ||
|
||
print("SIO Seismic Calibration Tool, v1.0") | ||
print("* Initialized on " + strftime('%x at %X %Z')) | ||
print("* Device info: model %s on %s (%d Hz transmission rate)" % (model, port, baud)) | ||
print("* Using offset: %d" % offset) | ||
print("* Sample limit: %d (approx. %d:%02d:%02d, finish at %d:%02d:%02d)" % (limit,h,m,s,fhr,fmn,fsc)) | ||
print("-----------------------------------------------------------------------------") | ||
print(" Sample Count | Sample Rate | Original Value | Adjusted Value | Current Mean ") | ||
|
||
device = serial.Serial(port,baud,timeout=tout) | ||
stime = time.time() | ||
try: | ||
sampcount = 0 | ||
runcount = 0 | ||
curtotl = 0 | ||
while len(alldata) < limit: | ||
sproctime = time.time() | ||
data = device.readline()[:-2] | ||
sampcount = sampcount + 1 | ||
if data: | ||
eproctime = time.time() | ||
|
||
try: | ||
rawdata = int(data) | ||
runcount = runcount + 1 | ||
alldata.append(rawdata) | ||
adjdata = rawdata - offset | ||
alladj.append(adjdata) | ||
curtotl = curtotl + rawdata | ||
curmean = int(curtotl / runcount) | ||
if adjdata > 0: | ||
numpos = numpos + 1 | ||
elif adjdata < 0: | ||
numneg = numneg + 1 | ||
else: | ||
numzer = numzer + 1 | ||
|
||
samprate = sampcount / (eproctime - sproctime) | ||
|
||
m = "{3:^13d} | {2:^11.2f} | {1:^14d} | {0:^14d} | {4:^14d}".format(adjdata,rawdata,samprate,runcount,curmean) | ||
msg(m + chr(13)) | ||
except ValueError: | ||
continue | ||
sampcount = 0 | ||
except KeyboardInterrupt: | ||
etime = time.time() | ||
elapsed = etime - stime | ||
counts = (float(numpos),float(numneg),float(numzer)) | ||
printStats(alldata, alladj, counts, elapsed) | ||
exit() | ||
etime = time.time() | ||
elapsed = etime - stime | ||
counts = (float(numpos),float(numneg),float(numzer)) | ||
printStats(alldata, alladj, counts, elapsed) | ||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
|
||
# seisDataLogger.py | ||
# | ||
# Connects to educational seismometer and gathers data. | ||
# Make save to current trace every user-defined interval of seconds | ||
# Reads a config file for parameters, but runs as a process. | ||
# | ||
|
||
from obspy.core import Stream, Trace, UTCDateTime | ||
from seisDataLoggerDaemon import Daemon | ||
from threading import Thread | ||
from time import strftime | ||
import serial, sys, os | ||
import numpy as np | ||
|
||
|
||
class DataLoggerDaemon(Daemon): | ||
def run(self): | ||
baseTime = UTCDateTime() | ||
|
||
# Assign all the configuration variables | ||
port = self.config.get ("connection","port") | ||
baud = self.config.getint ("connection","baudrate") | ||
tout = self.config.getfloat("connection","timeout") | ||
interval = self.config.getint ("data","interval") | ||
offset = self.config.getint ("calibration","offset") | ||
network = self.config.get ("device","network") | ||
station = self.config.get ("device","station") | ||
location = self.config.get ("device","location") | ||
channel = self.config.get ("device","channel") | ||
samprate = self.config.getfloat("device","samplerate") | ||
dataqual = self.config.get ("device","dataquality") | ||
|
||
sampleIdx = 0 | ||
traceData = np.array([]) | ||
|
||
self.logger.debug("["+ strftime('%X') + "] connecting...") | ||
|
||
rawData = serial.Serial(port,baud,timeout=tout) | ||
|
||
self.logger.debug("["+ strftime('%X') + "] listening for incoming data...") | ||
|
||
while True: # While loop that loops forever | ||
while (rawData.inWaiting()==0): #Wait here until there is data | ||
pass #do nothing | ||
|
||
dataPointString = rawData.readline() | ||
|
||
try: | ||
traceData = np.append(traceData, int(dataPointString)) | ||
except ValueError: | ||
offset = int(np.mean(traceData)) | ||
self.logger.debug("["+ strftime('%X') + "] * Bad value received. Replacing with current mean...") | ||
traceData = np.append(traceData, offset) | ||
|
||
sampleIdx = sampleIdx + 1 | ||
|
||
currentTime = UTCDateTime() | ||
elapsedTime = (currentTime - baseTime) | ||
|
||
# Write the data after x seconds | ||
if elapsedTime >= (interval + (baseTime.microsecond / 1e6)): | ||
# Fill header attributes | ||
stats = {'network': network, | ||
'station': station, | ||
'location': location, | ||
'channel': channel, | ||
'npts': len(traceData), | ||
'sampling_rate': samprate, | ||
'mseed': {'dataquality': dataqual}, | ||
'starttime': baseTime} | ||
|
||
# Save the file using a different thread. | ||
worker = Thread(target=self._writeData, args=(traceData, stats, baseTime)) | ||
worker.setDaemon(True) | ||
worker.start() | ||
|
||
baseTime = currentTime | ||
|
||
sampleIdx = 0 | ||
|
||
traceData = np.array([]) | ||
|
||
def _writeData(self, traceData, stats, timeObj): | ||
streamObj = Stream([Trace(data=traceData, header=stats)]) | ||
|
||
filename = self._prepareFilename(timeObj) | ||
offset = int(np.mean(streamObj.traces[0].data)) | ||
streamObj.traces[0].data = np.array([x - offset for x in streamObj.traces[0].data]) | ||
|
||
self.logger.debug("["+ strftime('%X') + "] Saving %d samples (corrected by %d) to %s..." % (len(traceData), offset, filename)) | ||
streamObj.write(filename, format='MSEED') | ||
|
||
def _prepareFilename(self, timeObj): | ||
datapath = self.config.get("file","datapath") | ||
filepath = datapath +"%d/%d/" % (timeObj.year, timeObj.julday) | ||
|
||
try: | ||
if not os.path.exists(filepath): | ||
os.makedirs(filepath) | ||
except OSError as exception: | ||
self.logger.debug("["+ strftime('%X') + "] * Error preparing path: (%d) %s" % (exception.errno, exception.strerror)) | ||
|
||
network = self.config.get("device","network") | ||
station = self.config.get("device","station") | ||
channel = self.config.get("device","channel") | ||
filename = network+"."+station+".%02d%02d%4d_%02d%02d%02d." % \ | ||
(timeObj.day,timeObj.month,timeObj.year, | ||
timeObj.hour,timeObj.minute,timeObj.second) +channel+".mseed" | ||
return (filepath+filename) | ||
|
||
def normalize(v): | ||
norm=np.linalg.norm(v) | ||
if norm==0: | ||
return v | ||
return v/norm | ||
|
||
if __name__ == "__main__": | ||
daemon = DataLoggerDaemon('/srv/tc1/run/seis_data_logger.pid') | ||
if len(sys.argv) == 2: | ||
if 'start' == sys.argv[1]: | ||
daemon.start() | ||
elif 'stop' == sys.argv[1]: | ||
daemon.stop() | ||
elif 'restart' == sys.argv[1]: | ||
daemon.restart() | ||
else: | ||
print "Unknown command" | ||
sys.exit(2) | ||
sys.exit(0) | ||
else: | ||
print "usage: %s start|stop|restart" % sys.argv[0] | ||
sys.exit(2) |
Oops, something went wrong.