VoltageIO.py
432 lines
| 12.0 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 | ||
|
r89 | from IO.JRODataIO import JRODataReader | |
from IO.JRODataIO import JRODataWriter | |||
|
r37 | ||
|
r59 | ||
|
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". | |||
|
r66 | perfiles * alturas * canales | |
|
r59 | ||
|
r20 | 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() | |||
|
r89 | ||
|
r25 | #print the profile | |
print profile | |||
#If you want to see all datablock | |||
print readerObj.datablock | |||
|
r20 | ||
|
r59 | if readerObj.flagNoMoreFiles: | |
|
r20 | break | |
""" | |||
|
r107 | dataOutObj = None | |
|
r59 | ||
datablock = None | |||
|
r46 | ||
|
r66 | ext = ".r" | |
optchar = "D" | |||
|
r9 | ||
|
r107 | def __init__(self, dataOutObj=None): | |
|
r20 | """ | |
Inicializador de la clase VoltageReader para la lectura de datos de voltage. | |||
Input: | |||
|
r107 | dataOutObj : Objeto de la clase Voltage. Este objeto sera utilizado para | |
|
r20 | 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: | |||
|
r107 | self.dataOutObj | |
|
r9 | ||
|
r20 | Return: | |
|
r59 | None | |
|
r20 | """ | |
|
r80 | ||
self.datablock = None | |||
self.utc = 0 | |||
self.ext = ".r" | |||
self.optchar = "D" | |||
self.m_BasicHeader = BasicHeader() | |||
|
r164 | self.systemHeaderObj = SystemHeader() | |
|
r80 | ||
|
r164 | self.radarControllerHeaderObj = RadarControllerHeader() | |
|
r80 | ||
self.m_ProcessingHeader = ProcessingHeader() | |||
self.online = 0 | |||
self.fp = None | |||
self.idFile = None | |||
self.startDateTime = None | |||
self.endDateTime = None | |||
self.dataType = None | |||
self.fileSizeByHeader = None | |||
self.filenameList = [] | |||
self.filename = None | |||
self.fileSize = None | |||
self.firstHeaderSize = 0 | |||
self.basicHeaderSize = 24 | |||
self.pathList = [] | |||
self.filenameList = [] | |||
self.lastUTTime = 0 | |||
self.maxTimeStep = 30 | |||
self.flagNoMoreFiles = 0 | |||
self.set = 0 | |||
self.path = None | |||
|
r89 | self.profileIndex = 9999 | |
|
r80 | ||
|
r164 | self.delay = 60 #seconds | |
|
r80 | ||
self.nTries = 3 #quantity tries | |||
self.nFiles = 3 #number of files for searching | |||
|
r89 | self.nReadBlocks = 0 | |
|
r80 | ||
self.flagIsNewFile = 1 | |||
self.ippSeconds = 0 | |||
self.flagResetProcessing = 0 | |||
self.flagIsNewBlock = 0 | |||
|
r89 | self.nTotalBlocks = 0 | |
|
r80 | ||
self.blocksize = 0 | |||
|
r37 | ||
|
r107 | def createObjByDefault(self): | |
dataObj = Voltage() | |||
return dataObj | |||
|
r59 | def __hasNotDataInBuffer(self): | |
|
r89 | if self.profileIndex >= self.m_ProcessingHeader.profilesPerBlock: | |
|
r9 | return 1 | |
|
r53 | return 0 | |
|
r37 | ||
|
r59 | ||
|
r53 | def getBlockDimension(self): | |
|
r59 | """ | |
Obtiene la cantidad de puntos a leer por cada bloque de datos | |||
|
r9 | ||
|
r59 | Affected: | |
self.blocksize | |||
Return: | |||
None | |||
""" | |||
|
r164 | pts2read = self.m_ProcessingHeader.profilesPerBlock * self.m_ProcessingHeader.numHeights * self.systemHeaderObj.numChannels | |
|
r89 | self.blocksize = pts2read | |
|
r59 | ||
|
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: | |
|
r89 | self.profileIndex | |
|
r25 | self.datablock | |
|
r53 | self.flagIsNewFile | |
|
r20 | self.flagIsNewBlock | |
|
r89 | self.nTotalBlocks | |
|
r20 | ||
|
r46 | Exceptions: | |
Si un bloque leido no es un bloque valido | |||
|
r9 | """ | |
|
r89 | ||
junk = numpy.fromfile( self.fp, self.dataType, self.blocksize ) | |||
|
r37 | ||
|
r46 | try: | |
|
r164 | junk = junk.reshape( (self.m_ProcessingHeader.profilesPerBlock, self.m_ProcessingHeader.numHeights, self.systemHeaderObj.numChannels) ) | |
|
r46 | except: | |
|
r89 | print "The read block (%3d) has not enough data" %self.nReadBlocks | |
|
r46 | return 0 | |
|
r9 | ||
|
r73 | junk = numpy.transpose(junk, (2,0,1)) | |
|
r46 | self.datablock = junk['real'] + junk['imag']*1j | |
|
r20 | ||
|
r89 | self.profileIndex = 0 | |
|
r53 | self.flagIsNewFile = 0 | |
|
r13 | self.flagIsNewBlock = 1 | |
|
r46 | ||
|
r89 | self.nTotalBlocks += 1 | |
|
r13 | self.nReadBlocks += 1 | |
|
r46 | ||
return 1 | |||
|
r59 | ||
|
r46 | ||
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: | |||
|
r107 | self.dataOutObj | |
|
r89 | self.profileIndex | |
|
r20 | ||
|
r37 | Affected: | |
|
r107 | self.dataOutObj | |
|
r89 | self.profileIndex | |
|
r37 | self.flagResetProcessing | |
self.flagIsNewBlock | |||
|
r9 | """ | |
|
r59 | if self.flagNoMoreFiles: return 0 | |
|
r46 | ||
|
r9 | self.flagResetProcessing = 0 | |
|
r13 | self.flagIsNewBlock = 0 | |
|
r9 | ||
|
r59 | if self.__hasNotDataInBuffer(): | |
|
r37 | ||
|
r46 | if not( self.readNextBlock() ): | |
return 0 | |||
|
r23 | ||
|
r89 | self.updateDataHeader() | |
|
r23 | ||
|
r59 | if self.flagNoMoreFiles == 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: | |
|
r107 | self.dataOutObj.flagNoData = True | |
|
r46 | return 0 | |
|
r89 | time = self.m_BasicHeader.utc + self.profileIndex * self.ippSeconds | |
|
r107 | self.dataOutObj.m_BasicHeader.utc = time | |
|
r37 | ||
|
r107 | self.dataOutObj.flagNoData = False | |
self.dataOutObj.flagResetProcessing = self.flagResetProcessing | |||
|
r23 | ||
|
r107 | self.dataOutObj.data = self.datablock[:,self.profileIndex,:] | |
|
r23 | ||
|
r89 | self.profileIndex += 1 | |
|
r9 | ||
#call setData - to Data Object | |||
|
r107 | return 1 #self.dataOutObj.data | |
|
r9 | ||
|
r59 | ||
|
r98 | 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 | ||
|
r107 | dataOutObj = None | |
|
r59 | ||
ext = ".r" | |||
optchar = "D" | |||
|
r66 | datablock = None | |
|
r89 | profileIndex = 0 | |
|
r66 | ||
|
r59 | shapeBuffer = None | |
|
r107 | def __init__(self, dataOutObj=None): | |
|
r37 | """ | |
Inicializador de la clase VoltageWriter para la escritura de datos de espectros. | |||
Affected: | |||
|
r107 | self.dataOutObj | |
|
r37 | ||
Return: None | |||
""" | |||
|
r107 | if dataOutObj == None: | |
dataOutObj = Voltage() | |||
|
r9 | ||
|
r107 | if not( isinstance(dataOutObj, Voltage) ): | |
raise ValueError, "in VoltageReader, dataOutObj must be an Spectra class object" | |||
|
r59 | ||
|
r107 | self.dataOutObj = dataOutObj | |
|
r59 | ||
|
r37 | ||
|
r53 | def hasAllDataInBuffer(self): | |
|
r89 | if self.profileIndex >= self.m_ProcessingHeader.profilesPerBlock: | |
|
r53 | return 1 | |
return 0 | |||
|
r37 | ||
|
r59 | ||
|
r53 | def setBlockDimension(self): | |
|
r59 | """ | |
Obtiene las formas dimensionales del los subbloques de datos que componen un bloque | |||
Affected: | |||
self.shape_spc_Buffer | |||
self.shape_cspc_Buffer | |||
self.shape_dc_Buffer | |||
Return: None | |||
""" | |||
self.shapeBuffer = (self.m_ProcessingHeader.profilesPerBlock, | |||
self.m_ProcessingHeader.numHeights, | |||
|
r164 | self.systemHeaderObj.numChannels ) | |
|
r22 | ||
|
r164 | self.datablock = numpy.zeros((self.systemHeaderObj.numChannels, | |
|
r73 | self.m_ProcessingHeader.profilesPerBlock, | |
|
r80 | self.m_ProcessingHeader.numHeights), | |
dtype=numpy.dtype('complex')) | |||
|
r59 | ||
|
r19 | ||
|
r53 | def writeBlock(self): | |
|
r37 | """ | |
Escribe el buffer en el file designado | |||
Affected: | |||
|
r89 | self.profileIndex | |
|
r53 | self.flagIsNewFile | |
|
r37 | self.flagIsNewBlock | |
|
r89 | self.nTotalBlocks | |
self.nWriteBlocks | |||
|
r37 | ||
Return: None | |||
""" | |||
|
r53 | data = numpy.zeros( self.shapeBuffer, self.dataType ) | |
|
r23 | ||
|
r73 | junk = numpy.transpose(self.datablock, (1,2,0)) | |
data['real'] = junk.real | |||
data['imag'] = junk.imag | |||
|
r23 | ||
|
r37 | data = data.reshape( (-1) ) | |
|
r23 | ||
|
r53 | data.tofile( self.fp ) | |
|
r23 | ||
|
r25 | self.datablock.fill(0) | |
|
r89 | self.profileIndex = 0 | |
|
r53 | self.flagIsNewFile = 0 | |
|
r19 | self.flagIsNewBlock = 1 | |
|
r89 | self.nTotalBlocks += 1 | |
|
r19 | self.nWriteBlocks += 1 | |
|
r59 | ||
|
r46 | def putData(self): | |
|
r37 | """ | |
Setea un bloque de datos y luego los escribe en un file | |||
Affected: | |||
self.flagIsNewBlock | |||
|
r89 | self.profileIndex | |
|
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 | |
|
r107 | if self.dataOutObj.flagNoData: | |
|
r23 | return 0 | |
|
r19 | ||
|
r107 | if self.dataOutObj.flagResetProcessing: | |
|
r23 | ||
|
r25 | self.datablock.fill(0) | |
|
r89 | self.profileIndex = 0 | |
|
r53 | self.setNextFile() | |
|
r22 | ||
|
r107 | self.datablock[:,self.profileIndex,:] = self.dataOutObj.data | |
|
r19 | ||
|
r89 | self.profileIndex += 1 | |
|
r19 | ||
|
r53 | if self.hasAllDataInBuffer(): | |
|
r59 | #if self.flagIsNewFile: | |
|
r89 | self.getDataHeader() | |
|
r19 | self.writeNextBlock() | |
|
r59 | if self.flagNoMoreFiles: | |
|
r23 | #print 'Process finished' | |
return 0 | |||
|
r19 | ||
return 1 | |||
|
r22 |