VoltageIO.py
463 lines
| 13.5 KiB
| text/x-python
|
PythonLexer
|
r9 | ''' | |
Created on 23/01/2012 | |||
|
r16 | @author $Author$ | |
@version $Id$ | |||
|
r9 | ''' | |
import os, sys | |||
import numpy | |||
import glob | |||
import fnmatch | |||
|
r20 | import time, datetime | |
|
r9 | ||
|
r18 | path = os.path.split(os.getcwd())[0] | |
sys.path.append(path) | |||
|
r49 | from Model.JROHeader import * | |
|
r11 | from Model.Voltage import Voltage | |
|
r9 | ||
|
r49 | from IO.DataIO import JRODataReader | |
from IO.DataIO import JRODataWriter | |||
|
r37 | ||
|
r49 | class VoltageReader(JRODataReader): | |
|
r20 | """ | |
Esta clase permite leer datos de voltage desde archivos en formato rawdata (.r). La lectura | |||
de los datos siempre se realiza por bloques. Los datos leidos (array de 3 dimensiones: | |||
perfiles*alturas*canales) son almacenados en la variable "buffer". | |||
Esta clase contiene instancias (objetos) de las clases BasicHeader, SystemHeader, | |||
RadarControllerHeader y Voltage. Los tres primeros se usan para almacenar informacion de la | |||
cabecera de datos (metadata), y el cuarto (Voltage) para obtener y almacenar un perfil de | |||
datos desde el "buffer" cada vez que se ejecute el metodo "getData". | |||
Example: | |||
dpath = "/home/myuser/data" | |||
startTime = datetime.datetime(2010,1,20,0,0,0,0,0,0) | |||
endTime = datetime.datetime(2010,1,21,23,59,59,0,0,0) | |||
readerObj = VoltageReader() | |||
readerObj.setup(dpath, startTime, endTime) | |||
while(True): | |||
|
r25 | #to get one profile | |
profile = readerObj.getData() | |||
|
r20 | ||
|
r25 | #print the profile | |
print profile | |||
#If you want to see all datablock | |||
print readerObj.datablock | |||
|
r20 | ||
if readerObj.noMoreFiles: | |||
break | |||
""" | |||
|
r46 | ||
|
r9 | ||
|
r46 | def __init__(self,m_Voltage=None): | |
|
r20 | """ | |
Inicializador de la clase VoltageReader para la lectura de datos de voltage. | |||
Input: | |||
m_Voltage : Objeto de la clase Voltage. Este objeto sera utilizado para | |||
almacenar un perfil de datos cada vez que se haga un requerimiento | |||
(getData). El perfil sera obtenido a partir del buffer de datos, | |||
si el buffer esta vacio se hara un nuevo proceso de lectura de un | |||
bloque de datos. | |||
Si este parametro no es pasado se creara uno internamente. | |||
Variables afectadas: | |||
|
r53 | self.m_DataObj | |
|
r20 | self.m_BasicHeader | |
self.m_SystemHeader | |||
self.m_RadarControllerHeader | |||
self.m_ProcessingHeader | |||
|
r9 | ||
|
r20 | Return: | |
Void | |||
""" | |||
|
r11 | if m_Voltage == None: | |
m_Voltage = Voltage() | |||
|
r20 | ||
if not(isinstance(m_Voltage, Voltage)): | |||
raise ValueError, "in VoltageReader, m_Voltage must be an Voltage class object" | |||
|
r53 | self.m_DataObj = m_Voltage | |
|
r19 | ||
|
r20 | self.m_BasicHeader = BasicHeader() | |
self.m_SystemHeader = SystemHeader() | |||
self.m_RadarControllerHeader = RadarControllerHeader() | |||
self.m_ProcessingHeader = ProcessingHeader() | |||
|
r19 | ||
|
r53 | self.fp = None | |
|
r19 | ||
|
r53 | self.idFile = None | |
|
r20 | ||
|
r53 | self.startDateTime = None | |
|
r19 | ||
|
r53 | self.endDateTime = None | |
|
r19 | ||
|
r53 | self.dataType = None | |
|
r19 | ||
|
r53 | self.fileSizeByHeader = 0 | |
|
r19 | ||
|
r53 | self.pathList = [] | |
|
r19 | ||
self.filenameList = [] | |||
|
r53 | self.lastUTTime = 0 | |
|
r19 | ||
|
r53 | self.maxTimeStep = 30 | |
|
r19 | ||
|
r53 | self.flagIsNewFile = 0 | |
|
r19 | ||
|
r53 | self.ippSeconds = 0 | |
|
r19 | ||
self.flagResetProcessing = 0 | |||
self.flagIsNewBlock = 0 | |||
self.noMoreFiles = 0 | |||
self.nReadBlocks = 0 | |||
self.online = 0 | |||
self.filename = None | |||
self.fileSize = None | |||
self.firstHeaderSize = 0 | |||
self.basicHeaderSize = 24 | |||
|
r20 | self.idProfile = 0 | |
|
r19 | ||
|
r25 | self.datablock = None | |
|
r19 | ||
|
r53 | self.datablockIndex = 9999 | |
|
r12 | ||
|
r53 | self.delay = 7 #seconds | |
|
r9 | ||
|
r53 | self.nTries = 3 #quantity tries | |
|
r9 | ||
|
r53 | self.nFiles = 3 #number of files for searching | |
|
r20 | ||
|
r53 | self.year = 0 | |
|
r15 | ||
|
r53 | self.doy = 0 | |
|
r37 | ||
|
r53 | self.set = 0 | |
|
r37 | ||
|
r53 | self.ext = ".r" | |
|
r37 | ||
|
r53 | self.path = None | |
|
r9 | ||
|
r53 | self.optchar = "D" | |
|
r9 | ||
|
r53 | self.pts2read = 0 | |
|
r9 | ||
|
r53 | self.blocksize = 0 | |
|
r9 | ||
|
r53 | self.utc = 0 | |
|
r20 | ||
|
r46 | self.nBlocks = 0 | |
|
r37 | ||
|
r53 | def hasNotDataInBuffer(self): | |
if self.datablockIndex >= self.m_ProcessingHeader.profilesPerBlock: | |||
|
r9 | return 1 | |
|
r53 | return 0 | |
|
r37 | ||
|
r53 | def getBlockDimension(self): | |
|
r9 | ||
|
r53 | self.pts2read = self.m_ProcessingHeader.profilesPerBlock * self.m_ProcessingHeader.numHeights * self.m_SystemHeader.numChannels | |
self.blocksize = self.pts2read | |||
|
r9 | ||
|
r53 | def readBlock(self): | |
|
r20 | """ | |
|
r53 | readBlock lee el bloque de datos desde la posicion actual del puntero del archivo | |
(self.fp) y actualiza todos los parametros relacionados al bloque de datos | |||
|
r20 | (metadata + data). La data leida es almacenada en el buffer y el contador del buffer | |
es seteado a 0 | |||
Inputs: | |||
None | |||
Return: | |||
None | |||
|
r46 | Affected: | |
|
r53 | self.datablockIndex | |
|
r25 | self.datablock | |
|
r53 | self.flagIsNewFile | |
|
r20 | self.idProfile | |
self.flagIsNewBlock | |||
self.nReadBlocks | |||
|
r46 | Exceptions: | |
Si un bloque leido no es un bloque valido | |||
|
r9 | """ | |
|
r46 | blockOk_flag = False | |
|
r53 | fpointer = self.fp.tell() | |
|
r20 | ||
|
r53 | junk = numpy.fromfile( self.fp, self.dataType, self.pts2read ) | |
|
r37 | ||
if self.online: | |||
|
r53 | if junk.size != self.blocksize: | |
for nTries in range( self.nTries ): | |||
|
r46 | print "\tWaiting for the next block, try %03d ..." % (nTries+1) | |
|
r53 | time.sleep( self.delay ) | |
self.fp.seek( fpointer ) | |||
fpointer = self.fp.tell() | |||
junk = numpy.fromfile( self.fp, self.dataType, self.pts2read ) | |||
if junk.size == self.blocksize: | |||
|
r46 | blockOk_flag = True | |
|
r37 | break | |
|
r46 | ||
if not( blockOk_flag ): | |||
return 0 | |||
|
r37 | ||
|
r46 | try: | |
junk = junk.reshape( (self.m_ProcessingHeader.profilesPerBlock, self.m_ProcessingHeader.numHeights, self.m_SystemHeader.numChannels) ) | |||
except: | |||
print "Data file %s is invalid" % self.filename | |||
return 0 | |||
|
r9 | ||
|
r46 | #data = junk['real'] + junk['imag']*1j | |
self.datablock = junk['real'] + junk['imag']*1j | |||
|
r20 | ||
|
r53 | self.datablockIndex = 0 | |
self.flagIsNewFile = 0 | |||
|
r20 | self.idProfile = 0 | |
|
r13 | self.flagIsNewBlock = 1 | |
|
r46 | ||
|
r13 | self.nReadBlocks += 1 | |
|
r46 | self.nBlocks += 1 | |
return 1 | |||
def getData(self): | |||
|
r20 | """ | |
getData obtiene una unidad de datos del buffer de lectura y la copia a la clase "Voltage" | |||
con todos los parametros asociados a este (metadata). cuando no hay datos en el buffer de | |||
|
r12 | lectura es necesario hacer una nueva lectura de los bloques de datos usando "readNextBlock" | |
|
r20 | ||
Ademas incrementa el contador del buffer en 1. | |||
Return: | |||
data : retorna un perfil de voltages (alturas * canales) copiados desde el | |||
buffer. Si no hay mas archivos a leer retorna None. | |||
Variables afectadas: | |||
|
r53 | self.m_DataObj | |
self.datablockIndex | |||
|
r20 | self.idProfile | |
|
r37 | Affected: | |
|
r53 | self.m_DataObj | |
self.datablockIndex | |||
|
r37 | self.flagResetProcessing | |
self.flagIsNewBlock | |||
self.idProfile | |||
|
r9 | """ | |
|
r46 | if self.noMoreFiles: return 0 | |
|
r9 | self.flagResetProcessing = 0 | |
|
r13 | self.flagIsNewBlock = 0 | |
|
r9 | ||
|
r53 | if self.hasNotDataInBuffer(): | |
|
r37 | ||
|
r46 | if not( self.readNextBlock() ): | |
|
r53 | self.setNextFile() | |
|
r46 | return 0 | |
|
r23 | ||
|
r53 | self.m_DataObj.m_BasicHeader = self.m_BasicHeader.copy() | |
self.m_DataObj.m_ProcessingHeader = self.m_ProcessingHeader.copy() | |||
self.m_DataObj.m_RadarControllerHeader = self.m_RadarControllerHeader.copy() | |||
self.m_DataObj.m_SystemHeader = self.m_SystemHeader.copy() | |||
self.m_DataObj.heights = self.heights | |||
self.m_DataObj.dataType = self.dataType | |||
|
r23 | ||
|
r9 | if self.noMoreFiles == 1: | |
|
r11 | print 'Process finished' | |
|
r46 | return 0 | |
|
r9 | ||
|
r18 | #data es un numpy array de 3 dmensiones (perfiles, alturas y canales) | |
|
r15 | ||
|
r46 | if self.datablock == None: | |
|
r53 | self.m_DataObj.flagNoData = True | |
|
r46 | return 0 | |
|
r53 | time = self.m_BasicHeader.utc + self.datablockIndex * self.ippSeconds | |
self.utc = time | |||
#self.m_DataObj.m_BasicHeader.utc = time | |||
|
r37 | ||
|
r53 | self.m_DataObj.flagNoData = False | |
self.m_DataObj.flagResetProcessing = self.flagResetProcessing | |||
|
r23 | ||
|
r53 | self.m_DataObj.data = self.datablock[self.datablockIndex,:,:] | |
self.m_DataObj.idProfile = self.idProfile | |||
|
r23 | ||
|
r53 | self.datablockIndex += 1 | |
|
r20 | self.idProfile += 1 | |
|
r9 | ||
#call setData - to Data Object | |||
|
r53 | return 1 #self.m_DataObj.data | |
|
r9 | ||
|
r49 | class VoltageWriter( JRODataWriter ): | |
|
r37 | """ | |
Esta clase permite escribir datos de voltajes a archivos procesados (.r). La escritura | |||
de los datos siempre se realiza por bloques. | |||
""" | |||
|
r22 | __configHeaderFile = 'wrSetHeadet.txt' | |
|
r9 | ||
|
r46 | def __init__(self,m_Voltage=None): | |
|
r37 | """ | |
Inicializador de la clase VoltageWriter para la escritura de datos de espectros. | |||
Affected: | |||
|
r53 | self.m_DataObj | |
|
r37 | self.m_BasicHeader | |
self.m_SystemHeader | |||
self.m_RadarControllerHeader | |||
self.m_ProcessingHeader | |||
Return: None | |||
""" | |||
|
r19 | if m_Voltage == None: | |
m_Voltage = Voltage() | |||
|
r9 | ||
|
r53 | self.m_DataObj = m_Voltage | |
|
r22 | ||
|
r53 | self.fp = None | |
|
r22 | ||
|
r53 | self.format = None | |
|
r19 | ||
|
r53 | self.blocksCounter = 0 | |
|
r19 | ||
|
r53 | self.setFile = None | |
|
r19 | ||
|
r53 | self.flagIsNewFile = 1 | |
|
r19 | ||
|
r25 | self.datablock = None | |
|
r19 | ||
|
r53 | self.datablockIndex = 0 | |
self.dataType = None | |||
self.ext = ".r" | |||
|
r19 | ||
|
r53 | self.path = None | |
|
r19 | ||
|
r53 | self.optchar = "D" | |
|
r19 | ||
|
r53 | self.shapeBuffer = None | |
|
r23 | ||
|
r19 | self.nWriteBlocks = 0 | |
self.flagIsNewBlock = 0 | |||
self.noMoreFiles = 0 | |||
self.filename = None | |||
self.m_BasicHeader= BasicHeader() | |||
self.m_SystemHeader = SystemHeader() | |||
self.m_RadarControllerHeader = RadarControllerHeader() | |||
self.m_ProcessingHeader = ProcessingHeader() | |||
|
r37 | ||
|
r53 | def hasAllDataInBuffer(self): | |
if self.datablockIndex >= self.m_ProcessingHeader.profilesPerBlock: | |||
return 1 | |||
return 0 | |||
|
r37 | ||
|
r53 | def setBlockDimension(self): | |
|
r22 | ||
|
r53 | self.shapeBuffer = (self.m_ProcessingHeader.profilesPerBlock, | |
self.m_ProcessingHeader.numHeights, | |||
self.m_SystemHeader.numChannels ) | |||
|
r22 | ||
|
r53 | self.datablock = numpy.zeros(self.shapeBuffer, numpy.dtype('complex')) | |
|
r19 | ||
|
r53 | def writeBlock(self): | |
|
r37 | """ | |
Escribe el buffer en el file designado | |||
Affected: | |||
|
r53 | self.datablockIndex | |
self.flagIsNewFile | |||
|
r37 | self.flagIsNewBlock | |
self.nWriteBlocks | |||
|
r53 | self.blocksCounter | |
|
r37 | ||
Return: None | |||
""" | |||
|
r53 | data = numpy.zeros( self.shapeBuffer, self.dataType ) | |
|
r23 | ||
|
r25 | data['real'] = self.datablock.real | |
data['imag'] = self.datablock.imag | |||
|
r23 | ||
|
r37 | data = data.reshape( (-1) ) | |
|
r23 | ||
|
r53 | data.tofile( self.fp ) | |
|
r23 | ||
|
r25 | self.datablock.fill(0) | |
|
r53 | self.datablockIndex = 0 | |
self.flagIsNewFile = 0 | |||
|
r19 | self.flagIsNewBlock = 1 | |
self.nWriteBlocks += 1 | |||
|
r53 | self.blocksCounter += 1 | |
|
r19 | ||
|
r46 | def putData(self): | |
|
r37 | """ | |
Setea un bloque de datos y luego los escribe en un file | |||
Affected: | |||
self.flagIsNewBlock | |||
|
r53 | self.datablockIndex | |
|
r37 | ||
Return: | |||
0 : Si no hay data o no hay mas files que puedan escribirse | |||
1 : Si se escribio la data de un bloque en un file | |||
""" | |||
|
r19 | self.flagIsNewBlock = 0 | |
|
r53 | if self.m_DataObj.flagNoData: | |
|
r23 | return 0 | |
|
r19 | ||
|
r53 | if self.m_DataObj.flagResetProcessing: | |
|
r23 | ||
|
r25 | self.datablock.fill(0) | |
|
r53 | self.datablockIndex = 0 | |
self.setNextFile() | |||
|
r22 | ||
|
r53 | self.datablock[self.datablockIndex,:,:] = self.m_DataObj.data | |
|
r19 | ||
|
r53 | self.datablockIndex += 1 | |
|
r19 | ||
|
r53 | if self.hasAllDataInBuffer(): | |
self.getHeader() | |||
|
r19 | self.writeNextBlock() | |
if self.noMoreFiles: | |||
|
r23 | #print 'Process finished' | |
return 0 | |||
|
r19 | ||
return 1 | |||
|
r22 |