|
|
'''
|
|
|
|
|
|
$Author: murco $
|
|
|
$Id: JROHeaderIO.py 151 2012-10-31 19:00:51Z murco $
|
|
|
'''
|
|
|
import sys
|
|
|
import numpy
|
|
|
import copy
|
|
|
import datetime
|
|
|
|
|
|
|
|
|
SPEED_OF_LIGHT = 299792458
|
|
|
SPEED_OF_LIGHT = 3e8
|
|
|
|
|
|
FILE_STRUCTURE = numpy.dtype([ #HEADER 48bytes
|
|
|
('FileMgcNumber','<u4'), #0x23020100
|
|
|
('nFDTdataRecors','<u4'), #No Of FDT data records in this file (0 or more)
|
|
|
('RadarUnitId','<u4'),
|
|
|
('SiteName','<s32'), #Null terminated
|
|
|
])
|
|
|
|
|
|
RECORD_STRUCTURE = numpy.dtype([ #RECORD HEADER 180+20N bytes
|
|
|
('RecMgcNumber','<u4'), #0x23030001
|
|
|
('RecCounter','<u4'), #Record counter(0,1, ...)
|
|
|
('Off2StartNxtRec','<u4'), #Offset to start of next record form start of this record
|
|
|
('Off2StartData','<u4'), #Offset to start of data from start of this record
|
|
|
('EpTimeStamp','<i4'), #Epoch time stamp of start of acquisition (seconds)
|
|
|
('msCompTimeStamp','<u4'), #Millisecond component of time stamp (0,...,999)
|
|
|
('ExpTagName','<s32'), #Experiment tag name (null terminated)
|
|
|
('ExpComment','<s32'), #Experiment comment (null terminated)
|
|
|
('SiteLatDegrees','<f4'), #Site latitude (from GPS) in degrees (positive implies North)
|
|
|
('SiteLongDegrees','<f4'), #Site longitude (from GPS) in degrees (positive implies East)
|
|
|
('RTCgpsStatus','<u4'), #RTC GPS engine status (0=SEEK, 1=LOCK, 2=NOT FITTED, 3=UNAVAILABLE)
|
|
|
('TransmitFrec','<u4'), #Transmit frequency (Hz)
|
|
|
('ReceiveFrec','<u4'), #Receive frequency
|
|
|
('FirstOsciFrec','<u4'), #First local oscillator frequency (Hz)
|
|
|
('Polarisation','<u4'), #(0="O", 1="E", 2="linear 1", 3="linear2")
|
|
|
('ReceiverFiltSett','<u4'), #Receiver filter settings (0,1,2,3)
|
|
|
('nModesInUse','<u4'), #Number of modes in use (1 or 2)
|
|
|
('DualModeIndex','<u4'), #Dual Mode index number for these data (0 or 1)
|
|
|
('DualModeRange','<u4'), #Dual Mode range correction for these data (m)
|
|
|
('nDigChannels','<u4'), #Number of digital channels acquired (2*N)
|
|
|
('SampResolution','<u4'), #Sampling resolution (meters)
|
|
|
('nRangeGatesSamp','<u4'), #Number of range gates sampled
|
|
|
('StartRangeSamp','<u4'), #Start range of sampling (meters)
|
|
|
('PRFhz','<u4'), #PRF (Hz)
|
|
|
('Integrations','<u4'), #Integrations
|
|
|
('nDataPointsTrsf','<u4'), #Number of data points transformed
|
|
|
('nReceiveBeams','<u4'), #Number of receive beams stored in file (1 or N)
|
|
|
('nSpectAverages','<u4'), #Number of spectral averages
|
|
|
('FFTwindowingInd','<u4'), #FFT windowing index (0 = no window)
|
|
|
('BeamAngleAzim','<f4'), #Beam steer angle (azimuth) in degrees (clockwise from true North)
|
|
|
('BeamAngleZen','<f4'), #Beam steer angle (zenith) in degrees (0=> vertical)
|
|
|
('AntennaCoord','<f24'), #Antenna coordinates (Range(meters), Bearing(degrees)) - N pairs
|
|
|
('RecPhaseCalibr','<f12'), #Receiver phase calibration (degrees) - N values
|
|
|
('RecAmpCalibr','<f12'), #Receiver amplitude calibration (ratio relative to receiver one) - N values
|
|
|
('ReceiverGaindB','<u12'), #Receiver gains in dB - N values
|
|
|
])
|
|
|
|
|
|
|
|
|
class Header(object):
|
|
|
|
|
|
def __init__(self):
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
def read(self):
|
|
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
def write(self):
|
|
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
def printInfo(self):
|
|
|
|
|
|
message = "#"*50 + "\n"
|
|
|
message += self.__class__.__name__.upper() + "\n"
|
|
|
message += "#"*50 + "\n"
|
|
|
|
|
|
keyList = list(self.__dict__.keys())
|
|
|
keyList.sort()
|
|
|
|
|
|
for key in keyList:
|
|
|
message += "%s = %s" %(key, self.__dict__[key]) + "\n"
|
|
|
|
|
|
if "size" not in keyList:
|
|
|
attr = getattr(self, "size")
|
|
|
|
|
|
if attr:
|
|
|
message += "%s = %s" %("size", attr) + "\n"
|
|
|
|
|
|
print(message)
|
|
|
|
|
|
class FileHeader(Header):
|
|
|
|
|
|
FileMgcNumber= None
|
|
|
nFDTdataRecors=None #No Of FDT data records in this file (0 or more)
|
|
|
RadarUnitId= None
|
|
|
SiteName= None
|
|
|
|
|
|
#__LOCALTIME = None
|
|
|
|
|
|
def __init__(self, useLocalTime=True):
|
|
|
|
|
|
self.FileMgcNumber= 0 #0x23020100
|
|
|
self.nFDTdataRecors=0 #No Of FDT data records in this file (0 or more)
|
|
|
self.RadarUnitId= 0
|
|
|
self.SiteName= ""
|
|
|
self.size = 48
|
|
|
|
|
|
#self.useLocalTime = useLocalTime
|
|
|
|
|
|
def read(self, fp):
|
|
|
|
|
|
try:
|
|
|
header = numpy.fromfile(fp, FILE_STRUCTURE,1)
|
|
|
''' numpy.fromfile(file, dtype, count, sep='')
|
|
|
file : file or str
|
|
|
Open file object or filename.
|
|
|
|
|
|
dtype : data-type
|
|
|
Data type of the returned array. For binary files, it is used to determine
|
|
|
the size and byte-order of the items in the file.
|
|
|
|
|
|
count : int
|
|
|
Number of items to read. -1 means all items (i.e., the complete file).
|
|
|
|
|
|
sep : str
|
|
|
Separator between items if file is a text file. Empty (“”) separator means
|
|
|
the file should be treated as binary. Spaces (” ”) in the separator match zero
|
|
|
or more whitespace characters. A separator consisting only of spaces must match
|
|
|
at least one whitespace.
|
|
|
|
|
|
'''
|
|
|
|
|
|
except Exception as e:
|
|
|
print("FileHeader: ")
|
|
|
print(eBasicHeader)
|
|
|
return 0
|
|
|
|
|
|
self.FileMgcNumber= byte(header['FileMgcNumber'][0])
|
|
|
self.nFDTdataRecors=int(header['nFDTdataRecors'][0]) #No Of FDT data records in this file (0 or more)
|
|
|
self.RadarUnitId= int(header['RadarUnitId'][0])
|
|
|
self.SiteName= char(header['SiteName'][0])
|
|
|
|
|
|
|
|
|
if self.size <48:
|
|
|
return 0
|
|
|
|
|
|
return 1
|
|
|
|
|
|
def write(self, fp):
|
|
|
|
|
|
headerTuple = (self.FileMgcNumber,
|
|
|
self.nFDTdataRecors,
|
|
|
self.RadarUnitId,
|
|
|
self.SiteName,
|
|
|
self.size)
|
|
|
|
|
|
|
|
|
header = numpy.array(headerTuple, FILE_STRUCTURE)
|
|
|
# numpy.array(object, dtype=None, copy=True, order=None, subok=False, ndmin=0)
|
|
|
header.tofile(fp)
|
|
|
''' ndarray.tofile(fid, sep, format) Write array to a file as text or binary (default).
|
|
|
|
|
|
fid : file or str
|
|
|
An open file object, or a string containing a filename.
|
|
|
|
|
|
sep : str
|
|
|
Separator between array items for text output. If “” (empty), a binary file is written,
|
|
|
equivalent to file.write(a.tobytes()).
|
|
|
|
|
|
format : str
|
|
|
Format string for text file output. Each entry in the array is formatted to text by
|
|
|
first converting it to the closest Python type, and then using “format” % item.
|
|
|
|
|
|
'''
|
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
class RecordHeader(Header):
|
|
|
|
|
|
RecMgcNumber=None #0x23030001
|
|
|
RecCounter= None
|
|
|
Off2StartNxtRec= None
|
|
|
EpTimeStamp= None
|
|
|
msCompTimeStamp= None
|
|
|
ExpTagName= None
|
|
|
ExpComment=None
|
|
|
SiteLatDegrees=None
|
|
|
SiteLongDegrees= None
|
|
|
RTCgpsStatus= None
|
|
|
TransmitFrec= None
|
|
|
ReceiveFrec= None
|
|
|
FirstOsciFrec= None
|
|
|
Polarisation= None
|
|
|
ReceiverFiltSett= None
|
|
|
nModesInUse= None
|
|
|
DualModeIndex= None
|
|
|
DualModeRange= None
|
|
|
nDigChannels= None
|
|
|
SampResolution= None
|
|
|
nRangeGatesSamp= None
|
|
|
StartRangeSamp= None
|
|
|
PRFhz= None
|
|
|
Integrations= None
|
|
|
nDataPointsTrsf= None
|
|
|
nReceiveBeams= None
|
|
|
nSpectAverages= None
|
|
|
FFTwindowingInd= None
|
|
|
BeamAngleAzim= None
|
|
|
BeamAngleZen= None
|
|
|
AntennaCoord= None
|
|
|
RecPhaseCalibr= None
|
|
|
RecAmpCalibr= None
|
|
|
ReceiverGaindB= None
|
|
|
|
|
|
'''size = None
|
|
|
nSamples = None
|
|
|
nProfiles = None
|
|
|
nChannels = None
|
|
|
adcResolution = None
|
|
|
pciDioBusWidth = None'''
|
|
|
|
|
|
def __init__(self, RecMgcNumber=None, RecCounter= 0, Off2StartNxtRec= 0,
|
|
|
EpTimeStamp= 0, msCompTimeStamp= 0, ExpTagName= None,
|
|
|
ExpComment=None, SiteLatDegrees=0, SiteLongDegrees= 0,
|
|
|
RTCgpsStatus= 0, TransmitFrec= 0, ReceiveFrec= 0,
|
|
|
FirstOsciFrec= 0, Polarisation= 0, ReceiverFiltSett= 0,
|
|
|
nModesInUse= 0, DualModeIndex= 0, DualModeRange= 0,
|
|
|
nDigChannels= 0, SampResolution= 0, nRangeGatesSamp= 0,
|
|
|
StartRangeSamp= 0, PRFhz= 0, Integrations= 0,
|
|
|
nDataPointsTrsf= 0, nReceiveBeams= 0, nSpectAverages= 0,
|
|
|
FFTwindowingInd= 0, BeamAngleAzim= 0, BeamAngleZen= 0,
|
|
|
AntennaCoord= 0, RecPhaseCalibr= 0, RecAmpCalibr= 0,
|
|
|
ReceiverGaindB= 0):
|
|
|
|
|
|
self.RecMgcNumber = RecMgcNumber #0x23030001
|
|
|
self.RecCounter = RecCounter
|
|
|
self.Off2StartNxtRec = Off2StartNxtRec
|
|
|
self.EpTimeStamp = EpTimeStamp
|
|
|
self.msCompTimeStamp = msCompTimeStamp
|
|
|
self.ExpTagName = ExpTagName
|
|
|
self.ExpComment = ExpComment
|
|
|
self.SiteLatDegrees = SiteLatDegrees
|
|
|
self.SiteLongDegrees = SiteLongDegrees
|
|
|
self.RTCgpsStatus = RTCgpsStatus
|
|
|
self.TransmitFrec = TransmitFrec
|
|
|
self.ReceiveFrec = ReceiveFrec
|
|
|
self.FirstOsciFrec = FirstOsciFrec
|
|
|
self.Polarisation = Polarisation
|
|
|
self.ReceiverFiltSett = ReceiverFiltSett
|
|
|
self.nModesInUse = nModesInUse
|
|
|
self.DualModeIndex = DualModeIndex
|
|
|
self.DualModeRange = DualModeRange
|
|
|
self.nDigChannels = nDigChannels
|
|
|
self.SampResolution = SampResolution
|
|
|
self.nRangeGatesSamp = nRangeGatesSamp
|
|
|
self.StartRangeSamp = StartRangeSamp
|
|
|
self.PRFhz = PRFhz
|
|
|
self.Integrations = Integrations
|
|
|
self.nDataPointsTrsf = nDataPointsTrsf
|
|
|
self.nReceiveBeams = nReceiveBeams
|
|
|
self.nSpectAverages = nSpectAverages
|
|
|
self.FFTwindowingInd = FFTwindowingInd
|
|
|
self.BeamAngleAzim = BeamAngleAzim
|
|
|
self.BeamAngleZen = BeamAngleZen
|
|
|
self.AntennaCoord = AntennaCoord
|
|
|
self.RecPhaseCalibr = RecPhaseCalibr
|
|
|
self.RecAmpCalibr = RecAmpCalibr
|
|
|
self.ReceiverGaindB = ReceiverGaindB
|
|
|
|
|
|
|
|
|
def read(self, fp):
|
|
|
|
|
|
startFp = fp.tell() #The method tell() returns the current position of the file read/write pointer within the file.
|
|
|
|
|
|
try:
|
|
|
header = numpy.fromfile(fp,RECORD_STRUCTURE,1)
|
|
|
except Exception as e:
|
|
|
print("System Header: " + e)
|
|
|
return 0
|
|
|
|
|
|
self.RecMgcNumber = header['RecMgcNumber'][0] #0x23030001
|
|
|
self.RecCounter = header['RecCounter'][0]
|
|
|
self.Off2StartNxtRec = header['Off2StartNxtRec'][0]
|
|
|
self.EpTimeStamp = header['EpTimeStamp'][0]
|
|
|
self.msCompTimeStamp = header['msCompTimeStamp'][0]
|
|
|
self.ExpTagName = header['ExpTagName'][0]
|
|
|
self.ExpComment = header['ExpComment'][0]
|
|
|
self.SiteLatDegrees = header['SiteLatDegrees'][0]
|
|
|
self.SiteLongDegrees = header['SiteLongDegrees'][0]
|
|
|
self.RTCgpsStatus = header['RTCgpsStatus'][0]
|
|
|
self.TransmitFrec = header['TransmitFrec'][0]
|
|
|
self.ReceiveFrec = header['ReceiveFrec'][0]
|
|
|
self.FirstOsciFrec = header['FirstOsciFrec'][0]
|
|
|
self.Polarisation = header['Polarisation'][0]
|
|
|
self.ReceiverFiltSett = header['ReceiverFiltSett'][0]
|
|
|
self.nModesInUse = header['nModesInUse'][0]
|
|
|
self.DualModeIndex = header['DualModeIndex'][0]
|
|
|
self.DualModeRange = header['DualModeRange'][0]
|
|
|
self.nDigChannels = header['nDigChannels'][0]
|
|
|
self.SampResolution = header['SampResolution'][0]
|
|
|
self.nRangeGatesSamp = header['nRangeGatesSamp'][0]
|
|
|
self.StartRangeSamp = header['StartRangeSamp'][0]
|
|
|
self.PRFhz = header['PRFhz'][0]
|
|
|
self.Integrations = header['Integrations'][0]
|
|
|
self.nDataPointsTrsf = header['nDataPointsTrsf'][0]
|
|
|
self.nReceiveBeams = header['nReceiveBeams'][0]
|
|
|
self.nSpectAverages = header['nSpectAverages'][0]
|
|
|
self.FFTwindowingInd = header['FFTwindowingInd'][0]
|
|
|
self.BeamAngleAzim = header['BeamAngleAzim'][0]
|
|
|
self.BeamAngleZen = header['BeamAngleZen'][0]
|
|
|
self.AntennaCoord = header['AntennaCoord'][0]
|
|
|
self.RecPhaseCalibr = header['RecPhaseCalibr'][0]
|
|
|
self.RecAmpCalibr = header['RecAmpCalibr'][0]
|
|
|
self.ReceiverGaindB = header['ReceiverGaindB'][0]
|
|
|
|
|
|
Self.size = 180+20*3
|
|
|
|
|
|
endFp = self.size + startFp
|
|
|
|
|
|
if fp.tell() > endFp:
|
|
|
sys.stderr.write("Warning %s: Size value read from System Header is lower than it has to be\n" %fp.name)
|
|
|
return 0
|
|
|
|
|
|
if fp.tell() < endFp:
|
|
|
sys.stderr.write("Warning %s: Size value read from System Header size is greater than it has to be\n" %fp.name)
|
|
|
return 0
|
|
|
|
|
|
return 1
|
|
|
|
|
|
def write(self, fp):
|
|
|
|
|
|
headerTuple = (self.RecMgcNumber,
|
|
|
self.RecCounter,
|
|
|
self.Off2StartNxtRec,
|
|
|
self.EpTimeStamp,
|
|
|
self.msCompTimeStamp,
|
|
|
self.ExpTagName,
|
|
|
self.ExpComment,
|
|
|
self.SiteLatDegrees,
|
|
|
self.SiteLongDegrees,
|
|
|
self.RTCgpsStatus,
|
|
|
self.TransmitFrec,
|
|
|
self.ReceiveFrec,
|
|
|
self.FirstOsciFrec,
|
|
|
self.Polarisation,
|
|
|
self.ReceiverFiltSett,
|
|
|
self.nModesInUse,
|
|
|
self.DualModeIndex,
|
|
|
self.DualModeRange,
|
|
|
self.nDigChannels,
|
|
|
self.SampResolution,
|
|
|
self.nRangeGatesSamp,
|
|
|
self.StartRangeSamp,
|
|
|
self.PRFhz,
|
|
|
self.Integrations,
|
|
|
self.nDataPointsTrsf,
|
|
|
self.nReceiveBeams,
|
|
|
self.nSpectAverages,
|
|
|
self.FFTwindowingInd,
|
|
|
self.BeamAngleAzim,
|
|
|
self.BeamAngleZen,
|
|
|
self.AntennaCoord,
|
|
|
self.RecPhaseCalibr,
|
|
|
self.RecAmpCalibr,
|
|
|
self.ReceiverGaindB)
|
|
|
|
|
|
# self.size,self.nSamples,
|
|
|
# self.nProfiles,
|
|
|
# self.nChannels,
|
|
|
# self.adcResolution,
|
|
|
# self.pciDioBusWidth
|
|
|
|
|
|
header = numpy.array(headerTuple,RECORD_STRUCTURE)
|
|
|
header.tofile(fp)
|
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
def get_dtype_index(numpy_dtype):
|
|
|
|
|
|
index = None
|
|
|
|
|
|
for i in range(len(NUMPY_DTYPE_LIST)):
|
|
|
if numpy_dtype == NUMPY_DTYPE_LIST[i]:
|
|
|
index = i
|
|
|
break
|
|
|
|
|
|
return index
|
|
|
|
|
|
def get_numpy_dtype(index):
|
|
|
|
|
|
#dtype4 = numpy.dtype([('real','<f4'),('imag','<f4')])
|
|
|
|
|
|
return NUMPY_DTYPE_LIST[index]
|
|
|
|
|
|
|
|
|
def get_dtype_width(index):
|
|
|
|
|
|
return DTYPE_WIDTH[index]
|