Esempio n. 1
0
class EnviSAT_SLC(Sensor):

    parameter_list = (ORBIT_DIRECTORY, ORBITFILE, INSTRUMENTFILE,
                      INSTRUMENT_DIRECTORY, IMAGEFILE) + Sensor.parameter_list
    """
        A Class for parsing EnviSAT instrument and imagery files
    """

    family = 'envisat'

    def __init__(self, family='', name=''):
        super(EnviSAT_SLC,
              self).__init__(family if family else self.__class__.family,
                             name=name)
        self._imageFile = None
        self._instrumentFileData = None
        self._imageryFileData = None
        self.dopplerRangeTime = None
        self.rangeRefTime = None
        self.logger = logging.getLogger("isce.sensor.EnviSAT_SLC")
        self.frame = None
        self.frameList = []

        self.constants = {'antennaLength': 10.0, 'iBias': 128, 'qBias': 128}

    def getFrame(self):
        return self.frame

    def parse(self):
        """
            Parse both imagery and instrument files and create
            objects representing the platform, instrument and scene
        """

        self.frame = Frame()
        self.frame.configure()

        self._imageFile = ImageryFile(fileName=self._imageFileName)
        self._imageryFileData = self._imageFile.parse()

        if self.instrumentFile in [None, '']:
            self.findInstrumentFile()

        instrumentFileParser = InstrumentFile(fileName=self.instrumentFile)
        self._instrumentFileData = instrumentFileParser.parse()

        self.populateMetadata()

    def populateMetadata(self):

        self._populatePlatform()
        self._populateInstrument()
        self._populateFrame()
        self._populateOrbit()
        self.dopplerRangeTime = self._imageryFileData['doppler']
        self.rangeRefTime = self._imageryFileData['dopplerOrigin'][0] * 1.0e-9


#        print('Doppler confidence: ', 100.0 * self._imageryFileData['dopplerConfidence'][0])

    def _populatePlatform(self):
        """Populate the platform object with metadata"""
        platform = self.frame.getInstrument().getPlatform()

        # Populate the Platform and Scene objects
        platform.setMission("Envisat")
        platform.setPointingDirection(-1)
        platform.setAntennaLength(self.constants['antennaLength'])
        platform.setPlanet(Planet(pname="Earth"))

    def _populateInstrument(self):
        """Populate the instrument object with metadata"""
        instrument = self.frame.getInstrument()

        rangeSampleSpacing = Const.c / (
            2 * self._imageryFileData['rangeSamplingRate'])
        pri = self._imageryFileData['pri']

        ####These shouldnt matter for SLC data since data is already focused.
        txPulseLength = 512 / 19207680.000000
        chirpPulseBandwidth = 16.0e6
        chirpSlope = chirpPulseBandwidth / txPulseLength

        instrument.setRangePixelSize(rangeSampleSpacing)
        instrument.setPulseLength(txPulseLength)
        #instrument.setSwath(imageryFileData['SWATH'])
        instrument.setRadarFrequency(self._instrumentFileData['frequency'])
        instrument.setChirpSlope(chirpSlope)
        instrument.setRangeSamplingRate(
            self._imageryFileData['rangeSamplingRate'])
        instrument.setPulseRepetitionFrequency(1.0 / pri)
        #instrument.setRangeBias(rangeBias)
        instrument.setInPhaseValue(self.constants['iBias'])
        instrument.setQuadratureValue(self.constants['qBias'])

    def _populateFrame(self):
        """Populate the scene object with metadata"""
        numberOfLines = self._imageryFileData['numLines']
        numberOfSamples = self._imageryFileData['numSamples']
        pri = self._imageryFileData['pri']
        startingRange = Const.c * float(
            self._imageryFileData['timeToFirstSample']) * 1.0e-9 / 2.0
        rangeSampleSpacing = Const.c / (
            2 * self._imageryFileData['rangeSamplingRate'])
        farRange = startingRange + numberOfSamples * rangeSampleSpacing
        first_line_utc = datetime.datetime.strptime(
            self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f')
        center_line_utc = datetime.datetime.strptime(
            self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f')
        last_line_utc = datetime.datetime.strptime(
            self._imageryFileData['LAST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f')
        centerTime = DTUtil.timeDeltaToSeconds(last_line_utc -
                                               first_line_utc) / 2.0
        center_line_utc = center_line_utc + datetime.timedelta(
            microseconds=int(centerTime * 1e6))

        self.frame.setStartingRange(startingRange)
        self.frame.setFarRange(farRange)
        self.frame.setProcessingFacility(self._imageryFileData['PROC_CENTER'])
        self.frame.setProcessingSystem(self._imageryFileData['SOFTWARE_VER'])
        self.frame.setTrackNumber(int(self._imageryFileData['REL_ORBIT']))
        self.frame.setOrbitNumber(int(self._imageryFileData['ABS_ORBIT']))
        self.frame.setPolarization(self._imageryFileData['MDS1_TX_RX_POLAR'])
        self.frame.setNumberOfSamples(numberOfSamples)
        self.frame.setNumberOfLines(numberOfLines)
        self.frame.setSensingStart(first_line_utc)
        self.frame.setSensingMid(center_line_utc)
        self.frame.setSensingStop(last_line_utc)

    def _populateOrbit(self):
        if self.orbitFile in [None, '']:
            self.findOrbitFile()

        dorParser = DOR(fileName=self.orbitFile)
        dorParser.parse()
        startTime = self.frame.getSensingStart() - datetime.timedelta(
            minutes=5)
        stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5)
        self.frame.setOrbit(dorParser.orbit.trimOrbit(startTime, stopTime))

    def _populateImage(self, outname, width, length):

        #farRange = self.frame.getStartingRange() + width*self.frame.getInstrument().getRangeSamplingRate()
        # Update the NumberOfSamples and NumberOfLines in the Frame object
        self.frame.setNumberOfSamples(width)
        self.frame.setNumberOfLines(length)
        #self.frame.setFarRange(farRange)
        # Create a RawImage object
        rawImage = createSlcImage()
        rawImage.setFilename(outname)
        rawImage.setAccessMode('read')
        rawImage.setByteOrder('l')
        rawImage.setXmin(0)
        rawImage.setXmax(width)
        rawImage.setWidth(width)
        self.frame.setImage(rawImage)

    def extractImage(self):
        from datetime import datetime as dt
        import tempfile as tf

        self.parse()
        width = self._imageryFileData['numSamples']
        length = self._imageryFileData['numLines']
        self._imageFile.extractImage(self.output, width, length)
        self._populateImage(self.output, width, length)

        pass

    def findOrbitFile(self):

        datefmt = '%Y%m%d%H%M%S'
        #        sensingStart = self.frame.getSensingStart()
        sensingStart = datetime.datetime.strptime(
            self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f')
        outFile = None

        if self.orbitDir in [None, '']:
            raise Exception(
                'No Envisat Orbit File or Orbit Directory specified')

        try:
            for fname in os.listdir(self.orbitDir):
                if not os.path.isfile(os.path.join(self.orbitDir, fname)):
                    continue

                if not fname.startswith('DOR'):
                    continue

                fields = fname.split('_')
                procdate = datetime.datetime.strptime(
                    fields[-6][-8:] + fields[-5], datefmt)
                startdate = datetime.datetime.strptime(fields[-4] + fields[-3],
                                                       datefmt)
                enddate = datetime.datetime.strptime(fields[-2] + fields[-1],
                                                     datefmt)

                if (sensingStart > startdate) and (sensingStart < enddate):
                    outFile = os.path.join(self.orbitDir, fname)
                    break

        except:
            raise Exception(
                'Error occured when trying to find orbit file in %s' %
                (self.orbitDir))

        if not outFile:
            raise Exception('Envisat orbit file could not be found in %s' %
                            (self.orbitDir))

        self.orbitFile = outFile
        return

    def findInstrumentFile(self):

        datefmt = '%Y%m%d%H%M%S'

        sensingStart = datetime.datetime.strptime(
            self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f')
        print('sens: ', sensingStart)
        outFile = None

        if self.instrumentDir in [None, '']:
            raise Exception(
                'No Envisat Instrument File or Instrument Directory specified')

        try:
            for fname in os.listdir(self.instrumentDir):
                if not os.path.isfile(os.path.join(self.instrumentDir, fname)):
                    continue

                if not fname.startswith('ASA_INS'):
                    continue

                fields = fname.split('_')
                procdate = datetime.datetime.strptime(
                    fields[-6][-8:] + fields[-5], datefmt)
                startdate = datetime.datetime.strptime(fields[-4] + fields[-3],
                                                       datefmt)
                enddate = datetime.datetime.strptime(fields[-2] + fields[-1],
                                                     datefmt)

                if (sensingStart > startdate) and (sensingStart < enddate):
                    outFile = os.path.join(self.instrumentDir, fname)
                    break

        except:
            raise Exception(
                'Error occured when trying to find instrument file in %s' %
                (self.instrumentDir))

        if not outFile:
            raise Exception(
                'Envisat instrument file could not be found in %s' %
                (self.instrumentDir))

        self.instrumentFile = outFile
        return

    def extractDoppler(self):
        """
        Return the doppler centroid as defined in the ASAR file.
        """
        quadratic = {}

        r0 = self.frame.getStartingRange()
        dr = self.frame.instrument.getRangePixelSize()
        width = self.frame.getNumberOfSamples()

        midr = r0 + (width / 2.0) * dr
        midtime = 2 * midr / Const.c - self.rangeRefTime

        fd_mid = 0.0
        tpow = midtime
        for kk in self.dopplerRangeTime:
            fd_mid += kk * tpow
            tpow *= midtime

        ####For insarApp
        quadratic['a'] = fd_mid / self.frame.getInstrument(
        ).getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.

        ####For roiApp
        ####More accurate
        from isceobj.Util import Poly1D

        coeffs = self.dopplerRangeTime
        dr = self.frame.getInstrument().getRangePixelSize()
        rref = 0.5 * Const.c * self.rangeRefTime
        r0 = self.frame.getStartingRange()
        norm = 0.5 * Const.c / dr

        dcoeffs = []
        for ind, val in enumerate(coeffs):
            dcoeffs.append(val / (norm**ind))

        poly = Poly1D.Poly1D()
        poly.initPoly(order=len(coeffs) - 1)
        poly.setMean((rref - r0) / dr - 1.0)
        poly.setCoeffs(dcoeffs)

        pix = np.linspace(0,
                          self.frame.getNumberOfSamples(),
                          num=len(coeffs) + 1)
        evals = poly(pix)
        fit = np.polyfit(pix, evals, len(coeffs) - 1)
        self.frame._dopplerVsPixel = list(fit[::-1])
        print('Doppler Fit: ', fit[::-1])

        return quadratic
Esempio n. 2
0
class Sentinel1A(Component):
    """
        A Class representing RadarSAT 2 data
    """
    def __init__(self):
        Component.__init__(self)
        self.xml = None
        self.tiff = None
        self.output = None
        self.gdal_translate = None
        self.frame = Frame()
        self.frame.configure()

        self._xml_root = None
        self.descriptionOfVariables = {}
        self.dictionaryOfVariables = {
            'XML': ['self.xml', 'str', 'mandatory'],
            'TIFF': ['self.tiff', 'str', 'mandatory'],
            'OUTPUT': ['self.output', 'str', 'optional'],
            'GDAL_TRANSLATE': ['self.gdal_translate', 'str', 'optional']
        }

    def getFrame(self):
        return self.frame

    def parse(self):
        try:
            fp = open(self.xml, 'r')
        except IOError as strerr:
            print("IOError: %s" % strerr)
            return
        self._xml_root = ElementTree(file=fp).getroot()
        #        self.product.set_from_etnode(self._xml_root)
        self.populateMetadata()

        fp.close()

    def grab_from_xml(self, path):
        try:
            res = self._xml_root.find(path).text
        except:
            raise Exception('Tag= %s not found' % (path))

        if res is None:
            raise Exception('Tag = %s not found' % (path))

        return res

    def convertToDateTime(self, string):
        dt = datetime.datetime.strptime(string, "%Y-%m-%dT%H:%M:%S.%f")
        return dt

    def populateMetadata(self):
        """
            Create metadata objects from the metadata files
        """
        ####Set each parameter one - by - one
        mission = self.grab_from_xml('adsHeader/missionId')
        swath = self.grab_from_xml('adsHeader/swath')
        polarization = self.grab_from_xml('adsHeader/polarisation')

        frequency = float(
            self.grab_from_xml(
                'generalAnnotation/productInformation/radarFrequency'))
        passDirection = self.grab_from_xml(
            'generalAnnotation/productInformation/pass')

        rangePixelSize = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/rangePixelSpacing'))
        azimuthPixelSize = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/azimuthPixelSpacing'))
        rangeSamplingRate = Const.c / (2.0 * rangePixelSize)
        prf = 1.0 / float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/azimuthTimeInterval'))

        lines = int(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/numberOfLines'))
        samples = int(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/numberOfSamples'))

        startingRange = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/slantRangeTime')
        ) * Const.c / 2.0
        incidenceAngle = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/incidenceAngleMidSwath'))
        dataStartTime = self.convertToDateTime(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/productFirstLineUtcTime'))
        dataStopTime = self.convertToDateTime(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/productLastLineUtcTime'))

        pulseLength = float(
            self.grab_from_xml(
                'generalAnnotation/downlinkInformationList/downlinkInformation/downlinkValues/txPulseLength'
            ))
        chirpSlope = float(
            self.grab_from_xml(
                'generalAnnotation/downlinkInformationList/downlinkInformation/downlinkValues/txPulseRampRate'
            ))
        pulseBandwidth = pulseLength * chirpSlope

        ####Sentinel is always right looking
        lookSide = -1
        facility = 'EU'
        version = '1.0'

        #        height = self.product.imageGenerationParameters.sarProcessingInformation._satelliteHeight

        ####Populate platform
        platform = self.frame.getInstrument().getPlatform()
        platform.setPlanet(Planet("Earth"))
        platform.setMission(mission)
        platform.setPointingDirection(lookSide)
        platform.setAntennaLength(2 * azimuthPixelSize)

        ####Populate instrument
        instrument = self.frame.getInstrument()
        instrument.setRadarFrequency(frequency)
        instrument.setPulseRepetitionFrequency(prf)
        instrument.setPulseLength(pulseLength)
        instrument.setChirpSlope(pulseBandwidth / pulseLength)
        instrument.setIncidenceAngle(incidenceAngle)
        #self.frame.getInstrument().setRangeBias(0)
        instrument.setRangePixelSize(rangePixelSize)
        instrument.setRangeSamplingRate(rangeSamplingRate)
        instrument.setBeamNumber(swath)
        instrument.setPulseLength(pulseLength)

        #Populate Frame
        #self.frame.setSatelliteHeight(height)
        self.frame.setSensingStart(dataStartTime)
        self.frame.setSensingStop(dataStopTime)
        diffTime = DTUtil.timeDeltaToSeconds(dataStopTime -
                                             dataStartTime) / 2.0
        sensingMid = dataStartTime + datetime.timedelta(
            microseconds=int(diffTime * 1e6))
        self.frame.setSensingMid(sensingMid)
        self.frame.setPassDirection(passDirection)
        self.frame.setPolarization(polarization)
        self.frame.setStartingRange(startingRange)
        self.frame.setFarRange(startingRange + (samples - 1) * rangePixelSize)
        self.frame.setNumberOfLines(lines)
        self.frame.setNumberOfSamples(samples)
        self.frame.setProcessingFacility(facility)
        self.frame.setProcessingSoftwareVersion(version)

        self.frame.setPassDirection(passDirection)
        self.extractOrbit()

    def extractOrbit(self):
        '''
        Extract orbit information from xml node.
        '''
        node = self._xml_root.find('generalAnnotation/orbitList')
        frameOrbit = self.frame.getOrbit()
        frameOrbit.setOrbitSource('Header')

        for child in node.getchildren():
            timestamp = self.convertToDateTime(child.find('time').text)
            pos = []
            vel = []
            posnode = child.find('position')
            velnode = child.find('velocity')
            for tag in ['x', 'y', 'z']:
                pos.append(float(posnode.find(tag).text))

            for tag in ['x', 'y', 'z']:
                vel.append(float(velnode.find(tag).text))

            vec = StateVector()
            vec.setTime(timestamp)
            vec.setPosition(pos)
            vec.setVelocity(vel)
            frameOrbit.addStateVector(vec)

    def extractImage(self):
        """
           Use gdal_translate to extract the slc
        """
        import tempfile
        import subprocess

        if (not self.gdal_translate):
            raise TypeError(
                "The path to executable gdal_translate was not specified")
        if (not os.path.exists(self.gdal_translate)):
            raise OSError("Could not find gdal_translate in directory %s" %
                          os.path.dirname(self.gdal_translate))

        self.parse()
        # Use GDAL to convert the geoTIFF file to an raster image
        # There should be a way to do this using the GDAL python api
        curdir = os.getcwd()
        tempdir = tempfile.mkdtemp(dir=curdir)
        #        os.rmdir(tempdir) # Wasteful, but if the directory exists, gdal_translate freaks out
        #instring = 'RADARSAT_2_CALIB:UNCALIB:%s' % self.xml
        #process = subprocess.Popen([self.gdal_translate,'-of','MFF2','-ot','CFloat32',instring,tempdir])
        if (self.tiff is None) or (not os.path.exists(self.tiff)):
            raise Exception(
                'Path to input tiff file: %s is wrong or file doesnt exist.' %
                (self.tiff))

        process = subprocess.Popen([
            self.gdal_translate,
            self.tiff.strip(), '-of', 'ENVI', '-ot', 'CFloat32', '-co',
            'INTERLEAVE=BIP',
            os.path.join(tempdir, 'image_data')
        ])
        process.wait()

        # Move the output of the gdal_translate call to a reasonable file name

        width = self.frame.getNumberOfSamples()
        lgth = self.frame.getNumberOfLines()

        os.rename(os.path.join(tempdir, 'image_data'), self.output)

        #       os.unlink(os.path.join(tempdir,'attrib'))
        os.unlink(os.path.join(tempdir, 'image_data.hdr'))
        os.rmdir(tempdir)

        ####
        slcImage = isceobj.createSlcImage()
        slcImage.setByteOrder('l')
        slcImage.setFilename(self.output)
        slcImage.setAccessMode('read')
        slcImage.setWidth(self.frame.getNumberOfSamples())
        slcImage.setLength(self.frame.getNumberOfLines())
        slcImage.setXmin(0)
        slcImage.setXmax(self.frame.getNumberOfSamples())
        self.frame.setImage(slcImage)

    def extractDoppler(self):
        '''
        self.parse()
        Extract doppler information as needed by mocomp
        '''
        #        ins = self.frame.getInstrument()
        #        dc = self.product.imageGenerationParameters.dopplerCentroid
        quadratic = {}

        #        r0 = self.frame.startingRange
        #        fs = ins.getRangeSamplingRate()
        #        tNear = 2*r0/Const.c

        #        tMid = tNear + 0.5*self.frame.getNumberOfSamples()/fs
        #        t0 = dc.dopplerCentroidReferenceTime
        #        poly = dc.dopplerCentroidCoefficients

        #        fd_mid = 0.0
        #        for kk in range(len(poly)):
        #            fd_mid += poly[kk] * (tMid - t0)**kk

        #        quadratic['a'] = fd_mid / ins.getPulseRepetitionFrequency()
        quadratic['a'] = 0.
        quadratic['b'] = 0.
        quadratic['c'] = 0.
        return quadratic
Esempio n. 3
0
class ALOS2(Sensor):
    """
        Code to read CEOSFormat leader files for ALOS2 SLC data.
    """

    family = 'alos2'

    parameter_list = (WAVELENGTH, LEADERFILE,
                      IMAGEFILE) + Sensor.parameter_list

    fsampConst = {
        104: 1.047915957140240E+08,
        52: 5.239579785701190E+07,
        34: 3.493053190467460E+07,
        17: 1.746526595233730E+07
    }

    #Orbital Elements (Quality) Designator
    #ALOS-2/PALSAR-2 Level 1.1/1.5/2.1/3.1 CEOS SAR Product Format Description
    #PALSAR-2_xx_Format_CEOS_E_r.pdf
    orbitElementsDesignator = {
        '0': 'preliminary',
        '1': 'decision',
        '2': 'high precision'
    }

    def __init__(self, name=''):
        super().__init__(family=self.__class__.family, name=name)
        self.leaderFile = None
        self.imageFile = None

        #####Soecific doppler functions for ALOS2
        self.doppler_coeff = None
        self.azfmrate_coeff = None
        self.lineDirection = None
        self.pixelDirection = None

        self.frame = Frame()
        self.frame.configure()

        self.constants = {'polarization': 'HH', 'antennaLength': 10}

    def getFrame(self):
        return self.frame

    def parse(self):
        self.leaderFile = LeaderFile(self, file=self._leaderFile)
        self.leaderFile.parse()

        self.imageFile = ImageFile(self, file=self._imageFile)
        self.imageFile.parse()

        self.populateMetadata()

    def populateMetadata(self):
        """
            Create the appropriate metadata objects from our CEOSFormat metadata
        """
        frame = self._decodeSceneReferenceNumber(
            self.leaderFile.sceneHeaderRecord.
            metadata['Scene reference number'])

        fsamplookup = int(self.leaderFile.sceneHeaderRecord.
                          metadata['Range sampling rate in MHz'])

        rangePixelSize = Const.c / (2 * self.fsampConst[fsamplookup])

        ins = self.frame.getInstrument()
        platform = ins.getPlatform()
        platform.setMission(self.leaderFile.sceneHeaderRecord.
                            metadata['Sensor platform mission identifier'])
        platform.setAntennaLength(self.constants['antennaLength'])
        platform.setPointingDirection(1)
        platform.setPlanet(Planet(pname='Earth'))

        if self.wavelength:
            ins.setRadarWavelength(float(self.wavelength))
#            print('ins.radarWavelength = ', ins.getRadarWavelength(),
#                  type(ins.getRadarWavelength()))
        else:
            ins.setRadarWavelength(
                self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength'])

        ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord.
                              metadata['Incidence angle at scene centre'])
        self.frame.getInstrument().setPulseRepetitionFrequency(
            self.leaderFile.sceneHeaderRecord.
            metadata['Pulse Repetition Frequency in mHz'] * 1.0e-3)
        ins.setRangePixelSize(rangePixelSize)
        ins.setRangeSamplingRate(self.fsampConst[fsamplookup])
        ins.setPulseLength(self.leaderFile.sceneHeaderRecord.
                           metadata['Range pulse length in microsec'] * 1.0e-6)
        chirpSlope = self.leaderFile.sceneHeaderRecord.metadata[
            'Nominal range pulse (chirp) amplitude coefficient linear term']
        chirpPulseBandwidth = abs(
            chirpSlope * self.leaderFile.sceneHeaderRecord.
            metadata['Range pulse length in microsec'] * 1.0e-6)
        ins.setChirpSlope(chirpSlope)
        ins.setInPhaseValue(7.5)
        ins.setQuadratureValue(7.5)

        self.lineDirection = self.leaderFile.sceneHeaderRecord.metadata[
            'Time direction indicator along line direction'].strip()
        self.pixelDirection = self.leaderFile.sceneHeaderRecord.metadata[
            'Time direction indicator along pixel direction'].strip()

        ######ALOS2 includes this information in clock angle
        clockAngle = self.leaderFile.sceneHeaderRecord.metadata[
            'Sensor clock angle']
        if clockAngle == 90.0:
            platform.setPointingDirection(-1)
        elif clockAngle == -90.0:
            platform.setPointingDirection(1)
        else:
            raise Exception(
                'Unknown look side. Clock Angle = {0}'.format(clockAngle))

#        print(self.leaderFile.sceneHeaderRecord.metadata["Sensor ID and mode of operation for this channel"])
        self.frame.setFrameNumber(frame)
        self.frame.setOrbitNumber(
            self.leaderFile.sceneHeaderRecord.metadata['Orbit number'])
        self.frame.setProcessingFacility(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing facility identifier'])
        self.frame.setProcessingSystem(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing system identifier'])
        self.frame.setProcessingSoftwareVersion(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing version identifier'])
        self.frame.setPolarization(self.constants['polarization'])
        self.frame.setNumberOfLines(
            self.imageFile.imageFDR.metadata['Number of lines per data set'])
        self.frame.setNumberOfSamples(
            self.imageFile.imageFDR.
            metadata['Number of pixels per line per SAR channel'])

        ######
        orb = self.frame.getOrbit()

        orb.setOrbitSource('Header')
        orb.setOrbitQuality(self.orbitElementsDesignator[
            self.leaderFile.platformPositionRecord.
            metadata['Orbital elements designator']])
        t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.
                               metadata['Year of data point'],
                               month=self.leaderFile.platformPositionRecord.
                               metadata['Month of data point'],
                               day=self.leaderFile.platformPositionRecord.
                               metadata['Day of data point'])
        t0 = t0 + datetime.timedelta(
            seconds=self.leaderFile.platformPositionRecord.
            metadata['Seconds of day'])

        #####Read in orbit in inertial coordinates
        deltaT = self.leaderFile.platformPositionRecord.metadata[
            'Time interval between data points']
        numPts = self.leaderFile.platformPositionRecord.metadata[
            'Number of data points']

        orb = self.frame.getOrbit()
        for i in range(numPts):
            vec = StateVector()
            t = t0 + datetime.timedelta(seconds=i * deltaT)
            vec.setTime(t)

            dataPoints = self.leaderFile.platformPositionRecord.metadata[
                'Positional Data Points'][i]
            pos = [
                dataPoints['Position vector X'],
                dataPoints['Position vector Y'],
                dataPoints['Position vector Z']
            ]
            vel = [
                dataPoints['Velocity vector X'],
                dataPoints['Velocity vector Y'],
                dataPoints['Velocity vector Z']
            ]
            vec.setPosition(pos)
            vec.setVelocity(vel)
            orb.addStateVector(vec)

        self.doppler_coeff = [
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency centroid constant term'],
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency centroid linear term'],
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency centroid quadratic term']
        ]

        self.azfmrate_coeff = [
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency rate constant term'],
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency rate linear term'],
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency rate quadratic term']
        ]


#        print('Terrain height: ', self.leaderFile.sceneHeaderRecord.metadata['Average terrain ellipsoid height'])

    def extractImage(self):
        import isceobj
        if (self.imageFile is None) or (self.leaderFile is None):
            self.parse()

        try:
            out = open(self.output, 'wb')
        except IOError as strerr:
            self.logger.error("IOError: %s" % strerr)

        self.imageFile.extractImage(output=out)
        out.close()

        #        rangeGate = self.leaderFile.sceneHeaderRecord.metadata['Range gate delay in microsec']*1e-6
        #        delt = datetime.timedelta(seconds=rangeGate)

        delt = datetime.timedelta(seconds=0.0)
        self.frame.setSensingStart(self.imageFile.sensingStart + delt)
        self.frame.setSensingStop(self.imageFile.sensingStop + delt)
        sensingMid = self.imageFile.sensingStart + datetime.timedelta(
            seconds=0.5 * (self.imageFile.sensingStop -
                           self.imageFile.sensingStart).total_seconds()) + delt
        self.frame.setSensingMid(sensingMid)

        self.frame.setStartingRange(self.imageFile.nearRange)

        self.frame.getInstrument().setPulseRepetitionFrequency(
            self.imageFile.prf)

        pixelSize = self.frame.getInstrument().getRangePixelSize()
        farRange = self.imageFile.nearRange + (pixelSize -
                                               1) * self.imageFile.width
        self.frame.setFarRange(farRange)

        rawImage = isceobj.createSlcImage()
        rawImage.setByteOrder('l')
        rawImage.setAccessMode('read')
        rawImage.setFilename(self.output)
        rawImage.setWidth(self.imageFile.width)
        rawImage.setXmin(0)
        rawImage.setXmax(self.imageFile.width)
        rawImage.renderHdr()
        self.frame.setImage(rawImage)

        return

    def extractDoppler(self):
        '''
        Evaluate the doppler polynomial and return the average value for now.
        '''
        midwidth = self.frame.getNumberOfSamples() / 2.0
        dop = 0.0
        prod = 1.0
        for ind, kk in enumerate(self.doppler_coeff):
            dop += kk * prod
            prod *= midwidth

        print('Average Doppler: {0}'.format(dop))

        ####For insarApp
        quadratic = {}
        quadratic['a'] = dop / self.frame.getInstrument(
        ).getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.

        ####For roiApp
        ####More accurate
        ####CEOS already provides function vs pixel
        self.frame._dopplerVsPixel = self.doppler_coeff

        return quadratic

    def _decodeSceneReferenceNumber(self, referenceNumber):
        return referenceNumber
Esempio n. 4
0
class Sentinel1(Sensor):
    """
        A Class representing Sentinel1 StripMap data
    """

    family = 's1sm'
    logging = 'isce.sensor.S1_SM'

    parameter_list = (
        XML,
        TIFF,
        MANIFEST,
        SAFE,
        ORBIT_FILE,
        ORBIT_DIR,
        POLARIZATION,
    ) + Sensor.parameter_list

    def __init__(self, family='', name=''):

        super(Sentinel1,
              self).__init__(family if family else self.__class__.family,
                             name=name)

        self.frame = Frame()
        self.frame.configure()

        self._xml_root = None

    def validateUserInputs(self):
        '''
        Validate inputs from user.
        Populate tiff and xml from SAFE folder name.
        '''

        import fnmatch
        import zipfile

        if not self.xml:
            if not self.safe:
                raise Exception('SAFE directory is not provided')

        ####First find annotation file
        ####Dont need swath number when driving with xml and tiff file
        if not self.xml:
            swathid = 's1?-s?-slc-{}'.format(self.polarization)

        dirname = self.safe
        if not self.xml:
            match = None

            if dirname.endswith('.zip'):
                pattern = os.path.join('*SAFE', 'annotation',
                                       swathid) + '*.xml'
                zf = zipfile.ZipFile(dirname, 'r')
                match = fnmatch.filter(zf.namelist(), pattern)
                zf.close()

                if (len(match) == 0):
                    raise Exception(
                        'No annotation xml file found in zip file: {0}'.format(
                            dirname))

                ####Add /vsizip at the start to make it a zip file
                self.xml = '/vsizip/' + os.path.join(dirname, match[0])

            else:
                pattern = os.path.join('annotation', swathid) + '*.xml'
                match = glob.glob(os.path.join(dirname, pattern))

                if (len(match) == 0):
                    raise Exception(
                        'No annotation xml file found in {0}'.format(dirname))

                self.xml = match[0]

        if not self.xml:
            raise Exception('No annotation files found')

        print('Input XML file: ', self.xml)

        ####Find TIFF file
        if (not self.tiff) and (self.safe):
            match = None

            if dirname.endswith('.zip'):
                pattern = os.path.join('*SAFE', 'measurement',
                                       swathid) + '*.tiff'
                zf = zipfile.ZipFile(dirname, 'r')
                match = fnmatch.filter(zf.namelist(), pattern)
                zf.close()

                if (len(match) == 0):
                    raise Exception(
                        'No tiff file found in zip file: {0}'.format(dirname))

                ####Add /vsizip at the start to make it a zip file
                self.tiff = '/vsizip/' + os.path.join(dirname, match[0])

            else:
                pattern = os.path.join('measurement', swathid) + '*.tiff'
                match = glob.glob(os.path.join(dirname, pattern))

                if len(match) == 0:
                    raise Exception(
                        'No tiff file found in directory: {0}'.format(dirname))

                self.tiff = match[0]

            print('Input TIFF files: ', self.tiff)

        ####Find manifest files
        if self.safe:
            if dirname.endswith('.zip'):
                pattern = '*SAFE/manifest.safe'
                zf = zipfile.ZipFile(dirname, 'r')
                match = fnmatch.filter(zf.namelist(), pattern)
                zf.close()
                self.manifest = '/vsizip/' + os.path.join(dirname, match[0])
            else:
                self.manifest = os.path.join(dirname, 'manifest.safe')

            print('Manifest files: ', self.manifest)

        return

    def getFrame(self):
        return self.frame

    def parse(self):
        '''
        Actual parsing of the metadata for the product.
        '''
        from isceobj.Sensor.TOPS.Sentinel1 import s1_findOrbitFile
        ###Check user inputs
        self.validateUserInputs()

        if self.xml.startswith('/vsizip'):
            import zipfile
            parts = self.xml.split(os.path.sep)

            if parts[2] == '':
                parts[2] = os.path.sep

            zipname = os.path.join(*(parts[2:-3]))
            fname = os.path.join(*(parts[-3:]))

            zf = zipfile.ZipFile(zipname, 'r')
            xmlstr = zf.read(fname)
            zf.close()
        else:
            with open(self.xml, 'r') as fid:
                xmlstr = fid.read()

        self._xml_root = ET.fromstring(xmlstr)
        self.populateMetadata()

        if self.manifest:
            self.populateIPFVersion()
        else:
            self.frame.setProcessingFacility('ESA')
            self.frame.setProcessingSoftwareVersion('IPFx.xx')

        if not self.orbitFile:
            if self.orbitDir:
                self.orbitFile = s1_findOrbitFile(
                    self.orbitDir,
                    self.frame.sensingStart,
                    self.frame.sensingStop,
                    mission=self.frame.getInstrument().getPlatform(
                    ).getMission())

        if self.orbitFile:
            orb = self.extractPreciseOrbit()
            self.frame.orbit.setOrbitSource(os.path.basename(self.orbitFile))
        else:
            orb = self.extractOrbitFromAnnotation()
            self.frame.orbit.setOrbitSource('Annotation')

        for sv in orb:
            self.frame.orbit.addStateVector(sv)

    def grab_from_xml(self, path):
        try:
            res = self._xml_root.find(path).text
        except:
            raise Exception('Tag= %s not found' % (path))

        if res is None:
            raise Exception('Tag = %s not found' % (path))

        return res

    def convertToDateTime(self, string):
        dt = datetime.datetime.strptime(string, "%Y-%m-%dT%H:%M:%S.%f")
        return dt

    def populateMetadata(self):
        """
            Create metadata objects from the metadata files
        """
        ####Set each parameter one - by - one
        mission = self.grab_from_xml('adsHeader/missionId')
        swath = self.grab_from_xml('adsHeader/swath')
        polarization = self.grab_from_xml('adsHeader/polarisation')

        frequency = float(
            self.grab_from_xml(
                'generalAnnotation/productInformation/radarFrequency'))
        passDirection = self.grab_from_xml(
            'generalAnnotation/productInformation/pass')

        rangePixelSize = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/rangePixelSpacing'))
        azimuthPixelSize = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/azimuthPixelSpacing'))
        rangeSamplingRate = Const.c / (2.0 * rangePixelSize)
        prf = 1.0 / float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/azimuthTimeInterval'))

        lines = int(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/numberOfLines'))
        samples = int(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/numberOfSamples'))

        startingRange = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/slantRangeTime')
        ) * Const.c / 2.0
        incidenceAngle = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/incidenceAngleMidSwath'))
        dataStartTime = self.convertToDateTime(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/productFirstLineUtcTime'))
        dataStopTime = self.convertToDateTime(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/productLastLineUtcTime'))

        pulseLength = float(
            self.grab_from_xml(
                'generalAnnotation/downlinkInformationList/downlinkInformation/downlinkValues/txPulseLength'
            ))
        chirpSlope = float(
            self.grab_from_xml(
                'generalAnnotation/downlinkInformationList/downlinkInformation/downlinkValues/txPulseRampRate'
            ))
        pulseBandwidth = pulseLength * chirpSlope

        ####Sentinel is always right looking
        lookSide = -1

        #        height = self.product.imageGenerationParameters.sarProcessingInformation._satelliteHeight

        ####Populate platform
        platform = self.frame.getInstrument().getPlatform()
        platform.setPlanet(Planet(pname="Earth"))
        platform.setMission(mission)
        platform.setPointingDirection(lookSide)
        platform.setAntennaLength(2 * azimuthPixelSize)

        ####Populate instrument
        instrument = self.frame.getInstrument()
        instrument.setRadarFrequency(frequency)
        instrument.setPulseRepetitionFrequency(prf)
        instrument.setPulseLength(pulseLength)
        instrument.setChirpSlope(pulseBandwidth / pulseLength)
        instrument.setIncidenceAngle(incidenceAngle)
        #self.frame.getInstrument().setRangeBias(0)
        instrument.setRangePixelSize(rangePixelSize)
        instrument.setRangeSamplingRate(rangeSamplingRate)
        instrument.setBeamNumber(swath)
        instrument.setPulseLength(pulseLength)

        #Populate Frame
        #self.frame.setSatelliteHeight(height)
        self.frame.setSensingStart(dataStartTime)
        self.frame.setSensingStop(dataStopTime)
        diffTime = DTUtil.timeDeltaToSeconds(dataStopTime -
                                             dataStartTime) / 2.0
        sensingMid = dataStartTime + datetime.timedelta(
            microseconds=int(diffTime * 1e6))
        self.frame.setSensingMid(sensingMid)
        self.frame.setPassDirection(passDirection)
        self.frame.setPolarization(polarization)
        self.frame.setStartingRange(startingRange)
        self.frame.setFarRange(startingRange + (samples - 1) * rangePixelSize)
        self.frame.setNumberOfLines(lines)
        self.frame.setNumberOfSamples(samples)

        self.frame.setPassDirection(passDirection)

    def extractOrbitFromAnnotation(self):
        '''
        Extract orbit information from xml node.
        '''

        node = self._xml_root.find('generalAnnotation/orbitList')
        frameOrbit = Orbit()
        frameOrbit.setOrbitSource('Header')

        for child in node:
            timestamp = self.convertToDateTime(child.find('time').text)
            pos = []
            vel = []
            posnode = child.find('position')
            velnode = child.find('velocity')
            for tag in ['x', 'y', 'z']:
                pos.append(float(posnode.find(tag).text))

            for tag in ['x', 'y', 'z']:
                vel.append(float(velnode.find(tag).text))

            vec = StateVector()
            vec.setTime(timestamp)
            vec.setPosition(pos)
            vec.setVelocity(vel)
            frameOrbit.addStateVector(vec)

        planet = self.frame.instrument.platform.planet
        orbExt = OrbitExtender(planet=planet)
        orbExt.configure()
        newOrb = orbExt.extendOrbit(frameOrbit)

        return newOrb

    def extractPreciseOrbit(self):
        '''
        Extract precise orbit from given Orbit file.
        '''
        try:
            fp = open(self.orbitFile, 'r')
        except IOError as strerr:
            print("IOError: %s" % strerr)
            return

        _xml_root = ET.ElementTree(file=fp).getroot()

        node = _xml_root.find('Data_Block/List_of_OSVs')

        orb = Orbit()
        orb.configure()

        margin = datetime.timedelta(seconds=40.0)
        tstart = self.frame.getSensingStart() - margin
        tend = self.frame.getSensingStop() + margin

        for child in node:
            timestamp = self.convertToDateTime(child.find('UTC').text[4:])

            if (timestamp >= tstart) and (timestamp < tend):

                pos = []
                vel = []

                for tag in ['VX', 'VY', 'VZ']:
                    vel.append(float(child.find(tag).text))

                for tag in ['X', 'Y', 'Z']:
                    pos.append(float(child.find(tag).text))

                vec = StateVector()
                vec.setTime(timestamp)
                vec.setPosition(pos)
                vec.setVelocity(vel)
                orb.addStateVector(vec)

        fp.close()

        return orb

    def extractImage(self):
        """
           Use gdal python bindings to extract image
        """
        try:
            from osgeo import gdal
        except ImportError:
            raise Exception(
                'GDAL python bindings not found. Need this for RSAT2/ TandemX / Sentinel1A.'
            )

        self.parse()
        width = self.frame.getNumberOfSamples()
        lgth = self.frame.getNumberOfLines()

        src = gdal.Open(self.tiff.strip(), gdal.GA_ReadOnly)
        band = src.GetRasterBand(1)
        fid = open(self.output, 'wb')
        for ii in range(lgth):
            data = band.ReadAsArray(0, ii, width, 1)
            data.tofile(fid)

        fid.close()
        src = None
        band = None

        ####
        slcImage = isceobj.createSlcImage()
        slcImage.setByteOrder('l')
        slcImage.setFilename(self.output)
        slcImage.setAccessMode('read')
        slcImage.setWidth(self.frame.getNumberOfSamples())
        slcImage.setLength(self.frame.getNumberOfLines())
        slcImage.setXmin(0)
        slcImage.setXmax(self.frame.getNumberOfSamples())
        self.frame.setImage(slcImage)

    def extractDoppler(self):
        '''
        self.parse()
        Extract doppler information as needed by mocomp
        '''
        from isceobj.Util import Poly1D

        node = self._xml_root.find('dopplerCentroid/dcEstimateList')

        tdiff = 1.0e9
        dpoly = None

        for index, burst in enumerate(node):
            refTime = self.convertToDateTime(burst.find('azimuthTime').text)

            delta = abs((refTime - self.frame.sensingMid).total_seconds())
            if delta < tdiff:
                tdiff = delta
                r0 = 0.5 * Const.c * float(burst.find('t0').text)
                coeffs = [
                    float(val)
                    for val in burst.find('dataDcPolynomial').text.split()
                ]

                poly = Poly1D.Poly1D()
                poly.initPoly(order=len(coeffs) - 1)
                poly.setMean(r0)
                poly.setNorm(0.5 * Const.c)
                poly.setCoeffs(coeffs)

                dpoly = poly

        if dpoly is None:
            raise Exception(
                'Could not extract Doppler information for S1 scene')

        ###Part for insarApp
        ###Should be removed in the future
        rmid = self.frame.startingRange + 0.5 * self.frame.getNumberOfSamples(
        ) * self.frame.getInstrument().getRangePixelSize()

        quadratic = {}
        quadratic['a'] = dpoly(
            rmid) / self.frame.getInstrument().getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.

        ###Actual Doppler Polynomial for accurate processing
        ###Will be used in roiApp
        pix = np.linspace(0,
                          self.frame.getNumberOfSamples(),
                          num=dpoly._order + 2)
        rngs = self.frame.startingRange + pix * self.frame.getInstrument(
        ).getRangePixelSize()
        evals = dpoly(rngs)
        fit = np.polyfit(pix, evals, dpoly._order)
        self.frame._dopplerVsPixel = list(fit[::-1])
        print('Doppler Fit : ', fit[::-1])

        return quadratic

    def populateIPFVersion(self):
        '''
        Get IPF version from the manifest file.
        '''

        try:
            if self.manifest.startswith('/vsizip'):
                import zipfile
                parts = self.manifest.split(os.path.sep)
                if parts[2] == '':
                    parts[2] = os.path.sep
                zipname = os.path.join(*(parts[2:-2]))
                fname = os.path.join(*(parts[-2:]))
                print('MANS: ', zipname, fname)

                zf = zipfile.ZipFile(zipname, 'r')
                xmlstr = zf.read(fname)

            else:
                with open(self.manifest, 'r') as fid:
                    xmlstr = fid.read()

            ####Setup namespace
            nsp = "{http://www.esa.int/safe/sentinel-1.0}"

            root = ET.fromstring(xmlstr)

            elem = root.find('.//metadataObject[@ID="processing"]')

            rdict = elem.find('.//xmlData/' + nsp + 'processing/' + nsp +
                              'facility').attrib
            self.frame.setProcessingFacility(rdict['site'] + ', ' +
                                             rdict['country'])

            rdict = elem.find('.//xmlData/' + nsp + 'processing/' + nsp +
                              'facility/' + nsp + 'software').attrib

            self.frame.setProcessingSoftwareVersion(rdict['name'] + ' ' +
                                                    rdict['version'])

        except:  ###Not a critical error ... continuing
            print(
                'Could not read version number successfully from manifest file: ',
                self.manifest)
            pass

        return
Esempio n. 5
0
class KOMPSAT5(Component):
    """
    A class representing a Level1Product meta data.
    Level1Product(hdf5=h5filename) will parse the hdf5
    file and produce an object with attributes for metadata.
    """

    logging_name = 'isce.Sensor.KOMPSAT5'

    def __init__(self):
        super(KOMPSAT5,self).__init__()
        self.hdf5 = None
        self.output = None
        self.frame = Frame()
        self.frame.configure()
        # Some extra processing parameters unique to CSK SLC (currently)
        self.dopplerCoeffs = []
        self.rangeFirstTime = None
        self.rangeLastTime = None
        self.rangeRefTime = None
        self.refUTC = None
        
        self.descriptionOfVariables = {}
        self.dictionaryOfVariables = {'HDF5': ['self.hdf5','str','mandatory'],
                                      'OUTPUT': ['self.output','str','optional']}
        
        self.lookMap = {'RIGHT': -1,
                        'LEFT': 1}                            
        return

    def __getstate__(self):
        d = dict(self.__dict__)
        del d['logger']
        return d

    def __setstate__(self,d):
        self.__dict__.update(d)
        self.logger = logging.getLogger('isce.Sensor.COSMO_SkyMed_SLC')
        return

    
    def getFrame(self):
        return self.frame
    
    def parse(self):
        try:
            fp = h5py.File(self.hdf5,'r')
        except Exception as strerr:
            self.logger.error("IOError: %s" % strerr)
            return None

        self.populateMetadata(fp)
        fp.close()

    def populateMetadata(self, file):
        """
            Populate our Metadata objects
        """
        
        self._populatePlatform(file)
        self._populateInstrument(file)
        self._populateFrame(file)
        self._populateOrbit(file)
        self._populateExtras(file)
    
    def _populatePlatform(self, file):
        platform = self.frame.getInstrument().getPlatform()

        platform.setMission(file.attrs['Satellite ID'])
        platform.setPointingDirection(self.lookMap[file.attrs['Look Side'].decode('utf-8')])
        platform.setPlanet(Planet("Earth"))                            

        ####This is an approximation for spotlight mode
        ####In spotlight mode, antenna length changes with azimuth position
        platform.setAntennaLength(file.attrs['Antenna Length'])
        try:
            if file.attrs['Multi-Beam ID'].startswith('ES'):
                platform.setAntennaLength(16000.0/file['S01/SBI'].attrs['Line Time Interval'])
        except:
            pass
    
    def _populateInstrument(self, file):
        instrument = self.frame.getInstrument()

#        rangePixelSize = Const.c/(2*file['S01'].attrs['Sampling Rate'])  
        rangePixelSize = file['S01/SBI'].attrs['Column Spacing']
        instrument.setRadarWavelength(file.attrs['Radar Wavelength'])
#        instrument.setPulseRepetitionFrequency(file['S01'].attrs['PRF'])
        instrument.setPulseRepetitionFrequency(1.0/file['S01/SBI'].attrs['Line Time Interval'])
        instrument.setRangePixelSize(rangePixelSize)
        instrument.setPulseLength(file['S01'].attrs['Range Chirp Length'])        
        instrument.setChirpSlope(file['S01'].attrs['Range Chirp Rate'])                
#        instrument.setRangeSamplingRate(file['S01'].attrs['Sampling Rate'])
        instrument.setRangeSamplingRate(1.0/file['S01/SBI'].attrs['Column Time Interval'])

        incangle = 0.5*(file['S01/SBI'].attrs['Far Incidence Angle'] +
                 file['S01/SBI'].attrs['Near Incidence Angle'])
        instrument.setIncidenceAngle(incangle) 


    def _populateFrame(self, file):

        rft = file['S01/SBI'].attrs['Zero Doppler Range First Time']
        slantRange = rft*Const.c/2.0
        self.frame.setStartingRange(slantRange)
        
        referenceUTC = self._parseNanoSecondTimeStamp(file.attrs['Reference UTC'])
        relStart = file['S01/SBI'].attrs['Zero Doppler Azimuth First Time']
        relEnd = file['S01/SBI'].attrs['Zero Doppler Azimuth Last Time']
        relMid = 0.5*(relStart + relEnd)
        
        sensingStart = self._combineDateTime(referenceUTC, relStart) 
        sensingStop = self._combineDateTime(referenceUTC, relEnd)        
        sensingMid = self._combineDateTime(referenceUTC, relMid)           
        
        
        self.frame.setPassDirection(file.attrs['Orbit Direction'])
        self.frame.setOrbitNumber(file.attrs['Orbit Number'])              
        self.frame.setProcessingFacility(file.attrs['Processing Centre'])        
        self.frame.setProcessingSoftwareVersion(file.attrs['L0 Software Version'])
        self.frame.setPolarization(file['S01'].attrs['Polarisation'])
        self.frame.setNumberOfLines(file['S01/SBI'].shape[0])
        self.frame.setNumberOfSamples(file['S01/SBI'].shape[1])
        self.frame.setSensingStart(sensingStart)
        self.frame.setSensingMid(sensingMid)
        self.frame.setSensingStop(sensingStop)

        rangePixelSize = self.frame.getInstrument().getRangePixelSize()
        farRange = slantRange +  (self.frame.getNumberOfSamples()-1)*rangePixelSize
        self.frame.setFarRange(farRange)

    def _populateOrbit(self,file):
        orbit = self.frame.getOrbit()
        
        orbit.setReferenceFrame('ECR')
        orbit.setOrbitSource('Header')
        t0 = datetime.datetime.strptime(file.attrs['Reference UTC'].decode('utf-8'),'%Y-%m-%d %H:%M:%S.%f000')
        t = file.attrs['State Vectors Times']
        position = file.attrs['ECEF Satellite Position']
        velocity = file.attrs['ECEF Satellite Velocity']
                
        for i in range(len(position)):
            vec = StateVector()
            dt = t0 + datetime.timedelta(seconds=t[i])          
            vec.setTime(dt)            
            vec.setPosition([position[i,0],position[i,1],position[i,2]])
            vec.setVelocity([velocity[i,0],velocity[i,1],velocity[i,2]])
            orbit.addStateVector(vec)


    def _populateExtras(self, file):
        """
        Populate some of the extra fields unique to processing TSX data.
        In the future, other sensors may need this information as well, 
        and a re-organization may be necessary.
        """
        from isceobj.Doppler.Doppler import Doppler

        scale = file['S01'].attrs['PRF'] * file['S01/SBI'].attrs['Line Time Interval']
        self.dopplerCoeffs = file.attrs['Centroid vs Range Time Polynomial']*scale
        self.rangeRefTime = file.attrs['Range Polynomial Reference Time']
        self.rangeFirstTime = file['S01/SBI'].attrs['Zero Doppler Range First Time']
        self.rangeLastTime = file['S01/SBI'].attrs['Zero Doppler Range Last Time']

    def extractImage(self):
        import os
        from ctypes import cdll, c_char_p
        extract_csk = cdll.LoadLibrary(os.path.dirname(__file__)+'/csk.so')
        inFile_c = c_char_p(bytes(self.hdf5, 'utf-8'))
        outFile_c = c_char_p(bytes(self.output, 'utf-8'))

        extract_csk.extract_csk_slc(inFile_c, outFile_c)

        self.parse()
        slcImage = isceobj.createSlcImage()
        slcImage.setFilename(self.output)
        slcImage.setXmin(0)
        slcImage.setXmax(self.frame.getNumberOfSamples())
        slcImage.setWidth(self.frame.getNumberOfSamples())
        slcImage.setAccessMode('r')
        self.frame.setImage(slcImage)
       

    def _parseNanoSecondTimeStamp(self,timestamp):
        """
            Parse a date-time string with nanosecond precision and return a datetime object
        """
        dateTime,nanoSeconds = timestamp.decode('utf-8').split('.')
        microsec = float(nanoSeconds)*1e-3
        dt = datetime.datetime.strptime(dateTime,'%Y-%m-%d %H:%M:%S')
        dt = dt + datetime.timedelta(microseconds=microsec)
        return dt

    def _combineDateTime(self,dobj, secsstr):
        '''Takes the date from dobj and time from secs to spit out a date time object.
        '''
        sec = float(secsstr)
        dt = datetime.timedelta(seconds = sec)
        return dobj + dt
       

    def extractDoppler(self):
        """
        Return the doppler centroid as defined in the HDF5 file.
        """
        quadratic = {}
        midtime = (self.rangeLastTime + self.rangeFirstTime)*0.5 - self.rangeRefTime
        fd_mid = self.dopplerCoeffs[0] + self.dopplerCoeffs[1]*midtime + self.dopplerCoeffs[2]*midtime*midtime

        quadratic['a'] = fd_mid/self.frame.getInstrument().getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.
        return quadratic
Esempio n. 6
0
class ERS(Component):

    #Parsers.CEOS.CEOSFormat.ceosTypes['text'] =
    #    {'typeCode': 63, 'subtypeCode': [18,18,18]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['leaderFile'] =
    #    {'typeCode': 192, 'subtypeCode': [63,18,18]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['dataSetSummary'] =
    #    {'typeCode': 10, 'subtypeCode': [10,31,20]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['platformPositionData'] =
    #    {'typeCode': 30, 'subtypeCode': [10,31,20]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['facilityData'] =
    #    {'typeCode': 200, 'subtypeCode': [10,31,50]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['datafileDescriptor'] =
    #    {'typeCode': 192, 'subtypeCode':[63,18,18]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['signalData'] =
    #    {'typeCode': 10, 'subtypeCode': [50,31,20]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['nullFileDescriptor'] =
    #    {'typeCode': 192, 'subtypeCode': [192,63,18]}

    logging_name = 'isce.sensor.ers'

    def __init__(self):
        Component.__init__(self)
        self._leaderFile = None
        self._imageFileList = ''
        self._leaderFileList = ''
        self._imageFile = None
        self._orbitDir = None # Use this for Delft Orbit files
        self._orbitFile = None # Use this for PDS Orbit files for now
        self._orbitType = None
        self.frameList = []
        self.output = None

        self.descriptionOfVariables = {}
        self.dictionaryOfVariables = {
            'ORBIT_TYPE': ['self._orbitType','str','mandatory'],
            'ORBIT_DIRECTORY': ['self._orbitDir','str','optional'],
            'ORBIT_FILE': ['self._orbitFile','str','optional'],
            'LEADERFILE': ['self._leaderFileList','str','mandatory'],
            'IMAGEFILE': ['self._imageFileList','str','mandatory'],
            'OUTPUT': ['self.output','str','optional']}


        self.frame = Frame()
        self.frame.configure()

        # Constants are from
        # J. J. Mohr and S. N. Madsen. Geometric calibration of ERS satellite
        # SAR images. IEEE T. Geosci. Remote, 39(4):842-850, Apr. 2001.
        self.constants = {'polarization': 'VV',
                          'antennaLength': 10,
                          'lookDirection': 'RIGHT',
                          'chirpPulseBandwidth': 15.50829e6,
                          'rangeSamplingRate': 18.962468e6,
                          'delayTime':6.622e-6,
                          'iBias': 15.5,
                          'qBias': 15.5}
        return None

    def getFrame(self):
        return self.frame

    def parse(self):
        self.leaderFile = LeaderFile(file=self._leaderFile)
        self.leaderFile.parse()

        self.imageFile = ImageFile(self)
        self.imageFile.parse()

        self.populateMetadata()

    def populateMetadata(self):
        """
        Create the appropriate metadata objects from our CEOSFormat metadata
        """

        self._populatePlatform()
        self._populateInstrument()
        self._populateFrame()
        if (self._orbitType == 'ODR'):
            self._populateDelftOrbits()
        elif (self._orbitType == 'PRC'):
            self._populatePRCOrbits()
        elif (self._orbitType == 'PDS'):
            self._populatePDSOrbits()
        else:
            self._populateHeaderOrbit()

    def _populatePlatform(self):
        """
        Populate the platform object with metadata
        """

        platform = self.frame.getInstrument().getPlatform()

        platform.setMission(self.leaderFile.sceneHeaderRecord.metadata[
            'Sensor platform mission identifier'])
        platform.setAntennaLength(self.constants['antennaLength'])
        platform.setPointingDirection(-1)
        platform.setPlanet(Planet('Earth'))

    def _populateInstrument(self):
        """Populate the instrument object with metadata"""
        instrument = self.frame.getInstrument()
        pri = self.imageFile.firstPri
        rangeSamplingRate = self.constants['rangeSamplingRate']
        #rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata[
        #    'Range sampling rate']*1e6
        rangePixelSize = Const.c/(2.0*rangeSamplingRate)
        pulseInterval = 4.0/rangeSamplingRate*(pri+2.0)
        prf = 1.0/pulseInterval

        instrument.setRadarWavelength(
            self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength'])
        instrument.setIncidenceAngle(
            self.leaderFile.sceneHeaderRecord.metadata[
            'Incidence angle at scene centre'])
        instrument.setPulseRepetitionFrequency(prf)
        instrument.setRangeSamplingRate(rangeSamplingRate)
        instrument.setRangePixelSize(rangePixelSize)
        instrument.setPulseLength(self.leaderFile.sceneHeaderRecord.metadata[
            'Range pulse length']*1e-6)
        instrument.setChirpSlope(self.constants['chirpPulseBandwidth']/
            (self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']*
             1e-6))
        instrument.setInPhaseValue(self.constants['iBias'])
        instrument.setQuadratureValue(self.constants['qBias'])

    def _populateFrame(self):
        """Populate the scene object with metadata"""
        rangeSamplingRate = self.constants['rangeSamplingRate']
        #rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata[
        #    'Range sampling rate']*1e6
        rangePixelSize = Const.c/(2.0*rangeSamplingRate)
        pulseInterval = 1.0/self.frame.getInstrument().getPulseRepetitionFrequency()
        frame = self._decodeSceneReferenceNumber(
            self.leaderFile.sceneHeaderRecord.metadata[
            'Scene reference number'])
        startingRange = (9*pulseInterval + self.imageFile.minSwst*4/rangeSamplingRate-self.constants['delayTime'])*Const.c/2.0
        farRange = startingRange + self.imageFile.width*rangePixelSize
        # Use the Scene center time to get the date, then use the ICU on board time from the image for the rest
        centerLineTime = datetime.datetime.strptime(self.leaderFile.sceneHeaderRecord.metadata['Scene centre time'],"%Y%m%d%H%M%S%f")
        first_line_utc = datetime.datetime(year=centerLineTime.year, month=centerLineTime.month, day=centerLineTime.day)
        if(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier'] in ('CRDC_SARDPF','GTS - ERS')):
            first_line_utc = first_line_utc + datetime.timedelta(milliseconds=self.imageFile.startTime)
        else:
            deltaSeconds = (self.imageFile.startTime - self.leaderFile.sceneHeaderRecord.metadata['Satellite encoded binary time code'])* 1/256.0
            # Sometimes, the ICU on board clock is corrupt, if the time suggested by the on board clock is more than
            # 5 days from the satellite clock time, assume its bogus and use the low-precision scene centre time
            if (math.fabs(deltaSeconds) > 5*86400):
                        self.logger.warn("ICU on board time appears to be corrupt, resorting to low precision clock")
                        first_line_utc = centerLineTime - datetime.timedelta(microseconds=pulseInterval*(self.imageFile.length/2.0)*1e6)
            else:
                satelliteClockTime = datetime.datetime.strptime(self.leaderFile.sceneHeaderRecord.metadata['Satellite clock time'],"%Y%m%d%H%M%S%f")
                first_line_utc = satelliteClockTime + datetime.timedelta(microseconds=int(deltaSeconds*1e6))
        mid_line_utc = first_line_utc + datetime.timedelta(microseconds=pulseInterval*(self.imageFile.length/2.0)*1e6)
        last_line_utc = first_line_utc + datetime.timedelta(microseconds=pulseInterval*self.imageFile.length*1e6)
        self.logger.debug("Frame UTC start, mid, end times:  %s %s %s" % (first_line_utc,mid_line_utc,last_line_utc))

        self.frame.setFrameNumber(frame)
        self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number'])
        self.frame.setStartingRange(startingRange)
        self.frame.setFarRange(farRange)
        self.frame.setProcessingFacility(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier'])
        self.frame.setProcessingSystem(self.leaderFile.sceneHeaderRecord.metadata['Processing system identifier'])
        self.frame.setProcessingSoftwareVersion(self.leaderFile.sceneHeaderRecord.metadata['Processing version identifier'])
        self.frame.setPolarization(self.constants['polarization'])
        self.frame.setNumberOfLines(self.imageFile.length)
        self.frame.setNumberOfSamples(self.imageFile.width)
        self.frame.setSensingStart(first_line_utc)
        self.frame.setSensingMid(mid_line_utc)
        self.frame.setSensingStop(last_line_utc)

    def _populateHeaderOrbit(self):
        """Populate an orbit object with the header orbits"""
        self.logger.info("Using Header Orbits")
        orbit = self.frame.getOrbit()

        orbit.setOrbitSource('Header')
        orbit.setOrbitQuality('Unknown')
        t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.metadata['Year of data point'],
                               month=self.leaderFile.platformPositionRecord.metadata['Month of data point'],
                               day=self.leaderFile.platformPositionRecord.metadata['Day of data point'])
        t0 = t0 + datetime.timedelta(microseconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day']*1e6)
        for i in range(self.leaderFile.platformPositionRecord.metadata['Number of data points']):
            vec = StateVector()
            deltaT = self.leaderFile.platformPositionRecord.metadata['Time interval between DATA points']
            t = t0 + datetime.timedelta(microseconds=i*deltaT*1e6)
            vec.setTime(t)
            dataPoints = self.leaderFile.platformPositionRecord.metadata['Positional Data Points'][i]
            vec.setPosition([dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z']])
            vec.setVelocity([dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z']])
            orbit.addStateVector(vec)

    def _populateDelftOrbits(self):
        """Populate an orbit object with the Delft orbits"""
        from isceobj.Orbit.ODR import ODR, Arclist
        self.logger.info("Using Delft Orbits")
        arclist = Arclist(os.path.join(self._orbitDir,'arclist'))
        arclist.parse()
        orbitFile = arclist.getOrbitFile(self.frame.getSensingStart())
        odr = ODR(file=os.path.join(self._orbitDir,orbitFile))
        #jng it seem that for this tipe of orbit points are separated by 60 sec. In ODR at least 9 state vectors are needed to compute the velocities. add
        # extra time before and after to allow interpolation, but do not do it for all data points. too slow
        startTimePreInterp = self.frame.getSensingStart() - datetime.timedelta(minutes=60)
        stopTimePreInterp = self.frame.getSensingStop() + datetime.timedelta(minutes=60)
        odr.parseHeader(startTimePreInterp,stopTimePreInterp)
        startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5)
        stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5)
        self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime))
        orbit = odr.trimOrbit(startTime,stopTime)
        self.frame.setOrbit(orbit)

    def _populatePRCOrbits(self):
        """Populate an orbit object the D-PAF PRC orbits"""
        from isceobj.Orbit.PRC import PRC, Arclist
        self.logger.info("Using PRC Orbits")
        arclist = Arclist(os.path.join(self._orbitDir,'arclist'))
        arclist.parse()
        orbitFile = arclist.getOrbitFile(self.frame.getSensingStart())
        self.logger.debug("Using file %s" % (orbitFile))
        prc = PRC(file=os.path.join(self._orbitDir,orbitFile))
        prc.parse()
        startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5)
        stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5)
        self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime))
        fullOrbit = prc.getOrbit()
        orbit = fullOrbit.trimOrbit(startTime,stopTime)
        self.frame.setOrbit(orbit)

    def _populatePDSOrbits(self):
        """
        Populate an orbit object using the ERS-2 PDS format
        """
        from isceobj.Orbit.PDS import PDS
        self.logger.info("Using PDS Orbits")
        pds = PDS(file=self._orbitFile)
        pds.parse()
        startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5)
        stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5)
        self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime))
        fullOrbit = pds.getOrbit()
        orbit = fullOrbit.trimOrbit(startTime,stopTime)
        self.frame.setOrbit(orbit)

    def extractImage(self):
        import array
        import math
        # just in case there was only one image and it was passed as a str instead of a list with only one element
        if(isinstance(self._imageFileList,str)):
            self._imageFileList = [self._imageFileList]
            self._leaderFileList = [self._leaderFileList]
        if(len(self._imageFileList) != len(self._leaderFileList)):
            self.logger.error("Number of leader files different from number of image files.")
            raise Exception

        self.frameList = []

        for i in range(len(self._imageFileList)):
            appendStr = "_" + str(i)
            #if only one file don't change the name
            if(len(self._imageFileList) == 1):
                appendStr = ''

            self.frame = Frame()
            self.frame.configure()

            self._leaderFile = self._leaderFileList[i]
            self._imageFile = self._imageFileList[i]
            self.leaderFile = LeaderFile(file=self._leaderFile)
            self.leaderFile.parse()

            self.imageFile = ImageFile(self)

            try:
                outputNow = self.output + appendStr
                out = open(outputNow,'wb')
            except IOError as strerr:
                self.logger.error("IOError: %s" % strerr)
                return

            self.imageFile.extractImage(output=out)
            out.close()

            rawImage = isceobj.createRawImage()
            rawImage.setByteOrder('l')
            rawImage.setAccessMode('read')
            rawImage.setFilename(outputNow)
            rawImage.setWidth(self.imageFile.width)
            rawImage.setXmin(0)
            rawImage.setXmax(self.imageFile.width)
            self.frame.setImage(rawImage)
            self.populateMetadata()
            self.frameList.append(self.frame)
            #jng Howard Z at this point adjusts the sampling starting time for imagery generated from CRDC_SARDPF facility.
            # for now create the orbit aux file based in starting time and prf
            prf = self.frame.getInstrument().getPulseRepetitionFrequency()
            senStart = self.frame.getSensingStart()
            numPulses = int(math.ceil(DTU.timeDeltaToSeconds(self.frame.getSensingStop()-senStart)*prf))
            # the aux files has two entries per line. day of the year and microseconds in the day
            musec0 = (senStart.hour*3600 + senStart.minute*60 + senStart.second)*10**6 + senStart.microsecond
            maxMusec = (24*3600)*10**6#use it to check if we went across  a day. very rare
            day0 = (datetime.datetime(senStart.year,senStart.month,senStart.day) - datetime.datetime(senStart.year,1,1)).days + 1
            outputArray  = array.array('d',[0]*2*numPulses)
            self.frame.auxFile = outputNow + '.aux'
            fp = open(self.frame.auxFile,'wb')
            j = -1
            for i1 in range(numPulses):
                j += 1
                musec = round((j/prf)*10**6) + musec0
                if musec >= maxMusec:
                    day0 += 1
                    musec0 = musec%maxMusec
                    musec = musec0
                    j = 0
                outputArray[2*i1] = day0
                outputArray[2*i1+1] = musec

            outputArray.tofile(fp)
            fp.close()

        tk = Track()
        if(len(self._imageFileList) > 1):
            self.frame = tk.combineFrames(self.output,self.frameList)

            for i in range(len(self._imageFileList)):
                try:
                    os.remove(self.output + "_" + str(i))
                except OSError:
                    print("Error. Cannot remove temporary file",self.output + "_" + str(i))
                    raise OSError



    def _decodeSceneReferenceNumber(self,referenceNumber):
        frameNumber = referenceNumber.split('=')
        if (len(frameNumber) > 2):
            frameNumber = frameNumber[2].strip()
        else:
            frameNumber = frameNumber[0]

        return frameNumber
Esempio n. 7
0
class UAVSAR_HDF5_SLC(Sensor):
    """
    A class representing a Level1Product meta data.
    Level1Product(hdf5=h5filename) will parse the hdf5
    file and produce an object with attributes for metadata.
    """
    parameter_list = (HDF5, FREQUENCY, POLARIZATION) + Sensor.parameter_list

    logging_name = 'isce.Sensor.UAVSAR_HDF5_SLC'
    family = 'uavsar_hdf5_slc'

    def __init__(self,
                 family='',
                 name=''):  # , frequency='frequencyA', polarization='HH'):
        super(UAVSAR_HDF5_SLC,
              self).__init__(family if family else self.__class__.family,
                             name=name)
        self.frame = Frame()
        self.frame.configure()
        # Some extra processing parameters unique to UAVSAR HDF5 SLC (currently)
        self.dopplerRangeTime = []
        self.dopplerAzimuthTime = []
        self.azimuthRefTime = None
        self.rangeRefTime = None
        self.rangeFirstTime = None
        self.rangeLastTime = None
        #self.frequency = frequency
        #self.polarization = polarization

        self.lookMap = {'right': -1, 'left': 1}
        return

    def __getstate__(self):
        d = dict(self.__dict__)
        del d['logger']
        return d

    def __setstate__(self, d):
        self.__dict__.update(d)
        self.logger = logging.getLogger('isce.Sensor.UAVSAR_HDF5_SLC')
        return

    def getFrame(self):
        return self.frame

    def parse(self):
        try:
            fp = h5py.File(self.hdf5, 'r')
        except Exception as strerr:
            self.logger.error("IOError: %s" % strerr)
            return None

        self.populateMetadata(fp)
        fp.close()

    def populateMetadata(self, file):
        """
            Populate our Metadata objects
        """

        self._populatePlatform(file)
        self._populateInstrument(file)
        self._populateFrame(file)
        self._populateOrbit(file)

    def _populatePlatform(self, file):
        platform = self.frame.getInstrument().getPlatform()

        platform.setMission(
            file['/science/LSAR/identification'].get('missionId')[(
            )].decode('utf-8'))
        platform.setPointingDirection(
            self.lookMap[file['/science/LSAR/identification'].get(
                'lookDirection')[()].decode('utf-8')])
        platform.setPlanet(Planet(pname="Earth"))

        # We are not using this value anywhere. Let's fix it for now.
        platform.setAntennaLength(12.0)

    def _populateInstrument(self, file):
        instrument = self.frame.getInstrument()

        rangePixelSize = file['/science/LSAR/SLC/swaths/' + self.frequency +
                              '/slantRangeSpacing'][()]
        wvl = SPEED_OF_LIGHT / file['/science/LSAR/SLC/swaths/' +
                                    self.frequency +
                                    '/processedCenterFrequency'][()]
        instrument.setRadarWavelength(wvl)
        instrument.setPulseRepetitionFrequency(
            1.0 / file['/science/LSAR/SLC/swaths/zeroDopplerTimeSpacing'][()])
        rangePixelSize = file['/science/LSAR/SLC/swaths/' + self.frequency +
                              '/slantRangeSpacing'][()]
        instrument.setRangePixelSize(rangePixelSize)

        # Chrip slope and length only are used in the split spectrum workflow to compute the bandwidth.
        # Therefore fixing it to 1.0 won't breack anything
        Chirp_slope = 1.0
        rangeBandwidth = file['/science/LSAR/SLC/swaths/' + self.frequency +
                              '/processedRangeBandwidth'][()]
        Chirp_length = rangeBandwidth / Chirp_slope
        instrument.setPulseLength(Chirp_length)
        instrument.setChirpSlope(Chirp_slope)
        rangeSamplingFrequency = SPEED_OF_LIGHT / 2. / rangePixelSize
        instrument.setRangeSamplingRate(rangeSamplingFrequency)

        incangle = 0.0
        instrument.setIncidenceAngle(incangle)

    def _populateFrame(self, file):

        slantRange = file['/science/LSAR/SLC/swaths/' + self.frequency +
                          '/slantRange'][0]
        self.frame.setStartingRange(slantRange)

        referenceUTC = file['/science/LSAR/SLC/swaths/zeroDopplerTime'].attrs[
            'units'].decode('utf-8')
        referenceUTC = referenceUTC.replace('seconds since ', '')
        referenceUTC = datetime.datetime.strptime(referenceUTC,
                                                  '%Y-%m-%d %H:%M:%S')

        relStart = file['/science/LSAR/SLC/swaths/zeroDopplerTime'][0]
        relEnd = file['/science/LSAR/SLC/swaths/zeroDopplerTime'][-1]
        relMid = 0.5 * (relStart + relEnd)

        sensingStart = self._combineDateTime(referenceUTC, relStart)
        sensingStop = self._combineDateTime(referenceUTC, relEnd)
        sensingMid = self._combineDateTime(referenceUTC, relMid)

        self.frame.setPassDirection(
            file['/science/LSAR/identification'].get('orbitPassDirection')[(
            )].decode('utf-8'))
        self.frame.setOrbitNumber(
            file['/science/LSAR/identification'].get('trackNumber')[()])
        self.frame.setProcessingFacility('JPL')
        self.frame.setProcessingSoftwareVersion(
            file['/science/LSAR/SLC/metadata/processingInformation/algorithms']
            .get('ISCEVersion')[()].decode('utf-8'))
        self.frame.setPolarization(self.polarization)
        self.frame.setNumberOfLines(
            file['/science/LSAR/SLC/swaths/' + self.frequency + '/' +
                 self.polarization].shape[0])
        self.frame.setNumberOfSamples(
            file['/science/LSAR/SLC/swaths/' + self.frequency + '/' +
                 self.polarization].shape[1])
        self.frame.setSensingStart(sensingStart)
        self.frame.setSensingMid(sensingMid)
        self.frame.setSensingStop(sensingStop)

        rangePixelSize = self.frame.instrument.rangePixelSize
        farRange = slantRange + (self.frame.getNumberOfSamples() -
                                 1) * rangePixelSize
        self.frame.setFarRange(farRange)

    def _populateOrbit(self, file):
        orbit = self.frame.getOrbit()

        orbit.setReferenceFrame('ECR')
        orbit.setOrbitSource('Header')

        referenceUTC = file['/science/LSAR/SLC/swaths/zeroDopplerTime'].attrs[
            'units'].decode('utf-8')
        referenceUTC = referenceUTC.replace('seconds since ', '')
        t0 = datetime.datetime.strptime(referenceUTC, '%Y-%m-%d %H:%M:%S')
        t = file['/science/LSAR/SLC/metadata/orbit/time']
        position = file['/science/LSAR/SLC/metadata/orbit/position']
        velocity = file['/science/LSAR/SLC/metadata/orbit/velocity']

        for i in range(len(position)):
            vec = StateVector()
            dt = t0 + datetime.timedelta(seconds=t[i])
            vec.setTime(dt)
            vec.setPosition([position[i, 0], position[i, 1], position[i, 2]])
            vec.setVelocity([velocity[i, 0], velocity[i, 1], velocity[i, 2]])
            orbit.addStateVector(vec)

    def extractImage(self):

        import numpy as np
        import h5py

        self.parse()

        fid = h5py.File(self.hdf5, 'r')
        ds = fid['/science/LSAR/SLC/swaths/' + self.frequency + '/' +
                 self.polarization]
        nLines = ds.shape[0]

        with open(self.output, 'wb') as fout:
            for ii in range(nLines):
                ds[ii, :].astype(np.complex64).tofile(fout)

        fid.close()

        slcImage = isceobj.createSlcImage()
        slcImage.setFilename(self.output)
        slcImage.setXmin(0)
        slcImage.setXmax(self.frame.getNumberOfSamples())
        slcImage.setWidth(self.frame.getNumberOfSamples())
        slcImage.setAccessMode('r')
        slcImage.renderHdr()
        self.frame.setImage(slcImage)

    def _parseNanoSecondTimeStamp(self, timestamp):
        """
            Parse a date-time string with nanosecond precision and return a datetime object
        """
        dateTime, nanoSeconds = timestamp.decode('utf-8').split('.')
        microsec = float(nanoSeconds) * 1e-3
        dt = datetime.datetime.strptime(dateTime, '%Y-%m-%d %H:%M:%S')
        dt = dt + datetime.timedelta(microseconds=microsec)
        return dt

    def _combineDateTime(self, dobj, secsstr):
        '''Takes the date from dobj and time from secs to spit out a date time object.
        '''
        sec = float(secsstr)
        dt = datetime.timedelta(seconds=sec)
        return dobj + dt

    def extractDoppler(self):
        """
        Return the doppler centroid as defined in the HDF5 file.
        """

        import h5py
        from scipy.interpolate import UnivariateSpline
        import numpy as np

        h5 = h5py.File(self.hdf5, 'r')

        # extract the 2D LUT of Doppler and choose only one range line as the data duplicates for other range lines
        dop = h5['/science/LSAR/SLC/metadata/processingInformation/parameters/'
                 + self.frequency + '/dopplerCentroid'][0, :]
        rng = h5[
            '/science/LSAR/SLC/metadata/processingInformation/parameters/slantRange']

        # extract the slant range of the image grid
        imgRng = h5['/science/LSAR/SLC/swaths/' + self.frequency +
                    '/slantRange']

        # use only part of the slant range that closely covers image ranges and ignore the rest
        ind0 = np.argmin(np.abs(rng - imgRng[0])) - 1
        ind0 = np.max([0, ind0])
        ind1 = np.argmin(np.abs(rng - imgRng[-1])) + 1
        ind1 = np.min([ind1, rng.shape[0]])

        dop = dop[ind0:ind1]
        rng = rng[ind0:ind1]

        f = UnivariateSpline(rng, dop)
        imgDop = f(imgRng)

        dr = imgRng[1] - imgRng[0]
        pix = (imgRng - imgRng[0]) / dr
        fit = np.polyfit(pix, imgDop, 41)

        self.frame._dopplerVsPixel = list(fit[::-1])

        ####insarApp style (doesn't get used for stripmapApp). A fixed Doppler at the middle of the scene
        quadratic = {}
        quadratic['a'] = imgDop[int(
            imgDop.shape[0] /
            2)] / self.frame.getInstrument().getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.

        return quadratic
Esempio n. 8
0
class Radarsat1(Component):
    """
        Code to read CEOSFormat leader files for Radarsat-1 SAR data.  The tables used to create
        this parser are based on document number ER-IS-EPO-GS-5902.1 from the European
        Space Agency.
    """
    auxLength = 50

    def __init__(self):
        Component.__init__(self)
        self._leaderFile = None
        self._imageFile = None
        self._parFile = None
        self.output = None
        self.imageFile = None
        self.leaderFile = None

        #####Soecific doppler functions for RSAT1
        self.doppler_ref_range = None
        self.doppler_ref_azi = None
        self.doppler_predict = None
        self.doppler_DAR = None
        self.doppler_coeff = None

        self.frame = Frame()
        self.frame.configure()

        self.constants = {'polarization': 'HH', 'antennaLength': 15}

        self.descriptionOfVariables = {}
        self.dictionaryOfVariables = {
            'LEADERFILE': ['self._leaderFile', 'str', 'mandatory'],
            'IMAGEFILE': ['self._imageFile', 'str', 'mandatory'],
            'PARFILE': ['self._parFile', 'str', 'optional'],
            'OUTPUT': ['self.output', 'str', 'optional']
        }

    def getFrame(self):
        return self.frame

    def parse(self):
        self.leaderFile = LeaderFile(self, file=self._leaderFile)
        self.leaderFile.parse()

        self.imageFile = ImageFile(self, file=self._imageFile)
        self.imageFile.parse()

        self.populateMetadata()

    def populateMetadata(self):
        """
            Create the appropriate metadata objects from our CEOSFormat metadata
        """
        frame = self._decodeSceneReferenceNumber(
            self.leaderFile.sceneHeaderRecord.
            metadata['Scene reference number'])
        try:
            rangePixelSize = Const.c / (2 * self.leaderFile.sceneHeaderRecord.
                                        metadata['Range sampling rate'] * 1e6)
        except ZeroDivisionError:
            rangePixelSize = 0

        ins = self.frame.getInstrument()
        platform = ins.getPlatform()
        platform.setMission(self.leaderFile.sceneHeaderRecord.
                            metadata['Sensor platform mission identifier'])
        platform.setAntennaLength(self.constants['antennaLength'])
        platform.setPointingDirection(-1)
        platform.setPlanet(Planet('Earth'))

        ins.setRadarWavelength(
            self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength'])
        ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord.
                              metadata['Incidence angle at scene centre'])
        ##RSAT-1 does not have PRF for raw data in leader file.
        #        self.frame.getInstrument().setPulseRepetitionFrequency(self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency'])
        ins.setRangePixelSize(rangePixelSize)
        ins.setPulseLength(
            self.leaderFile.sceneHeaderRecord.metadata['Range pulse length'] *
            1e-6)
        chirpPulseBandwidth = 15.50829e6  # Is this really not in the CEOSFormat Header?
        ins.setChirpSlope(
            chirpPulseBandwidth /
            (self.leaderFile.sceneHeaderRecord.metadata['Range pulse length'] *
             1e-6))
        ins.setInPhaseValue(7.5)
        ins.setQuadratureValue(7.5)

        self.frame.setFrameNumber(frame)
        self.frame.setOrbitNumber(
            self.leaderFile.sceneHeaderRecord.metadata['Orbit number'])
        self.frame.setProcessingFacility(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing facility identifier'])
        self.frame.setProcessingSystem(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing system identifier'])
        self.frame.setProcessingSoftwareVersion(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing version identifier'])
        self.frame.setPolarization(self.constants['polarization'])
        self.frame.setNumberOfLines(
            self.imageFile.imageFDR.metadata['Number of lines per data set'])
        self.frame.setNumberOfSamples(
            self.imageFile.imageFDR.
            metadata['Number of pixels per line per SAR channel'])

        self.frame.getOrbit().setOrbitSource('Header')
        self.frame.getOrbit().setOrbitQuality(
            self.leaderFile.platformPositionRecord.
            metadata['Orbital elements designator'])
        t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.
                               metadata['Year of data point'],
                               month=self.leaderFile.platformPositionRecord.
                               metadata['Month of data point'],
                               day=self.leaderFile.platformPositionRecord.
                               metadata['Day of data point'])
        t0 = t0 + datetime.timedelta(
            seconds=self.leaderFile.platformPositionRecord.
            metadata['Seconds of day'])

        #####Read in orbit in inertial coordinates
        orb = Orbit()
        for i in range(self.leaderFile.platformPositionRecord.
                       metadata['Number of data points']):
            vec = StateVector()
            t = t0 + datetime.timedelta(
                seconds=(i * self.leaderFile.platformPositionRecord.
                         metadata['Time interval between DATA points']))
            vec.setTime(t)
            dataPoints = self.leaderFile.platformPositionRecord.metadata[
                'Positional Data Points'][i]
            vec.setPosition([
                dataPoints['Position vector X'],
                dataPoints['Position vector Y'],
                dataPoints['Position vector Z']
            ])
            vec.setVelocity([
                dataPoints['Velocity vector X'] / 1000.,
                dataPoints['Velocity vector Y'] / 1000.,
                dataPoints['Velocity vector Z'] / 1000.
            ])
            orb.addStateVector(vec)

        #####Convert orbits from ECI to ECEF frame.
        convOrb = ECI2ECEF(orb, eci='ECI_TOD')
        wgsorb = convOrb.convert()

        orb = self.frame.getOrbit()

        for sv in wgsorb:
            orb.addStateVector(sv)

        self.parseParFile()

    def extractImage(self):
        import isceobj
        if (self.imageFile is None) or (self.leaderFile is None):
            self.parse()

        try:
            out = open(self.output, 'wb')
        except IOError as strerr:
            self.logger.error("IOError: %s" % strerr)

        self.imageFile.extractImage(output=out)
        out.close()

        ####RSAT1 is weird. Contains all useful info in RAW data and not leader.
        ins = self.frame.getInstrument()
        ins.setPulseRepetitionFrequency(self.imageFile.prf)
        ins.setPulseLength(self.imageFile.pulseLength)
        ins.setRangeSamplingRate(self.imageFile.rangeSamplingRate)
        ins.setRangePixelSize(Const.c / (2 * self.imageFile.rangeSamplingRate))
        ins.setChirpSlope(self.imageFile.chirpSlope)

        ######
        self.frame.setSensingStart(self.imageFile.sensingStart)
        sensingStop = self.imageFile.sensingStart + datetime.timedelta(
            seconds=((self.frame.getNumberOfLines() - 1) / self.imageFile.prf))
        sensingMid = self.imageFile.sensingStart + datetime.timedelta(
            seconds=0.5 *
            (sensingStop - self.imageFile.sensingStart).total_seconds())
        self.frame.setSensingStop(sensingStop)
        self.frame.setSensingMid(sensingMid)
        self.frame.setNumberOfSamples(self.imageFile.width)
        self.frame.setStartingRange(self.imageFile.startingRange)
        farRange = self.imageFile.startingRange + ins.getRangePixelSize(
        ) * self.imageFile.width * 0.5
        self.frame.setFarRange(farRange)

        rawImage = isceobj.createRawImage()
        rawImage.setByteOrder('l')
        rawImage.setAccessMode('read')
        rawImage.setFilename(self.output)
        rawImage.setWidth(self.imageFile.width)
        rawImage.setXmin(0)
        rawImage.setXmax(self.imageFile.width)
        rawImage.renderHdr()
        self.frame.setImage(rawImage)

    def parseParFile(self):
        '''Parse the par file if any is available.'''
        if self._parFile not in (None, ''):
            par = ParFile(self._parFile)

            doppinfo = par['prep_block']['sensor']['beam'][
                'DopplerCentroidParameters']
            #######Selectively update some values.
            #######Currently used only for doppler centroids.

            self.doppler_ref_range = float(doppinfo['reference_range'])
            self.doppler_ref_azi = datetime.datetime.strptime(
                doppinfo['reference_date'], '%Y%m%d%H%M%S%f')
            self.doppler_predict = float(doppinfo['Predict_doppler'])
            self.doppler_DAR = float(doppinfo['DAR_doppler'])

            coeff = doppinfo['doppler_centroid_coefficients']
            rngOrder = int(coeff['number_of_coefficients_first_dimension'])
            azOrder = int(coeff['number_of_coefficients_second_dimension'])

            self.doppler_coeff = Polynomial(rangeOrder=rngOrder,
                                            azimuthOrder=azOrder)
            self.doppler_coeff.setMeanRange(self.doppler_ref_range)
            self.doppler_coeff.setMeanAzimuth(
                secondsSinceMidnight(self.doppler_ref_azi))

            for ii in range(azOrder):
                for jj in range(rngOrder):
                    key = 'a%d%d' % (ii, jj)
                    val = float(coeff[key])
                    self.doppler_coeff.setCoeff(ii, jj, val)

    def extractDoppler(self):
        '''
        Evaluate the doppler polynomial and return the average value for now.
        '''

        rmin = self.frame.getStartingRange()
        rmax = self.frame.getFarRange()
        rmid = 0.5 * (rmin + rmax)

        azmid = secondsSinceMidnight(self.frame.getSensingMid())

        print(rmid, self.doppler_coeff.getMeanRange())
        print(azmid, self.doppler_coeff.getMeanAzimuth())

        if self.doppler_coeff is None:
            raise Exception(
                'ASF PARFILE was not provided. Cannot determine default doppler.'
            )

        dopav = self.doppler_coeff(azmid, rmid)
        prf = self.frame.getInstrument().getPulseRepetitionFrequency()
        quadratic = {}
        quadratic['a'] = dopav / prf
        quadratic['b'] = 0.
        quadratic['c'] = 0.
        return quadratic

    def _decodeSceneReferenceNumber(self, referenceNumber):
        return referenceNumber
Esempio n. 9
0
class Generic(Component):
    """
    A class to parse generic SAR data stored in the HDF5 format
    """

    logging_name = 'isce.sensor.Generic'

    def __init__(self):
        super(Generic, self).__init__()
        self._hdf5File = None
        self.output = None
        self.frame = Frame()
        self.frame.configure()

        self.logger = logging.getLogger('isce.sensor.Generic')

        self.descriptionOfVariables = {}
        self.dictionaryOfVariables = {
            'HDF5': ['self._hdf5File', 'str', 'mandatory'],
            'OUTPUT': ['self.output', 'str', 'optional']
        }
        return None

    def getFrame(self):
        return self.frame

    def parse(self):
        try:
            fp = h5py.File(self._hdf5File, 'r')
        except Exception as strerror:
            self.logger.error("IOError: %s" % strerror)
            return

        self.populateMetadata(fp)
        fp.close()

    def populateMetadata(self, file):
        """
        Create the appropriate metadata objects from our HDF5 file
        """
        self._populatePlatform(file)
        self._populateInstrument(file)
        self._populateFrame(file)
        self._populateOrbit(file)

    def _populatePlatform(self, file):
        platform = self.frame.getInstrument().getPlatform()

        platform.setMission(file['Platform'].attrs['Mission'])
        platform.setPlanet(Planet(pname='Earth'))
        platform.setAntennaLength(file['Platform'].attrs['Antenna Length'])

    def _populateInstrument(self, file):
        instrument = self.frame.getInstrument()

        instrument.setRadarWavelength(file['Instrument'].attrs['Wavelength'])
        instrument.setPulseRepetitionFrequency(
            file['Instrument'].attrs['Pulse Repetition Frequency'])
        instrument.setRangePixelSize(
            file['Instrument'].attrs['Range Pixel Size'])
        instrument.setPulseLength(file['Instrument'].attrs['Pulse Length'])
        instrument.setChirpSlope(file['Instrument'].attrs['Chirp Slope'])
        instrument.setRangeSamplingRate(
            file['Instrument'].attrs['Range Sampling Frequency'])
        instrument.setInPhaseValue(file['Frame'].attrs['In Phase Bias'])
        instrument.setQuadratureValue(file['Frame'].attrs['Quadrature Bias'])

    def _populateFrame(self, file):
        size = file['Frame'].shape
        start = DTU.parseIsoDateTime(file['Frame'].attrs['Sensing Start'])
        stop = DTU.parseIsoDateTime(file['Frame'].attrs['Sensing Stop'])
        deltaT = DTU.timeDeltaToSeconds(stop - start)
        mid = start + datetime.timedelta(microseconds=int(deltaT / 2.0 * 1e6))
        startingRange = file['Frame'].attrs['Starting Range']
        rangePixelSize = file['Instrument'].attrs['Range Pixel Size']
        farRange = startingRange + size[1] * rangePixelSize

        self.frame.setStartingRange(file['Frame'].attrs['Starting Range'])
        self.frame.setFarRange(farRange)
        self.frame.setNumberOfLines(size[0])
        self.frame.setNumberOfSamples(2 * size[1])
        self.frame.setSensingStart(start)
        self.frame.setSensingMid(mid)
        self.frame.setSensingStop(stop)

    def _populateOrbit(self, file):
        orbit = self.frame.getOrbit()

        orbit.setReferenceFrame('ECR')
        orbit.setOrbitSource(file['Orbit'].attrs['Source'])

        for i in range(len(file['Orbit']['Time'])):
            vec = StateVector()
            time = DTU.parseIsoDateTime(file['Orbit']['Time'][i])
            vec.setTime(time)
            vec.setPosition(list(file['Orbit']['Position'][i]))
            vec.setVelocity(list(file['Orbit']['Velocity'][i]))
            orbit.addStateVector(vec)

    def extractImage(self):
        try:
            file = h5py.File(self._hdf5File, 'r')
        except Exception as strerror:
            self.logger.error("IOError: %s" % strerror)
            return
        size = file['Frame'].shape
        dtype = self._translateDataType(file['Frame'].attrs['Image Type'])
        length = size[0]
        width = size[1]
        data = numpy.memmap(self.output,
                            dtype=dtype,
                            mode='w+',
                            shape=(length, width, 2))
        data[:, :, :] = file['Frame'][:, :, :]
        del data

        rawImage = isceobj.createRawImage()
        rawImage.setByteOrder('l')
        rawImage.setAccessMode('r')
        rawImage.setFilename(self.output)
        rawImage.setWidth(2 * width)
        rawImage.setXmin(0)
        rawImage.setXmax(2 * width)
        self.frame.setImage(rawImage)
        self.populateMetadata(file)

        file.close()

    def write(self, output, compression=None):
        """
        Given a frame object (appropriately populated) and an image, create
        an HDF5 from those objects.
        """
        if (not self.frame):
            self.logger.error("Frame not set")
            raise AttributeError("Frame not set")

        h5file = h5py.File(output, 'w')
        self._writeMetadata(h5file, compression)

    def _writeMetadata(self, h5file, compression=None):
        self._writePlatform(h5file)
        self._writeInstrument(h5file)
        self._writeFrame(h5file, compression)
        self._writeOrbit(h5file)

    def _writePlatform(self, h5file):
        platform = self.frame.getInstrument().getPlatform()
        if (not platform):
            self.logger.error("Platform not set")
            raise AttributeError("Platform not set")

        group = h5file.create_group('Platform')
        group.attrs['Mission'] = platform.getMission()
        group.attrs['Planet'] = platform.getPlanet().name
        group.attrs['Antenna Length'] = platform.getAntennaLength()

    def _writeInstrument(self, h5file):
        instrument = self.frame.getInstrument()
        if (not instrument):
            self.logger.error("Instrument not set")
            raise AttributeError("Instrument not set")

        group = h5file.create_group('Instrument')
        group.attrs['Wavelength'] = instrument.getRadarWavelength()
        group.attrs[
            'Pulse Repetition Frequency'] = instrument.getPulseRepetitionFrequency(
            )
        group.attrs['Range Pixel Size'] = instrument.getRangePixelSize()
        group.attrs['Pulse Length'] = instrument.getPulseLength()
        group.attrs['Chirp Slope'] = instrument.getChirpSlope()
        group.attrs[
            'Range Sampling Frequency'] = instrument.getRangeSamplingRate()
        group.attrs['In Phase Bias'] = instrument.getInPhaseValue()
        group.attrs['Quadrature Bias'] = instrument.getQuadratureValue()

    def _writeFrame(self, h5file, compression=None):
        group = self._writeImage(h5file, compression)
        group.attrs['Starting Range'] = self.frame.getStartingRange()
        group.attrs['Sensing Start'] = self.frame.getSensingStart().isoformat()
        group.attrs['Sensing Stop'] = self.frame.getSensingStop().isoformat()

    def _writeImage(self, h5file, compression=None):
        image = self.frame.getImage()
        if (not image):
            self.logger.error("Image not set")
            raise AttributeError("Image not set")
        filename = image.getFilename()
        length = image.getLength()
        width = image.getWidth()

        dtype = self._translateDataType(image.dataType)
        if (image.dataType == 'BYTE'):
            width = int(width / 2)

        self.logger.debug("Width: %s" % (width))
        self.logger.debug("Length: %s" % (length))
        data = numpy.memmap(filename,
                            dtype=dtype,
                            mode='r',
                            shape=(length, 2 * width))
        dset = h5file.create_dataset("Frame", (length, width, 2),
                                     dtype=dtype,
                                     compression=compression)
        dset.attrs['Image Type'] = image.dataType
        dset[:, :, 0] = data[:, ::2]
        dset[:, :, 1] = data[:, 1::2]
        del data

        return dset

    def _writeOrbit(self, h5file):
        # Add orbit information
        (time, position, velocity) = self._orbitToArray()
        group = h5file.create_group("Orbit")
        group.attrs['Source'] = self.frame.getOrbit().getOrbitSource()
        group.attrs['Reference Frame'] = self.frame.getOrbit(
        ).getReferenceFrame()
        timedset = h5file.create_dataset("Orbit/Time",
                                         time.shape,
                                         dtype=time.dtype)
        posdset = h5file.create_dataset("Orbit/Position",
                                        position.shape,
                                        dtype=numpy.float64)
        veldset = h5file.create_dataset("Orbit/Velocity",
                                        velocity.shape,
                                        dtype=numpy.float64)
        timedset[...] = time
        posdset[...] = position
        veldset[...] = velocity

    def _orbitToArray(self):
        orbit = self.frame.getOrbit()
        if (not orbit):
            self.logger.error("Orbit not set")
            raise AttributeError("Orbit not set")

        time = []
        position = []
        velocity = []
        for sv in orbit:
            timeString = sv.getTime().isoformat()
            time.append(timeString)
            position.append(sv.getPosition())
            velocity.append(sv.getVelocity())

        return numpy.array(time), numpy.array(position), numpy.array(velocity)

    def _translateDataType(self, imageType):
        dtype = ''
        if (imageType == 'BYTE'):
            dtype = 'int8'
        elif (imageType == 'CFLOAT'):
            dtype = 'float32'
        elif (imageType == 'SHORT'):
            dtype = 'int16'
        else:
            self.logger.error("Unknown data type %s" % (imageType))
            raise ValueError("Unknown data type %s" % (imageType))

        return dtype
Esempio n. 10
0
class SAOCOM_SLC(Sensor):

    parameter_list = (IMAGEFILE,
                      XEMTFILE,
                      XMLFILE)           + Sensor.parameter_list

    """
        A Class for parsing SAOCOM instrument and imagery files
    """

    family = 'saocom_slc'

    def __init__(self,family='',name=''):
        super(SAOCOM_SLC, self).__init__(family if family else  self.__class__.family, name=name)
        self._imageFile = None
        self._xemtFileParser = None
        self._xmlFileParser = None
        self._instrumentFileData = None
        self._imageryFileData = None
        self.dopplerRangeTime = None
        self.rangeRefTime = None
        self.azimuthRefTime = None
        self.rangeFirstTime = None
        self.rangeLastTime = None
        self.logger = logging.getLogger("isce.sensor.SAOCOM_SLC")
        self.frame = None
        self.frameList = []
        
        self.lookMap = {'RIGHT': -1,
                        'LEFT': 1}
        self.nearIncidenceAngle = {'S1DP': 20.7, 
        'S2DP': 24.9, 
        'S3DP': 29.1, 
        'S4DP': 33.7, 
        'S5DP': 38.2, 
        'S6DP': 41.3, 
        'S7DP': 44.6, 
        'S8DP': 47.2, 
        'S9DP': 48.8, 
        'S1QP': 17.6, 
        'S2QP': 19.5, 
        'S3QP': 21.4, 
        'S4QP': 23.2, 
        'S5QP': 25.3, 
        'S6QP': 27.2, 
        'S7QP': 29.6, 
        'S8QP': 31.2, 
        'S9QP': 33.0, 
        'S10QP': 34.6}
        self.farIncidenceAngle = {'S1DP': 25.0, 
        'S2DP': 29.2, 
        'S3DP': 33.8, 
        'S4DP': 38.3, 
        'S5DP': 41.3, 
        'S6DP': 44.5, 
        'S7DP': 47.1, 
        'S8DP': 48.7, 
        'S9DP': 50.2, 
        'S1QP': 19.6, 
        'S2QP': 21.5, 
        'S3QP': 23.3, 
        'S4QP': 25.4, 
        'S5QP': 27.3, 
        'S6QP': 29.6, 
        'S7QP': 31.2, 
        'S8QP': 33.0, 
        'S9QP': 34.6, 
        'S10QP': 35.5}
        
    def parse(self):
        """
            Parse both imagery and instrument files and create
            objects representing the platform, instrument and scene
        """

        self.frame = Frame()
        self.frame.configure()
        self._xemtFileParser = XEMTFile(fileName=self.xemtFile)
        self._xemtFileParser.parse()
        self._xmlFileParser = XMLFile(fileName=self.xmlFile)
        self._xmlFileParser.parse()
        self.populateMetadata()

    def populateMetadata(self):
        self._populatePlatform()
        self._populateInstrument()
        self._populateFrame()
        self._populateOrbit()
        self._populateExtras()
        
    def _populatePlatform(self):
        """Populate the platform object with metadata"""
        platform = self.frame.getInstrument().getPlatform()
        
        # Populate the Platform and Scene objects
        platform.setMission(self._xmlFileParser.sensorName)
        platform.setPointingDirection(self.lookMap[self._xmlFileParser.sideLooking])
        platform.setAntennaLength(9.968)
        platform.setPlanet(Planet(pname="Earth"))
        
    def _populateInstrument(self):
        """Populate the instrument object with metadata"""
        instrument = self.frame.getInstrument()
        
        rangePixelSize = self._xmlFileParser.PSRng
        azimuthPixelSize = self._xmlFileParser.PSAz
        radarWavelength = Const.c/float(self._xmlFileParser.fc_hz)
        instrument.setRadarWavelength(radarWavelength)
        instrument.setPulseRepetitionFrequency(self._xmlFileParser.prf)
        instrument.setRangePixelSize(rangePixelSize)
        instrument.setAzimuthPixelSize(azimuthPixelSize)
        instrument.setPulseLength(self._xmlFileParser.pulseLength)
        instrument.setChirpSlope(float(self._xmlFileParser.pulseBandwidth)/float(self._xmlFileParser.pulseLength))

        instrument.setRangeSamplingRate(self._xmlFileParser.frg)

        incAngle = 0.5*(self.nearIncidenceAngle[self._xemtFileParser.beamID] + self.farIncidenceAngle[self._xemtFileParser.beamID])
        instrument.setIncidenceAngle(incAngle)
        
    def _populateFrame(self):
        """Populate the scene object with metadata"""
        
        rft = self._xmlFileParser.rangeStartTime
        slantRange = float(rft)*Const.c/2.0
        self.frame.setStartingRange(slantRange)

        sensingStart = self._parseNanoSecondTimeStamp(self._xmlFileParser.azimuthStartTime)
        sensingTime = self._xmlFileParser.lines/self._xmlFileParser.prf
        sensingStop = sensingStart + datetime.timedelta(seconds=sensingTime)
        sensingMid = sensingStart + datetime.timedelta(seconds=0.5*sensingTime)

        self.frame.setPassDirection(self._xmlFileParser.orbitDirection)
        self.frame.setProcessingFacility(self._xemtFileParser.facilityID)
        self.frame.setProcessingSoftwareVersion(self._xemtFileParser.softVersion)
        self.frame.setPolarization(self._xmlFileParser.polarization)
        self.frame.setNumberOfLines(self._xmlFileParser.lines)
        self.frame.setNumberOfSamples(self._xmlFileParser.samples)
        self.frame.setSensingStart(sensingStart)
        self.frame.setSensingMid(sensingMid)
        self.frame.setSensingStop(sensingStop)

        rangePixelSize = self.frame.getInstrument().getRangePixelSize()
        farRange = slantRange +  (self.frame.getNumberOfSamples()-1)*rangePixelSize
        self.frame.setFarRange(farRange)
        
    def _populateOrbit(self):
        orbit = self.frame.getOrbit()
        orbit.setReferenceFrame('ECR')
        orbit.setOrbitSource('Header')
        t0 = self._parseNanoSecondTimeStamp(self._xmlFileParser.orbitStartTime)
        t = np.arange(self._xmlFileParser.numberSV)*self._xmlFileParser.deltaTimeSV
        position = self._xmlFileParser.orbitPositionXYZ
        velocity = self._xmlFileParser.orbitVelocityXYZ

        for i in range(0,self._xmlFileParser.numberSV):
            vec = StateVector()
            dt = t0 + datetime.timedelta(seconds=t[i])
            vec.setTime(dt)
            vec.setPosition([position[i*3],position[i*3+1],position[i*3+2]])
            vec.setVelocity([velocity[i*3],velocity[i*3+1],velocity[i*3+2]])
            orbit.addStateVector(vec)
            print("valor "+str(i)+": "+str(dt))
        
    def _populateExtras(self):
        from isceobj.Doppler.Doppler import Doppler
        
        self.dopplerRangeTime = self._xmlFileParser.dopRngTime
        self.rangeRefTime = self._xmlFileParser.trg
        self.rangeFirstTime = self._xmlFileParser.rangeStartTime
        
    def extractImage(self):
        """
        Exports GeoTiff to ISCE format.
        """
        from osgeo import gdal
        
        ds = gdal.Open(self._imageFileName)
        metadata = ds.GetMetadata()
        geoTs = ds.GetGeoTransform() #GeoTransform
        prj = ds.GetProjection() #Projection
        dataType = ds.GetRasterBand(1).DataType
        gcps = ds.GetGCPs()
        
        sds = ds.ReadAsArray()
        
        # Output raster array to ISCE file
        driver = gdal.GetDriverByName('ISCE')  
        export = driver.Create(self.output, ds.RasterXSize, ds.RasterYSize, 1, dataType)
        band = export.GetRasterBand(1)
        band.WriteArray(sds)
        export.SetGeoTransform(geoTs)
        export.SetMetadata(metadata)
        export.SetProjection(prj)
        export.SetGCPs(gcps,prj)
        band.FlushCache()
        export.FlushCache()        
        
        self.parse()
        slcImage = isceobj.createSlcImage()
        slcImage.setFilename(self.output)
        slcImage.setXmin(0)
        slcImage.setXmax(self.frame.getNumberOfSamples())
        slcImage.setWidth(self.frame.getNumberOfSamples())
        slcImage.setAccessMode('r')
        self.frame.setImage(slcImage)
        
    def _parseNanoSecondTimeStamp(self,timestamp):
        """
            Parse a date-time string with microsecond precision and return a datetime object
        """
        dateTime,decSeconds = timestamp.split('.')
        microsec = float("0."+decSeconds)*1e6
        dt = datetime.datetime.strptime(dateTime,'%d-%b-%Y %H:%M:%S')
        dt = dt + datetime.timedelta(microseconds=microsec)
        return dt

    def extractDoppler(self):
        """
        Return the doppler centroid.
        """
        quadratic = {}

        r0 = self.frame.getStartingRange()
        dr = self.frame.instrument.getRangePixelSize()
        width = self.frame.getNumberOfSamples()
        
        midr = r0 + (width/2.0) * dr
        midtime = 2 * midr/ Const.c - self.rangeRefTime

        fd_mid = 0.0
        tpow = midtime
        
        for kk in self.dopplerRangeTime:
            fd_mid += kk * tpow
            tpow *= midtime

        ####For insarApp
        quadratic['a'] = fd_mid/self.frame.getInstrument().getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.

        ####For roiApp
        ####More accurate
        from isceobj.Util import Poly1D
        
        coeffs = self.dopplerRangeTime
        dr = self.frame.getInstrument().getRangePixelSize()
        rref = 0.5 * Const.c * self.rangeRefTime 
        r0 = self.frame.getStartingRange()
        norm = 0.5*Const.c/dr
        
        dcoeffs = []
        for ind, val in enumerate(coeffs):
            dcoeffs.append( val / (norm**ind))

        poly = Poly1D.Poly1D()
        poly.initPoly(order=len(coeffs)-1)
        poly.setMean( (rref - r0)/dr - 1.0)
        poly.setCoeffs(dcoeffs)

        pix = np.linspace(0, self.frame.getNumberOfSamples(), num=len(coeffs)+1)
        evals = poly(pix)
        fit = np.polyfit(pix,evals, len(coeffs)-1)
        self.frame._dopplerVsPixel = list(fit[::-1])
        print('Doppler Fit: ', fit[::-1])
        
        return quadratic
Esempio n. 11
0
class ALOS_SLC(Sensor):
    """
        Code to read CEOSFormat leader files for ALOS SLC data.
    """

    parameter_list = (WAVELENGTH,
                      LEADERFILE,
                      IMAGEFILE) + Sensor.parameter_list
    family = 'alos_slc'
    logging_name = 'isce.sensor.ALOS_SLC'

    #Orbital Elements (Quality) Designator
    #ALOS-2/PALSAR-2 Level 1.1/1.5/2.1/3.1 CEOS SAR Product Format Description
    #PALSAR-2_xx_Format_CEOS_E_r.pdf
    orbitElementsDesignator = {'0': 'preliminary',
                               '1': 'decision',
                               '2': 'high precision'}

    def __init__(self, name=''):
        super().__init__(family=self.__class__.family, name=name)
        self.imageFile = None
        self.leaderFile = None

        # Specific doppler functions for ALOS
        self.doppler_coeff = None
        self.azfmrate_coeff = None
        self.lineDirection = None
        self.pixelDirection = None

        self.frame = Frame()
        self.frame.configure()

        self.constants = {'antennaLength': 15}

    def getFrame(self):
        return self.frame

    def parse(self):
        self.leaderFile = LeaderFile(self, file=self._leaderFile)
        self.leaderFile.parse()

        self.imageFile = ImageFile(self, file=self._imageFile)
        self.imageFile.parse()
        self.populateMetadata()
        self._populateExtras()

    def populateMetadata(self):
        """
            Create the appropriate metadata objects from our CEOSFormat metadata
        """
        frame = self._decodeSceneReferenceNumber(self.leaderFile.sceneHeaderRecord.metadata['Scene reference number'])

        fsamplookup = self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate in MHz']*1.0e6

        rangePixelSize = Const.c/(2*fsamplookup)

        ins = self.frame.getInstrument()
        platform = ins.getPlatform()
        platform.setMission(self.leaderFile.sceneHeaderRecord.metadata['Sensor platform mission identifier'])
        platform.setAntennaLength(self.constants['antennaLength'])
        platform.setPointingDirection(1)
        platform.setPlanet(Planet(pname='Earth'))

        if self.wavelength:
            ins.setRadarWavelength(float(self.wavelength))
        else:
            ins.setRadarWavelength(self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength'])

        ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord.metadata['Incidence angle at scene centre'])
        self.frame.getInstrument().setPulseRepetitionFrequency(self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency in mHz']*1.0e-3)
        ins.setRangePixelSize(rangePixelSize)
        ins.setRangeSamplingRate(fsamplookup)
        ins.setPulseLength(self.leaderFile.sceneHeaderRecord.metadata['Range pulse length in microsec']*1.0e-6)
        chirpSlope = self.leaderFile.sceneHeaderRecord.metadata['Nominal range pulse (chirp) amplitude coefficient linear term']
        chirpPulseBandwidth = abs(chirpSlope * self.leaderFile.sceneHeaderRecord.metadata['Range pulse length in microsec']*1.0e-6)
        ins.setChirpSlope(chirpSlope)
        ins.setInPhaseValue(7.5)
        ins.setQuadratureValue(7.5)

        self.lineDirection = self.leaderFile.sceneHeaderRecord.metadata['Time direction indicator along line direction'].strip()
        self.pixelDirection =  self.leaderFile.sceneHeaderRecord.metadata['Time direction indicator along pixel direction'].strip()

        ######ALOS includes this information in clock angle
        clockAngle = self.leaderFile.sceneHeaderRecord.metadata['Sensor clock angle']
        if clockAngle == 90.0:
            platform.setPointingDirection(-1)
        elif clockAngle == -90.0:
            platform.setPointingDirection(1)
        else:
            raise Exception('Unknown look side. Clock Angle = {0}'.format(clockAngle))

        self.frame.setFrameNumber(frame)
        self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number'])
        self.frame.setProcessingFacility(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier'])
        self.frame.setProcessingSystem(self.leaderFile.sceneHeaderRecord.metadata['Processing system identifier'])
        self.frame.setProcessingSoftwareVersion(self.leaderFile.sceneHeaderRecord.metadata['Processing version identifier'])
        self.frame.setNumberOfLines(self.imageFile.imageFDR.metadata['Number of lines per data set'])
        self.frame.setNumberOfSamples(self.imageFile.imageFDR.metadata['Number of pixels per line per SAR channel'])
        self.frame.instrument.setAzimuthPixelSize(self.leaderFile.dataQualitySummaryRecord.metadata['Azimuth resolution'])
        
        ######
        orb = self.frame.getOrbit()

        orb.setOrbitSource('Header')
        orb.setOrbitQuality(
            self.orbitElementsDesignator[
                self.leaderFile.platformPositionRecord.metadata['Orbital elements designator']
            ]
        )
        t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.metadata['Year of data point'],
                               month=self.leaderFile.platformPositionRecord.metadata['Month of data point'],
                               day=self.leaderFile.platformPositionRecord.metadata['Day of data point'])
        t0 = t0 + datetime.timedelta(seconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day'])

        #####Read in orbit in inertial coordinates
        deltaT = self.leaderFile.platformPositionRecord.metadata['Time interval between data points']
        numPts = self.leaderFile.platformPositionRecord.metadata['Number of data points']


        orb = self.frame.getOrbit()
        for i in range(numPts):
            vec = StateVector()
            t = t0 + datetime.timedelta(seconds=i*deltaT)
            vec.setTime(t)

            dataPoints = self.leaderFile.platformPositionRecord.metadata['Positional Data Points'][i]
            pos = [dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z']]
            vel = [dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z']]
            vec.setPosition(pos)
            vec.setVelocity(vel)
            orb.addStateVector(vec)


        self.doppler_coeff = [self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid constant term'],
        self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid linear term'],
        self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid quadratic term']]


        self.azfmrate_coeff =  [self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency rate constant term'],
        self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency rate linear term'],
        self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency rate quadratic term']]

    def _populateExtras(self):
        dataset = self.leaderFile.radiometricRecord.metadata
        print("Record Number: %d" % (dataset["Record Number"]))
        print("First Record Subtype: %d" % (dataset["First Record Subtype"]))
        print("Record Type Code: %d" % (dataset["Record Type Code"]))
        print("Second Record Subtype: %d" % (dataset["Second Record Subtype"]))
        print("Third Record Subtype: %d" % (dataset["Third Record Subtype"]))
        print("Record Length: %d" % (dataset["Record Length"]))
        print("SAR channel indicator: %d" % (dataset["SAR channel indicator"]))
        print("Number of data sets: %d" % (dataset["Number of data sets"]))
        numPts = dataset['Number of data sets']
        for i in range(numPts):
            if i > 1:
                break
            print('Radiometric record field: %d' % (i+1))
            dataset = self.leaderFile.radiometricRecord.metadata[
                'Radiometric data sets'][i]
            DT11 = complex(dataset['Real part of DT 1,1'],
                           dataset['Imaginary part of DT 1,1'])
            DT12 = complex(dataset['Real part of DT 1,2'],
                           dataset['Imaginary part of DT 1,2'])
            DT21 = complex(dataset['Real part of DT 2,1'],
                           dataset['Imaginary part of DT 2,1'])
            DT22 = complex(dataset['Real part of DT 2,2'],
                           dataset['Imaginary part of DT 2,2'])
            DR11 = complex(dataset['Real part of DR 1,1'],
                           dataset['Imaginary part of DR 1,1'])
            DR12 = complex(dataset['Real part of DR 1,2'],
                           dataset['Imaginary part of DR 1,2'])
            DR21 = complex(dataset['Real part of DR 2,1'],
                           dataset['Imaginary part of DR 2,1'])
            DR22 = complex(dataset['Real part of DR 2,2'],
                           dataset['Imaginary part of DR 2,2'])
            print("Calibration factor [dB]: %f" %
                  (dataset["Calibration factor"]))
            print('Distortion matrix Trasmission [DT11, DT12, DT21, DT22]: '
                  '[%s, %s, %s, %s]' %
                  (str(DT11), str(DT12), str(DT21), str(DT22)))
            print('Distortion matrix Reception [DR11, DR12, DR21, DR22]: '
                  '[%s, %s, %s, %s]' %
                  (str(DR11), str(DR12), str(DR21), str(DR22)))
            self.transmit = Distortion(DT12, DT21, DT22)
            self.receive = Distortion(DR12, DR21, DR22)
            self.calibrationFactor = float(
                dataset['Calibration factor'])

    def extractImage(self):
        import isceobj
        if (self.imageFile is None) or (self.leaderFile is None):
            self.parse()

        try:
            out = open(self.output, 'wb')
        except IOError as strerr:
            self.logger.error("IOError: %s" % strerr)

        self.imageFile.extractImage(output=out)
        out.close()

        self.frame.setSensingStart(self.imageFile.sensingStart)
        self.frame.setSensingStop(self.imageFile.sensingStop)
        sensingMid = self.imageFile.sensingStart + datetime.timedelta(seconds = 0.5* (self.imageFile.sensingStop - self.imageFile.sensingStart).total_seconds())
        self.frame.setSensingMid(sensingMid)

        try:
            rngGate=  Const.c*0.5*self.leaderFile.sceneHeaderRecord.metadata['Range gate delay in microsec']*1e-6
        except:
            rngGate = None

        if (rngGate is None) or (rngGate == 0.0):
            rngGate = self.imageFile.nearRange

        self.frame.setStartingRange(rngGate)

        self.frame.getInstrument().setPulseRepetitionFrequency(self.imageFile.prf)

        pixelSize = self.frame.getInstrument().getRangePixelSize()
        farRange = self.imageFile.nearRange + (pixelSize-1) * self.imageFile.width
        self.frame.setFarRange(farRange)
        self.frame.setPolarization(self.imageFile.current_polarization)
        
        rawImage = isceobj.createSlcImage()
        rawImage.setByteOrder('l')
        rawImage.setAccessMode('read')
        rawImage.setFilename(self.output)
        rawImage.setWidth(self.imageFile.width)
        rawImage.setXmin(0)
        rawImage.setXmax(self.imageFile.width)
        rawImage.renderHdr()
        self.frame.setImage(rawImage)

        return


    def extractDoppler(self):
        '''
        Evaluate the doppler polynomial and return the average value for now.
        '''
        midwidth = self.frame.getNumberOfSamples() / 2.0
        dop = 0.0
        prod = 1.0
        for ind, kk in enumerate(self.doppler_coeff):
            dop += kk * prod
            prod *= midwidth

        print ('Average Doppler: {0}'.format(dop))

        ####For insarApp
        quadratic = {}
        quadratic['a'] = dop / self.frame.getInstrument().getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.


        ####For roiApp
        ####More accurate
        ####CEOS already provides function vs pixel
        self.frame._dopplerVsPixel = self.doppler_coeff
        return quadratic

    def _decodeSceneReferenceNumber(self,referenceNumber):
        return referenceNumber
Esempio n. 12
0
class ERS_SLC(Sensor):

    family = 'ers_slc'
    logging_name = 'isce.sensor.ers_slc'

    parameter_list = (IMAGEFILE,
                      LEADERFILE,
                      ORBIT_TYPE,
                      ORBIT_DIRECTORY,
                      ORBIT_FILE)      + Sensor.parameter_list

    @logged
    def __init__(self, name=''):
        super().__init__(family=self.__class__.family, name=name)

        self.frame = Frame()
        self.frame.configure()
        self.dopplerRangeTime = None

        # Constants are from
        # J. J. Mohr and S. N. Madsen. Geometric calibration of ERS satellite
        # SAR images. IEEE T. Geosci. Remote, 39(4):842-850, Apr. 2001.
        self.constants = {'polarization': 'VV',
                          'antennaLength': 10,
                          'lookDirection': 'RIGHT',
                          'chirpPulseBandwidth': 15.50829e6,
                          'rangeSamplingRate': 18.962468e6,
                          'delayTime':6.622e-6,
                          'iBias': 15.5,
                          'qBias': 15.5}
        return None

    def getFrame(self):
        return self.frame

    def parse(self):
        self.leaderFile = LeaderFile(file=self._leaderFile)
        self.leaderFile.parse()

        self.imageFile = ImageFile(self)
        self.imageFile.parse()

        self.populateMetadata()

    def populateMetadata(self):
        """
        Create the appropriate metadata objects from our CEOSFormat metadata
        """

        self._populatePlatform()
        self._populateInstrument()
        self._populateFrame()
        if (self._orbitType == 'ODR'):
            self._populateDelftOrbits()
        elif (self._orbitType == 'PRC'):
            self._populatePRCOrbits()
        elif (self._orbitType == 'PDS'):
            self._populatePDSOrbits()
        else:
            self._populateHeaderOrbit()

        self._populateDoppler()

    def _populatePlatform(self):
        """
        Populate the platform object with metadata
        """

        platform = self.frame.getInstrument().getPlatform()

        platform.setMission(self.leaderFile.sceneHeaderRecord.metadata[
            'Sensor platform mission identifier'])
        platform.setAntennaLength(self.constants['antennaLength'])
        platform.setPointingDirection(-1)
        platform.setPlanet(Planet(pname='Earth'))

    def _populateInstrument(self):
        """Populate the instrument object with metadata"""
        instrument = self.frame.getInstrument()
        prf = self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency']
        rangeSamplingRate = self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate']*1.0e6
        rangePixelSize = Const.c/(2.0*rangeSamplingRate)

        instrument.setRadarWavelength(
            self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength'])
        instrument.setIncidenceAngle(
            self.leaderFile.sceneHeaderRecord.metadata[
            'Incidence angle at scene centre'])
        instrument.setPulseRepetitionFrequency(prf)
        instrument.setRangeSamplingRate(rangeSamplingRate)
        instrument.setRangePixelSize(rangePixelSize)
        instrument.setPulseLength(self.leaderFile.sceneHeaderRecord.metadata[
            'Range pulse length']*1e-6)
        instrument.setChirpSlope(self.constants['chirpPulseBandwidth']/
            (self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']*
             1e-6))
        instrument.setInPhaseValue(self.constants['iBias'])
        instrument.setQuadratureValue(self.constants['qBias'])

    def _populateFrame(self):
        """Populate the scene object with metadata"""
        rangeSamplingRate = self.constants['rangeSamplingRate']
        rangePixelSize = Const.c/(2.0*rangeSamplingRate)
        pulseInterval = 1.0/self.frame.getInstrument().getPulseRepetitionFrequency()
        frame = self._decodeSceneReferenceNumber(
            self.leaderFile.sceneHeaderRecord.metadata[
            'Scene reference number'])

        prf = self.frame.instrument.getPulseRepetitionFrequency()
        tau0 = self.leaderFile.sceneHeaderRecord.metadata['Zero-doppler range time of first range pixel']*1.0e-3
        startingRange = tau0*Const.c/2.0
        farRange = startingRange + self.imageFile.width*rangePixelSize


        first_line_utc = datetime.datetime.strptime(self.leaderFile.sceneHeaderRecord.metadata['Zero-doppler azimuth time of first azimuth pixel'], "%d-%b-%Y %H:%M:%S.%f")
        mid_line_utc = first_line_utc + datetime.timedelta(seconds = (self.imageFile.length-1) * 0.5 / prf)

        last_line_utc = first_line_utc + datetime.timedelta(seconds = (self.imageFile.length-1)/prf)

        self.logger.debug("Frame UTC start, mid, end times:  %s %s %s" % (first_line_utc,mid_line_utc,last_line_utc))

        self.frame.setFrameNumber(frame)
        self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number'])
        self.frame.setStartingRange(startingRange)
        self.frame.setFarRange(farRange)
        self.frame.setProcessingFacility(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier'])
        self.frame.setProcessingSystem(self.leaderFile.sceneHeaderRecord.metadata['Processing system identifier'])
        self.frame.setProcessingSoftwareVersion(self.leaderFile.sceneHeaderRecord.metadata['Processing version identifier'])
        self.frame.setPolarization(self.constants['polarization'])
        self.frame.setNumberOfLines(self.imageFile.length)
        self.frame.setNumberOfSamples(self.imageFile.width)
        self.frame.setSensingStart(first_line_utc)
        self.frame.setSensingMid(mid_line_utc)
        self.frame.setSensingStop(last_line_utc)

    def _populateHeaderOrbit(self):
        """Populate an orbit object with the header orbits"""
        self.logger.info("Using Header Orbits")
        orbit = self.frame.getOrbit()

        orbit.setOrbitSource('Header')
        orbit.setOrbitQuality('Unknown')
        t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.metadata['Year of data point'],
                               month=self.leaderFile.platformPositionRecord.metadata['Month of data point'],
                               day=self.leaderFile.platformPositionRecord.metadata['Day of data point'])
        t0 = t0 + datetime.timedelta(microseconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day']*1e6)
        for i in range(self.leaderFile.platformPositionRecord.metadata['Number of data points']):
            vec = StateVector()
            deltaT = self.leaderFile.platformPositionRecord.metadata['Time interval between DATA points']
            t = t0 + datetime.timedelta(microseconds=i*deltaT*1e6)
            vec.setTime(t)
            dataPoints = self.leaderFile.platformPositionRecord.metadata['Positional Data Points'][i]
            vec.setPosition([dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z']])
            vec.setVelocity([dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z']])
            orbit.addStateVector(vec)

    def _populateDelftOrbits(self):
        """Populate an orbit object with the Delft orbits"""
        from isceobj.Orbit.ODR import ODR, Arclist
        self.logger.info("Using Delft Orbits")
        arclist = Arclist(os.path.join(self._orbitDir,'arclist'))
        arclist.parse()
        orbitFile = arclist.getOrbitFile(self.frame.getSensingStart())
        odr = ODR(file=os.path.join(self._orbitDir,orbitFile))


        startTimePreInterp = self.frame.getSensingStart() - datetime.timedelta(minutes=60)
        stopTimePreInterp = self.frame.getSensingStop() + datetime.timedelta(minutes=60)
        odr.parseHeader(startTimePreInterp,stopTimePreInterp)
        startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5)
        stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5)
        self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime))
        orbit = odr.trimOrbit(startTime,stopTime)
        self.frame.setOrbit(orbit)

    def _populatePRCOrbits(self):
        """Populate an orbit object the D-PAF PRC orbits"""
        from isceobj.Orbit.PRC import PRC, Arclist
        self.logger.info("Using PRC Orbits")
        arclist = Arclist(os.path.join(self._orbitDir,'arclist'))
        arclist.parse()
        orbitFile = arclist.getOrbitFile(self.frame.getSensingStart())
        self.logger.debug("Using file %s" % (orbitFile))
        prc = PRC(file=os.path.join(self._orbitDir,orbitFile))
        prc.parse()
        startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5)
        stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5)
        self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime))
        fullOrbit = prc.getOrbit()
        orbit = fullOrbit.trimOrbit(startTime,stopTime)
        self.frame.setOrbit(orbit)

    def _populatePDSOrbits(self):
        """
        Populate an orbit object using the ERS-2 PDS format
        """
        from isceobj.Orbit.PDS import PDS
        self.logger.info("Using PDS Orbits")
        pds = PDS(file=self._orbitFile)
        pds.parse()
        startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5)
        stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5)
        self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime))
        fullOrbit = pds.getOrbit()
        orbit = fullOrbit.trimOrbit(startTime,stopTime)
        self.frame.setOrbit(orbit)

    def _populateDoppler(self):
        '''
        Extract doppler from the CEOS file.
        '''

        prf = self.frame.instrument.getPulseRepetitionFrequency()

        #####ERS provides doppler as a function of slant range time in seconds
        d0 = self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid constant term']

        d1 = self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid linear term']

        d2 = self.leaderFile.sceneHeaderRecord.metadata['Cross track Doppler frequency centroid quadratic term']

        self.dopplerRangeTime = [d0, d1, d2]

        return

    def extractDoppler(self):

        width = self.frame.getNumberOfSamples()
        prf = self.frame.instrument.getPulseRepetitionFrequency()

        midtime = 0.5*width/self.frame.instrument.getRangeSamplingRate() 

        fd_mid = 0.0
        x = 1.0
        for ind, coeff in enumerate(self.dopplerRangeTime):
            fd_mid += coeff * x
            x *= midtime

        ####For insarApp
        quadratic = {}
        quadratic['a'] = fd_mid / prf
        quadratic['b'] = 0.0
        quadratic['c'] = 0.0


        ###For roiApp more accurate
        ####Convert stuff to pixel wise coefficients
        dr = self.frame.getInstrument().getRangePixelSize()
        norm = 0.5*Const.c/dr

        dcoeffs = []
        for ind, val in enumerate(self.dopplerRangeTime):
            dcoeffs.append( val / (norm**ind))


        self.frame._dopplerVsPixel = dcoeffs
        print('Doppler Fit: ', fit[::-1])

        return quadratic



    def extractImage(self):
        import array
        import math

        self.parse()
        try:
            out = open(self.output, 'wb')
        except:
            raise Exception('Cannot open output file: %s'%(self.output))

        self.imageFile.extractImage(output=out)
        out.close()

        rawImage = isceobj.createSlcImage()
        rawImage.setByteOrder('l')
        rawImage.setAccessMode('read')
        rawImage.setFilename(self.output)
        rawImage.setWidth(self.imageFile.width)
        rawImage.setXmin(0)
        rawImage.setXmax(self.imageFile.width)
        self.frame.setImage(rawImage)

        prf = self.frame.getInstrument().getPulseRepetitionFrequency()
        senStart = self.frame.getSensingStart()
        numPulses = int(math.ceil(DTU.timeDeltaToSeconds(self.frame.getSensingStop()-senStart)*prf))
        musec0 = (senStart.hour*3600 + senStart.minute*60 + senStart.second)*10**6 + senStart.microsecond
        maxMusec = (24*3600)*10**6#use it to check if we went across  a day. very rare
        day0 = (datetime.datetime(senStart.year,senStart.month,senStart.day) - datetime.datetime(senStart.year,1,1)).days + 1
        outputArray  = array.array('d',[0]*2*numPulses)
        self.frame.auxFile = self.output + '.aux'
        fp = open(self.frame.auxFile,'wb')
        j = -1
        for i1 in range(numPulses):
            j += 1
            musec = round((j/prf)*10**6) + musec0
            if musec >= maxMusec:
                day0 += 1
                musec0 = musec%maxMusec
                musec = musec0
                j = 0
            outputArray[2*i1] = day0
            outputArray[2*i1+1] = musec

        outputArray.tofile(fp)
        fp.close()


    def _decodeSceneReferenceNumber(self,referenceNumber):
        frameNumber = referenceNumber.split('=')
        if (len(frameNumber) > 2):
            frameNumber = frameNumber[2].strip()
        else:
            frameNumber = frameNumber[0]

        return frameNumber
class COSMO_SkyMed_SLC(Sensor):
    """
    A class representing a Level1Product meta data.
    Level1Product(hdf5=h5filename) will parse the hdf5
    file and produce an object with attributes for metadata.
    """
    parameter_list = (HDF5, ) + Sensor.parameter_list
    logging_name = 'isce.Sensor.COSMO_SkyMed_SLC'
    family = 'cosmo_skymed_slc'

    def __init__(self, family='', name=''):
        super(COSMO_SkyMed_SLC,
              self).__init__(family if family else self.__class__.family,
                             name=name)
        self.frame = Frame()
        self.frame.configure()
        # Some extra processing parameters unique to CSK SLC (currently)
        self.dopplerRangeTime = []
        self.dopplerAzimuthTime = []
        self.azimuthRefTime = None
        self.rangeRefTime = None
        self.rangeFirstTime = None
        self.rangeLastTime = None

        self.lookMap = {'RIGHT': -1, 'LEFT': 1}
        return

    def __getstate__(self):
        d = dict(self.__dict__)
        del d['logger']
        return d

    def __setstate__(self, d):
        self.__dict__.update(d)
        self.logger = logging.getLogger('isce.Sensor.COSMO_SkyMed_SLC')
        return

    def getFrame(self):
        return self.frame

    def parse(self):
        try:
            fp = h5py.File(self.hdf5, 'r')
        except Exception as strerr:
            self.logger.error("IOError: %s" % strerr)
            return None

        self.populateMetadata(fp)
        fp.close()

    def populateMetadata(self, file):
        """
            Populate our Metadata objects
        """

        self._populatePlatform(file)
        self._populateInstrument(file)
        self._populateFrame(file)
        self._populateOrbit(file)
        self._populateExtras(file)

    def _populatePlatform(self, file):
        platform = self.frame.getInstrument().getPlatform()

        platform.setMission(file.attrs['Satellite ID'])
        platform.setPointingDirection(
            self.lookMap[file.attrs['Look Side'].decode('utf-8')])
        platform.setPlanet(Planet(pname="Earth"))

        ####This is an approximation for spotlight mode
        ####In spotlight mode, antenna length changes with azimuth position
        platform.setAntennaLength(file.attrs['Antenna Length'])
        try:
            if file.attrs['Multi-Beam ID'].startswith('ES'):
                platform.setAntennaLength(
                    16000.0 / file['S01/SBI'].attrs['Line Time Interval'])
        except:
            pass

    def _populateInstrument(self, file):
        instrument = self.frame.getInstrument()

        #        rangePixelSize = Const.c/(2*file['S01'].attrs['Sampling Rate'])
        rangePixelSize = file['S01/SBI'].attrs['Column Spacing']
        instrument.setRadarWavelength(file.attrs['Radar Wavelength'])
        #        instrument.setPulseRepetitionFrequency(file['S01'].attrs['PRF'])
        instrument.setPulseRepetitionFrequency(
            1.0 / file['S01/SBI'].attrs['Line Time Interval'])
        instrument.setRangePixelSize(rangePixelSize)
        instrument.setPulseLength(file['S01'].attrs['Range Chirp Length'])
        instrument.setChirpSlope(file['S01'].attrs['Range Chirp Rate'])
        #        instrument.setRangeSamplingRate(file['S01'].attrs['Sampling Rate'])
        instrument.setRangeSamplingRate(
            1.0 / file['S01/SBI'].attrs['Column Time Interval'])

        incangle = 0.5 * (file['S01/SBI'].attrs['Far Incidence Angle'] +
                          file['S01/SBI'].attrs['Near Incidence Angle'])
        instrument.setIncidenceAngle(incangle)

    def _populateFrame(self, file):

        rft = file['S01/SBI'].attrs['Zero Doppler Range First Time']
        slantRange = rft * Const.c / 2.0
        self.frame.setStartingRange(slantRange)

        referenceUTC = self._parseNanoSecondTimeStamp(
            file.attrs['Reference UTC'])
        relStart = file['S01/SBI'].attrs['Zero Doppler Azimuth First Time']
        relEnd = file['S01/SBI'].attrs['Zero Doppler Azimuth Last Time']
        relMid = 0.5 * (relStart + relEnd)

        sensingStart = self._combineDateTime(referenceUTC, relStart)
        sensingStop = self._combineDateTime(referenceUTC, relEnd)
        sensingMid = self._combineDateTime(referenceUTC, relMid)

        self.frame.setPassDirection(file.attrs['Orbit Direction'])
        self.frame.setOrbitNumber(file.attrs['Orbit Number'])
        self.frame.setProcessingFacility(file.attrs['Processing Centre'])
        self.frame.setProcessingSoftwareVersion(
            file.attrs['L0 Software Version'])
        self.frame.setPolarization(file['S01'].attrs['Polarisation'])
        self.frame.setNumberOfLines(file['S01/SBI'].shape[0])
        self.frame.setNumberOfSamples(file['S01/SBI'].shape[1])
        self.frame.setSensingStart(sensingStart)
        self.frame.setSensingMid(sensingMid)
        self.frame.setSensingStop(sensingStop)

        rangePixelSize = self.frame.getInstrument().getRangePixelSize()
        farRange = slantRange + (self.frame.getNumberOfSamples() -
                                 1) * rangePixelSize
        self.frame.setFarRange(farRange)

    def _populateOrbit(self, file):
        orbit = self.frame.getOrbit()

        orbit.setReferenceFrame('ECR')
        orbit.setOrbitSource('Header')
        t0 = datetime.datetime.strptime(
            file.attrs['Reference UTC'].decode('utf-8'),
            '%Y-%m-%d %H:%M:%S.%f000')
        t = file.attrs['State Vectors Times']
        position = file.attrs['ECEF Satellite Position']
        velocity = file.attrs['ECEF Satellite Velocity']

        for i in range(len(position)):
            vec = StateVector()
            dt = t0 + datetime.timedelta(seconds=t[i])
            vec.setTime(dt)
            vec.setPosition([position[i, 0], position[i, 1], position[i, 2]])
            vec.setVelocity([velocity[i, 0], velocity[i, 1], velocity[i, 2]])
            orbit.addStateVector(vec)

    def _populateExtras(self, file):
        """
        Populate some of the extra fields unique to processing TSX data.
        In the future, other sensors may need this information as well,
        and a re-organization may be necessary.
        """
        from isceobj.Doppler.Doppler import Doppler

        self.dopplerRangeTime = file.attrs['Centroid vs Range Time Polynomial']
        self.dopplerAzimuthTime = file.attrs[
            'Centroid vs Azimuth Time Polynomial']
        self.rangeRefTime = file.attrs['Range Polynomial Reference Time']
        self.azimuthRefTime = file.attrs['Azimuth Polynomial Reference Time']
        self.rangeFirstTime = file['S01/SBI'].attrs[
            'Zero Doppler Range First Time']
        self.rangeLastTime = file['S01/SBI'].attrs[
            'Zero Doppler Range Last Time']

        # get Doppler rate information, vs. azimuth first EJF 2015/00/05
        # guessing that same scale applies as for Doppler centroid
        self.dopplerRateCoeffs = file.attrs[
            'Doppler Rate vs Azimuth Time Polynomial']

    def extractImage(self):
        import os
        from ctypes import cdll, c_char_p
        extract_csk = cdll.LoadLibrary(os.path.dirname(__file__) + '/csk.so')
        inFile_c = c_char_p(bytes(self.hdf5, 'utf-8'))
        outFile_c = c_char_p(bytes(self.output, 'utf-8'))

        extract_csk.extract_csk_slc(inFile_c, outFile_c)

        self.parse()
        slcImage = isceobj.createSlcImage()
        slcImage.setFilename(self.output)
        slcImage.setXmin(0)
        slcImage.setXmax(self.frame.getNumberOfSamples())
        slcImage.setWidth(self.frame.getNumberOfSamples())
        slcImage.setAccessMode('r')
        self.frame.setImage(slcImage)

    def _parseNanoSecondTimeStamp(self, timestamp):
        """
            Parse a date-time string with nanosecond precision and return a datetime object
        """
        dateTime, nanoSeconds = timestamp.decode('utf-8').split('.')
        microsec = float(nanoSeconds) * 1e-3
        dt = datetime.datetime.strptime(dateTime, '%Y-%m-%d %H:%M:%S')
        dt = dt + datetime.timedelta(microseconds=microsec)
        return dt

    def _combineDateTime(self, dobj, secsstr):
        '''Takes the date from dobj and time from secs to spit out a date time object.
        '''
        sec = float(secsstr)
        dt = datetime.timedelta(seconds=sec)
        return datetime.datetime.combine(dobj.date(), datetime.time(0, 0)) + dt

    def extractDoppler(self):
        """
        Return the doppler centroid as defined in the HDF5 file.
        """
        import numpy as np

        quadratic = {}
        midtime = (self.rangeLastTime +
                   self.rangeFirstTime) * 0.5 - self.rangeRefTime

        fd_mid = 0.0
        x = 1.0
        for ind, coeff in enumerate(self.dopplerRangeTime):
            fd_mid += coeff * x
            x *= midtime

        ####insarApp style
        quadratic['a'] = fd_mid / self.frame.getInstrument(
        ).getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.

        ####For roiApp more accurate
        ####Convert stuff to pixel wise coefficients
        from isceobj.Util import Poly1D

        coeffs = self.dopplerRangeTime
        dr = self.frame.getInstrument().getRangePixelSize()
        rref = 0.5 * Const.c * self.rangeRefTime
        r0 = self.frame.getStartingRange()
        norm = 0.5 * Const.c / dr

        dcoeffs = []
        for ind, val in enumerate(coeffs):
            dcoeffs.append(val / (norm**ind))

        poly = Poly1D.Poly1D()
        poly.initPoly(order=len(coeffs) - 1)
        poly.setMean((rref - r0) / dr - 1.0)
        poly.setCoeffs(dcoeffs)

        pix = np.linspace(0,
                          self.frame.getNumberOfSamples(),
                          num=len(coeffs) + 1)
        evals = poly(pix)
        fit = np.polyfit(pix, evals, len(coeffs) - 1)
        self.frame._dopplerVsPixel = list(fit[::-1])
        print('Doppler Fit: ', fit[::-1])

        #EMG - 20160420 This section was introduced in the populateMetadata method by EJF in r2022
        #Its pupose seems to be to set self.doppler_coeff and self.azfmrate_coeff, which don't seem
        #to be used anywhere in ISCE. Need to take time to understand the need for this and consult
        #with EJF.
        #
        ## save the Doppler centroid coefficients, converting units from .h5 file
        ## units in the file are quadratic coefficients in Hz, Hz/sec, and Hz/(sec^2)
        ## ISCE expects Hz, Hz/(range sample), Hz/(range sample)^2
        ## note that RS2 Doppler values are estimated at time dc.dopplerCentroidReferenceTime,
        ## so the values might need to be adjusted for ISCE usage
        ## adapted from RS2 version EJF 2015/09/05
        #        poly = self.frame._dopplerVsPixel
        #        rangeSamplingRate = self.frame.getInstrument().getPulseRepetitionFrequency()
        #        # need to convert units
        #        poly[1] = poly[1]/rangeSamplingRate
        #        poly[2] = poly[2]/rangeSamplingRate**2
        #        self.doppler_coeff = poly
        #
        ## similarly save Doppler azimuth fm rate values, converting units
        ## units in the file are quadratic coefficients in Hz, Hz/sec, and Hz/(sec^2)
        ## units are already converted below
        ## Guessing that ISCE expects Hz, Hz/(azimuth line), Hz/(azimuth line)^2
        ## note that RS2 Doppler values are estimated at time dc.dopplerRateReferenceTime,
        ## so the values might need to be adjusted for ISCE usage
        ## modified from RS2 version EJF 2015/09/05
        ## CSK Doppler azimuth FM rate not yet implemented in reading section, set to zero for now
        #
        #        fmpoly = self.dopplerRateCoeffs
        #        # don't need to convert units
        ##        fmpoly[1] = fmpoly[1]/rangeSamplingRate
        ##        fmpoly[2] = fmpoly[2]/rangeSamplingRate**2
        #        self.azfmrate_coeff = fmpoly
        #EMG - 20160420

        return quadratic
Esempio n. 14
0
class Radarsat2(Component):
    """
        A Class representing RadarSAT 2 data
    """
    def __init__(self):
        Component.__init__(self)        
        self.xml = None
        self.tiff = None
        self.output = None
        self.product = _Product()                                
        self.frame = Frame()
        self.frame.configure()
        
        self.descriptionOfVariables = {}
        self.dictionaryOfVariables = {'XML': ['self.xml','str','mandatory'],
                                      'TIFF': ['self.tiff','str','mandatory'],
                                      'OUTPUT': ['self.output','str','optional']}
        
                                               
    def getFrame(self):
        return self.frame
    
    def parse(self):
        try:
            fp = open(self.xml,'r')
        except IOError as strerr:
            print("IOError: %s" % strerr)
            return
        self._xml_root = ElementTree(file=fp).getroot()                     
        self.product.set_from_etnode(self._xml_root)
        self.populateMetadata()
        
        fp.close()
    
    def populateMetadata(self):
        """
            Create metadata objects from the metadata files
        """
        mission = self.product.sourceAttributes.satellite
        swath = self.product.sourceAttributes.radarParameters.beams
        frequency = self.product.sourceAttributes.radarParameters.radarCenterFrequency
        prf = self.product.sourceAttributes.radarParameters.prf        
        rangePixelSize = self.product.imageAttributes.rasterAttributes.sampledPixelSpacing
        rangeSamplingRate = Const.c/(2*rangePixelSize)        
        pulseLength = self.product.sourceAttributes.radarParameters.pulseLengths[0]
        pulseBandwidth = self.product.sourceAttributes.radarParameters.pulseBandwidths[0]
        polarization = self.product.sourceAttributes.radarParameters.polarizations
        lookSide = lookMap[self.product.sourceAttributes.radarParameters.antennaPointing.upper()]
        facility = self.product.imageGenerationParameters.generalProcessingInformation._processingFacility
        version = self.product.imageGenerationParameters.generalProcessingInformation.softwareVersion
        lines = self.product.imageAttributes.rasterAttributes.numberOfLines
        samples = self.product.imageAttributes.rasterAttributes.numberOfSamplesPerLine
        startingRange = self.product.imageGenerationParameters.slantRangeToGroundRange.slantRangeTimeToFirstRangeSample * (Const.c/2)
        incidenceAngle = (self.product.imageGenerationParameters.sarProcessingInformation.incidenceAngleNearRange + self.product.imageGenerationParameters.sarProcessingInformation.incidenceAngleFarRange)/2

        lineFlip =  (self.product.imageAttributes.rasterAttributes.lineTimeOrdering.upper() == 'DECREASING')

        if lineFlip:
            dataStopTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeFirstLine
            dataStartTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeLastLine
        else:
            dataStartTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeFirstLine
            dataStopTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeLastLine

        passDirection = self.product.sourceAttributes.orbitAndAttitude.orbitInformation.passDirection
        height = self.product.imageGenerationParameters.sarProcessingInformation._satelliteHeight

        ####Populate platform
        platform = self.frame.getInstrument().getPlatform()
        platform.setPlanet(Planet("Earth"))
        platform.setMission(mission)
        platform.setPointingDirection(lookSide)
        platform.setAntennaLength(15.0)

        ####Populate instrument
        instrument = self.frame.getInstrument()
        instrument.setRadarFrequency(frequency)
        instrument.setPulseRepetitionFrequency(prf)
        instrument.setPulseLength(pulseLength)
        instrument.setChirpSlope(pulseBandwidth/pulseLength)
        instrument.setIncidenceAngle(incidenceAngle)
        #self.frame.getInstrument().setRangeBias(0)
        instrument.setRangePixelSize(rangePixelSize)
        instrument.setRangeSamplingRate(rangeSamplingRate)
        instrument.setBeamNumber(swath)
        instrument.setPulseLength(pulseLength)


        #Populate Frame
        #self.frame.setSatelliteHeight(height)
        self.frame.setSensingStart(dataStartTime)
        self.frame.setSensingStop(dataStopTime)
        diffTime = DTUtil.timeDeltaToSeconds(dataStopTime - dataStartTime)/2.0
        sensingMid = dataStartTime + datetime.timedelta(microseconds=int(diffTime*1e6))
        self.frame.setSensingMid(sensingMid)
        self.frame.setPassDirection(passDirection)
        self.frame.setPolarization(polarization) 
        self.frame.setStartingRange(startingRange)
        self.frame.setFarRange(startingRange + (samples-1)*rangePixelSize)
        self.frame.setNumberOfLines(lines)
        self.frame.setNumberOfSamples(samples)
        self.frame.setProcessingFacility(facility)
        self.frame.setProcessingSoftwareVersion(version)
        
        # Initialize orbit objects
        # Read into temp orbit first. 
        # Radarsat 2 needs orbit extensions.
        tempOrbit = Orbit()

        self.frame.getOrbit().setOrbitSource('Header: ' + self.product.sourceAttributes.orbitAndAttitude.orbitInformation.orbitDataFile)
        self.frame.setPassDirection(passDirection)
        stateVectors = self.product.sourceAttributes.orbitAndAttitude.orbitInformation.stateVectors
        for i in range(len(stateVectors)):
            position = [stateVectors[i].xPosition, stateVectors[i].yPosition, stateVectors[i].zPosition]
            velocity = [stateVectors[i].xVelocity, stateVectors[i].yVelocity, stateVectors[i].zVelocity]
            vec = StateVector()            
            vec.setTime(stateVectors[i].timeStamp)
            vec.setPosition(position)
            vec.setVelocity(velocity)
            tempOrbit.addStateVector(vec)

        planet = self.frame.instrument.platform.planet
        orbExt = OrbitExtender(planet=planet)
        orbExt.configure()
        newOrb = orbExt.extendOrbit(tempOrbit)

        for sv in newOrb:
            self.frame.getOrbit().addStateVector(sv)


    def extractImage(self, verbose=True):
        '''
        Use gdal to extract the slc.
        '''

        try:
            from osgeo import gdal
        except ImportError:
            raise Exception('GDAL python bindings not found. Need this for RSAT2 / TandemX / Sentinel1A.')

        self.parse()

        width = self.frame.getNumberOfSamples()
        lgth  = self.frame.getNumberOfLines()
        lineFlip = (self.product.imageAttributes.rasterAttributes.lineTimeOrdering.upper() == 'DECREASING')
        pixFlip = (self.product.imageAttributes.rasterAttributes.pixelTimeOrdering.upper() == 'DECREASING')

        src = gdal.Open(self.tiff.strip(), gdal.GA_ReadOnly)
        cJ = np.complex64(1.0j)

        ####Images are small enough that we can do it all in one go - Piyush
        real = src.GetRasterBand(1).ReadAsArray(0,0,width,lgth)
        imag = src.GetRasterBand(2).ReadAsArray(0,0,width,lgth)

        if (real is None) or (imag is None):
            raise Exception('Input Radarsat2 SLC seems to not be a 2 band Int16 image.')

        data = real+cJ*imag

        real = None
        imag = None
        src = None

        if lineFlip:
            if verbose:
                print('Vertically Flipping data')
            data = np.flipud(data)

        if pixFlip:
            if verbose:
                print('Horizontally Flipping data')
            data = np.fliplr(data)

        data.tofile(self.output)

        ####
        slcImage = isceobj.createSlcImage()
        slcImage.setByteOrder('l')
        slcImage.setFilename(self.output)
        slcImage.setAccessMode('read')
        slcImage.setWidth(width)
        slcImage.setLength(lgth)
        slcImage.setXmin(0)
        slcImage.setXmax(width)
#        slcImage.renderHdr()
        self.frame.setImage(slcImage)


    def extractDoppler(self):
        '''
        self.parse()
        Extract doppler information as needed by mocomp
        '''
        ins = self.frame.getInstrument()
        dc = self.product.imageGenerationParameters.dopplerCentroid
        quadratic = {}

        r0 = self.frame.startingRange
        fs = ins.getRangeSamplingRate()
        tNear = 2*r0/Const.c

        tMid = tNear + 0.5*self.frame.getNumberOfSamples()/fs
        t0 = dc.dopplerCentroidReferenceTime
        poly = dc.dopplerCentroidCoefficients
       
        fd_mid = 0.0
        for kk in range(len(poly)):
            fd_mid += poly[kk] * (tMid - t0)**kk
        
        quadratic['a'] = fd_mid / ins.getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.
        return quadratic
Esempio n. 15
0
class Sentinel1A(Component):
    """
        A Class representing RadarSAT 2 data
    """
    def __init__(self):
        Component.__init__(self)
        self.xml = None
        self.tiff = None
        self.orbitfile = None
        self.output = None
        self.frame = Frame()
        self.frame.configure()

        self._xml_root = None
        self.descriptionOfVariables = {}
        self.dictionaryOfVariables = {
            'XML': ['self.xml', 'str', 'mandatory'],
            'TIFF': ['self.tiff', 'str', 'mandatory'],
            'ORBITFILE': ['self.orbitfile', 'str', 'optional'],
            'OUTPUT': ['self.output', 'str', 'optional']
        }

    def getFrame(self):
        return self.frame

    def parse(self):
        try:
            fp = open(self.xml, 'r')
        except IOError as strerr:
            print("IOError: %s" % strerr)
            return
        self._xml_root = ElementTree(file=fp).getroot()
        #        self.product.set_from_etnode(self._xml_root)
        self.populateMetadata()

        fp.close()

    def grab_from_xml(self, path):
        try:
            res = self._xml_root.find(path).text
        except:
            raise Exception('Tag= %s not found' % (path))

        if res is None:
            raise Exception('Tag = %s not found' % (path))

        return res

    def convertToDateTime(self, string):
        dt = datetime.datetime.strptime(string, "%Y-%m-%dT%H:%M:%S.%f")
        return dt

    def populateMetadata(self):
        """
            Create metadata objects from the metadata files
        """
        ####Set each parameter one - by - one
        mission = self.grab_from_xml('adsHeader/missionId')
        swath = self.grab_from_xml('adsHeader/swath')
        polarization = self.grab_from_xml('adsHeader/polarisation')

        frequency = float(
            self.grab_from_xml(
                'generalAnnotation/productInformation/radarFrequency'))
        passDirection = self.grab_from_xml(
            'generalAnnotation/productInformation/pass')

        rangePixelSize = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/rangePixelSpacing'))
        azimuthPixelSize = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/azimuthPixelSpacing'))
        rangeSamplingRate = Const.c / (2.0 * rangePixelSize)
        prf = 1.0 / float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/azimuthTimeInterval'))

        lines = int(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/numberOfLines'))
        samples = int(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/numberOfSamples'))

        startingRange = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/slantRangeTime')
        ) * Const.c / 2.0
        incidenceAngle = float(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/incidenceAngleMidSwath'))
        dataStartTime = self.convertToDateTime(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/productFirstLineUtcTime'))
        dataStopTime = self.convertToDateTime(
            self.grab_from_xml(
                'imageAnnotation/imageInformation/productLastLineUtcTime'))

        pulseLength = float(
            self.grab_from_xml(
                'generalAnnotation/downlinkInformationList/downlinkInformation/downlinkValues/txPulseLength'
            ))
        chirpSlope = float(
            self.grab_from_xml(
                'generalAnnotation/downlinkInformationList/downlinkInformation/downlinkValues/txPulseRampRate'
            ))
        pulseBandwidth = pulseLength * chirpSlope

        ####Sentinel is always right looking
        lookSide = -1
        facility = 'EU'
        version = '1.0'

        #        height = self.product.imageGenerationParameters.sarProcessingInformation._satelliteHeight

        ####Populate platform
        platform = self.frame.getInstrument().getPlatform()
        platform.setPlanet(Planet(pname="Earth"))
        platform.setMission(mission)
        platform.setPointingDirection(lookSide)
        platform.setAntennaLength(2 * azimuthPixelSize)

        ####Populate instrument
        instrument = self.frame.getInstrument()
        instrument.setRadarFrequency(frequency)
        instrument.setPulseRepetitionFrequency(prf)
        instrument.setPulseLength(pulseLength)
        instrument.setChirpSlope(pulseBandwidth / pulseLength)
        instrument.setIncidenceAngle(incidenceAngle)
        #self.frame.getInstrument().setRangeBias(0)
        instrument.setRangePixelSize(rangePixelSize)
        instrument.setRangeSamplingRate(rangeSamplingRate)
        instrument.setBeamNumber(swath)
        instrument.setPulseLength(pulseLength)

        #Populate Frame
        #self.frame.setSatelliteHeight(height)
        self.frame.setSensingStart(dataStartTime)
        self.frame.setSensingStop(dataStopTime)
        diffTime = DTUtil.timeDeltaToSeconds(dataStopTime -
                                             dataStartTime) / 2.0
        sensingMid = dataStartTime + datetime.timedelta(
            microseconds=int(diffTime * 1e6))
        self.frame.setSensingMid(sensingMid)
        self.frame.setPassDirection(passDirection)
        self.frame.setPolarization(polarization)
        self.frame.setStartingRange(startingRange)
        self.frame.setFarRange(startingRange + (samples - 1) * rangePixelSize)
        self.frame.setNumberOfLines(lines)
        self.frame.setNumberOfSamples(samples)
        self.frame.setProcessingFacility(facility)
        self.frame.setProcessingSoftwareVersion(version)

        self.frame.setPassDirection(passDirection)

        ResOrbFlag = self.extractResOrbit()
        if ResOrbFlag == 0:
            print(
                "cannot find POD Restituted Orbit, using orbit coming along with SLC"
            )
            self.extractOrbit()

######################################################################################

    def extractResOrbit(self):
        #read ESA's POD Restituted Orbit by Cunren Liang, APR. 2, 2015.
        import pathlib

        useResOrbFlag = 0

        ResOrbDir = os.environ.get('RESORB')
        if ResOrbDir != None:
            print("Trying to find POD Restituted Orbit...")
            #get start time and stop time of the SLC data from data xml file
            dataStartTime = self.convertToDateTime(
                self.grab_from_xml(
                    'imageAnnotation/imageInformation/productFirstLineUtcTime')
            )
            dataStopTime = self.convertToDateTime(
                self.grab_from_xml(
                    'imageAnnotation/imageInformation/productLastLineUtcTime'))

            #RESORB has an orbit every 10 sec, extend the start and stop time by 50 sec.
            dataStartTimeExt = dataStartTime - datetime.timedelta(0, 50)
            dataStopTimeExt = dataStopTime + datetime.timedelta(0, 50)

            ###########################
            #deal with orbit directory
            ###########################

            orbList = pathlib.Path(ResOrbDir).glob('**/*.EOF')
            for orb in orbList:
                #save full path
                orb = str(orb)
                orbx = orb

                #get orbit file name
                orb = os.path.basename(os.path.normpath(orb))
                #print("{0}".format(orb))

                #get start and stop time of the orbit file
                orbStartTime = datetime.datetime.strptime(
                    orb[42:57], "%Y%m%dT%H%M%S")
                orbStopTime = datetime.datetime.strptime(
                    orb[58:73], "%Y%m%dT%H%M%S")
                #print("{0}, {1}".format(orbStartTime, orbStopTime))

                if dataStartTimeExt >= orbStartTime and dataStopTimeExt <= orbStopTime:
                    try:
                        orbfp = open(orbx, 'r')
                    except IOError as strerr:
                        print("IOError: %s" % strerr)
                        return useResOrbFlag
                    orbxml = ElementTree(file=orbfp).getroot()
                    print('using orbit file: {0}'.format(orbx))

                    frameOrbit = Orbit()
                    frameOrbit.setOrbitSource('Restituted')

                    #find the orbit data from the file, and use them
                    node = orbxml.find('Data_Block/List_of_OSVs'
                                       )  #note upper case and lower case
                    for child in node.getchildren():
                        timestamp = self.convertToDateTime(
                            child.find('UTC').text[4:])
                        if timestamp < dataStartTimeExt:
                            continue
                        if timestamp > dataStopTimeExt:
                            break

                        pos = []
                        vel = []
                        for tag in ['X', 'Y', 'Z']:
                            pos.append(float(child.find(tag).text))
                            vel.append(float(child.find('V' + tag).text))

                        vec = StateVector()
                        vec.setTime(timestamp)
                        vec.setPosition(pos)
                        vec.setVelocity(vel)
                        frameOrbit.addStateVector(vec)

                    #there is no need to extend the orbit any longer
                    #planet = self.frame.instrument.platform.planet
                    #orbExt = OrbitExtender(planet=planet)
                    #orbExt.configure()
                    #newOrb = orbExt.extendOrbit(frameOrbit)

                    self.frame.getOrbit().setOrbitSource('Restituted')
                    for sv in frameOrbit:
                        self.frame.getOrbit().addStateVector(sv)

                    orbfp.close()
                    useResOrbFlag = 1
                    break
        return useResOrbFlag
######################################################################################

    def extractOrbit(self):
        '''
        Extract orbit information from xml node.
        '''

        node = self._xml_root.find('generalAnnotation/orbitList')
        frameOrbit = Orbit()
        frameOrbit.setOrbitSource('Header')

        for child in node.getchildren():
            timestamp = self.convertToDateTime(child.find('time').text)
            pos = []
            vel = []
            posnode = child.find('position')
            velnode = child.find('velocity')
            for tag in ['x', 'y', 'z']:
                pos.append(float(posnode.find(tag).text))

            for tag in ['x', 'y', 'z']:
                vel.append(float(velnode.find(tag).text))

            vec = StateVector()
            vec.setTime(timestamp)
            vec.setPosition(pos)
            vec.setVelocity(vel)
            frameOrbit.addStateVector(vec)

        planet = self.frame.instrument.platform.planet
        orbExt = OrbitExtender(planet=planet)
        orbExt.configure()
        newOrb = orbExt.extendOrbit(frameOrbit)

        self.frame.getOrbit().setOrbitSource('Header')
        for sv in newOrb:
            self.frame.getOrbit().addStateVector(sv)

        return

    def extractPreciseOrbit(self):
        '''
        Extract precise orbit from given Orbit file.
        '''
        try:
            fp = open(self.orbitfile, 'r')
        except IOError as strerr:
            print("IOError: %s" % strerr)
            return

        _xml_root = ElementTree(file=fp).getroot()

        node = _xml_root.find('Data_Block/List_of_OSVs')

        orb = Orbit()
        orb.configure()

        margin = datetime.timedelta(seconds=40.0)
        tstart = self.frame.getSensingStart() - margin
        tend = self.frame.getSensingStop() + margin

        for child in node.getchildren():
            timestamp = self.convertToDateTime(child.find('UTC').text[4:])

            if (timestamp >= tstart) and (timestamp < tend):

                pos = []
                vel = []

                for tag in ['VX', 'VY', 'VZ']:
                    vel.append(float(child.find(tag).text))

                for tag in ['X', 'Y', 'Z']:
                    pos.append(float(child.find(tag).text))

                vec = StateVector()
                vec.setTime(timestamp)
                vec.setPosition(pos)
                vec.setVelocity(vel)
                orb.addStateVector(vec)

        fp.close()

        self.frame.getOrbit().setOrbitSource('Header')
        for sv in orb:
            self.frame.getOrbit().addStateVector(sv)

        return

    def extractImage(self):
        """
           Use gdal python bindings to extract image
        """
        try:
            from osgeo import gdal
        except ImportError:
            raise Exception(
                'GDAL python bindings not found. Need this for RSAT2/ TandemX / Sentinel1A.'
            )

        self.parse()
        width = self.frame.getNumberOfSamples()
        lgth = self.frame.getNumberOfLines()

        src = gdal.Open(self.tiff.strip(), gdal.GA_ReadOnly)
        band = src.GetRasterBand(1)
        fid = open(self.output, 'wb')
        for ii in range(lgth):
            data = band.ReadAsArray(0, ii, width, 1)
            data.tofile(fid)

        fid.close()
        src = None
        band = None

        ####
        slcImage = isceobj.createSlcImage()
        slcImage.setByteOrder('l')
        slcImage.setFilename(self.output)
        slcImage.setAccessMode('read')
        slcImage.setWidth(self.frame.getNumberOfSamples())
        slcImage.setLength(self.frame.getNumberOfLines())
        slcImage.setXmin(0)
        slcImage.setXmax(self.frame.getNumberOfSamples())
        self.frame.setImage(slcImage)

    def extractDoppler(self):
        '''
        self.parse()
        Extract doppler information as needed by mocomp
        '''
        #        ins = self.frame.getInstrument()
        #        dc = self.product.imageGenerationParameters.dopplerCentroid
        quadratic = {}

        #        r0 = self.frame.startingRange
        #        fs = ins.getRangeSamplingRate()
        #        tNear = 2*r0/Const.c

        #        tMid = tNear + 0.5*self.frame.getNumberOfSamples()/fs
        #        t0 = dc.dopplerCentroidReferenceTime
        #        poly = dc.dopplerCentroidCoefficients

        #        fd_mid = 0.0
        #        for kk in range(len(poly)):
        #            fd_mid += poly[kk] * (tMid - t0)**kk

        #        quadratic['a'] = fd_mid / ins.getPulseRepetitionFrequency()
        quadratic['a'] = 0.
        quadratic['b'] = 0.
        quadratic['c'] = 0.
        return quadratic
Esempio n. 16
0
class JERS(Component):
    """
    Code to read CEOSFormat leader files for ERS-1/2 SAR data.
    The tables used to create this parser are based on document
    number ER-IS-EPO-GS-5902.1 from the European Space Agency.
    """

    #Parsers.CEOS.CEOSFormat.ceosTypes['text'] = {'typeCode': 63, 'subtypeCode': [18,18,18]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['leaderFile'] = {'typeCode': 192, 'subtypeCode': [63,18,18]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['dataSetSummary'] = {'typeCode': 10, 'subtypeCode': [10,31,20]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['platformPositionData'] = {'typeCode': 30, 'subtypeCode': [10,31,20]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['facilityData'] = {'typeCode': 200, 'subtypeCode': [10,31,50]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['datafileDescriptor'] = {'typeCode': 192, 'subtypeCode':[63,18,18]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['signalData'] = {'typeCode': 10, 'subtypeCode': [50,31,20]}
    #Parsers.CEOS.CEOSFormat.ceosTypes['nullFileDescriptor'] = {'typeCode': 192, 'subtypeCode': [192,63,18]}

    def __init__(self):
        Component.__init__(self)
        self._leaderFile = None
        self._imageFile = None
        self.output = None

        self.frame = Frame()
        self.frame.configure()

        self.constants = {'polarization': 'HH',
                          'antennaLength': 12}

        self.descriptionOfVariables = {}
        self.dictionaryOfVariables = {'LEADERFILE': ['self._leaderFile','str','mandatory'],
                                      'IMAGEFILE': ['self._imageFile','str','mandatory'],
                                      'OUTPUT': ['self.output','str','optional']}

    def getFrame(self):
        return self.frame

    def parse(self):
        self.leaderFile = LeaderFile(file=self._leaderFile)
        self.leaderFile.parse()

        self.imageFile = ImageFile(file=self._imageFile)
        self.imageFile.parse()

        self.populateMetadata()

    def populateMetadata(self):
        """
            Create the appropriate metadata objects from our CEOSFormat metadata
        """
        frame = self.leaderFile.sceneHeaderRecord.metadata['Scene reference number'].strip()
        frame = self._decodeSceneReferenceNumber(frame)
        rangePixelSize = Constants.SPEED_OF_LIGHT/(2*self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate']*1e6)

        self.frame.getInstrument().getPlatform().setMission(self.leaderFile.sceneHeaderRecord.metadata['Sensor platform mission identifier'])
        self.frame.getInstrument().getPlatform().setPlanet(Planet(pname='Earth'))

        self.frame.getInstrument().setWavelength(self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength'])
        self.frame.getInstrument().setIncidenceAngle(self.leaderFile.sceneHeaderRecord.metadata['Incidence angle at scene centre'])
        self.frame.getInstrument().setPulseRepetitionFrequency(self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency'])
        self.frame.getInstrument().setRangePixelSize(rangePixelSize)
        self.frame.getInstrument().setPulseLength(self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']*1e-6)
        chirpPulseBandwidth = 15.50829e6 # Is this really not in the CEOSFormat Header?
        self.frame.getInstrument().setChirpSlope(chirpPulseBandwidth/(self.leaderFile.sceneHeaderRecord.metadata['Range pulse length']*1e-6))

        self.frame.setFrameNumber(frame)
        self.frame.setOrbitNumber(self.leaderFile.sceneHeaderRecord.metadata['Orbit number'])
        #self.frame.setStartingRange(self.leaderFile.facilityRecord.metadata['Slant range reference'])
        self.frame.setProcessingFacility(self.leaderFile.sceneHeaderRecord.metadata['Processing facility identifier'])
        self.frame.setProcessingSystem(self.leaderFile.sceneHeaderRecord.metadata['Processing system identifier'])
        self.frame.setProcessingSoftwareVersion(self.leaderFile.sceneHeaderRecord.metadata['Processing version identifier'])
        self.frame.setPolarization('HH')
        self.frame.setNumberOfLines(self.imageFile.imageFDR.metadata['Number of lines per data set'])
        self.frame.setNumberOfSamples(self.imageFile.imageFDR.metadata['Number of pixels per line per SAR channel'])


        self.frame.getOrbit().setOrbitSource('Header')
        t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.metadata['Year of data point'],
                               month=self.leaderFile.platformPositionRecord.metadata['Month of data point'],
                               day=self.leaderFile.platformPositionRecord.metadata['Day of data point'])
        t0 = t0 + datetime.timedelta(seconds=self.leaderFile.platformPositionRecord.metadata['Seconds of day'])
        for i in range(self.leaderFile.platformPositionRecord.metadata['Number of data points']):
            vec = StateVector()
            t = t0 + datetime.timedelta(seconds=(i*self.leaderFile.platformPositionRecord.metadata['Time interval between DATA points']))
            vec.setTime(t)
            dataPoints = self.leaderFile.platformPositionRecord.metadata['Positional Data Points'][i]
            vec.setPosition([dataPoints['Position vector X'], dataPoints['Position vector Y'], dataPoints['Position vector Z']])
            vec.setVelocity([dataPoints['Velocity vector X'], dataPoints['Velocity vector Y'], dataPoints['Velocity vector Z']])
            self.frame.getOrbit().addStateVector(vec)

    def extractImage(self):
        raise NotImplementedError()

    def _decodeSceneReferenceNumber(self,referenceNumber):
        return referenceNumber
Esempio n. 17
0
class Radarsat2(Sensor):
    """
        A Class representing RADARSAT 2 data
    """

    family = 'radarsat2'
    parameter_list = (XML, TIFF) + Sensor.parameter_list

    def __init__(self, family='', name=''):
        super().__init__(family if family else self.__class__.family,
                         name=name)
        self.product = _Product()
        self.frame = Frame()
        self.frame.configure()

    def getFrame(self):
        return self.frame

    def parse(self):
        try:
            fp = open(self.xml, 'r')
        except IOError as strerr:
            print("IOError: %s" % strerr)
            return
        self._xml_root = ElementTree(file=fp).getroot()
        self.product.set_from_etnode(self._xml_root)
        self.populateMetadata()

        fp.close()

    def populateMetadata(self):
        """
            Create metadata objects from the metadata files
        """
        mission = self.product.sourceAttributes.satellite
        swath = self.product.sourceAttributes.radarParameters.beams
        frequency = self.product.sourceAttributes.radarParameters.radarCenterFrequency
        orig_prf = self.product.sourceAttributes.radarParameters.prf  # original PRF not necessarily effective PRF
        rangePixelSize = self.product.imageAttributes.rasterAttributes.sampledPixelSpacing
        rangeSamplingRate = Const.c / (2 * rangePixelSize)
        pulseLength = self.product.sourceAttributes.radarParameters.pulseLengths[
            0]
        pulseBandwidth = self.product.sourceAttributes.radarParameters.pulseBandwidths[
            0]
        polarization = self.product.sourceAttributes.radarParameters.polarizations
        lookSide = lookMap[self.product.sourceAttributes.radarParameters.
                           antennaPointing.upper()]
        facility = self.product.imageGenerationParameters.generalProcessingInformation._processingFacility
        version = self.product.imageGenerationParameters.generalProcessingInformation.softwareVersion
        lines = self.product.imageAttributes.rasterAttributes.numberOfLines
        samples = self.product.imageAttributes.rasterAttributes.numberOfSamplesPerLine
        startingRange = self.product.imageGenerationParameters.slantRangeToGroundRange.slantRangeTimeToFirstRangeSample * (
            Const.c / 2)
        incidenceAngle = (self.product.imageGenerationParameters.
                          sarProcessingInformation.incidenceAngleNearRange +
                          self.product.imageGenerationParameters.
                          sarProcessingInformation.incidenceAngleFarRange) / 2
        # some RS2 scenes have oversampled SLC images because processed azimuth bandwidth larger than PRF EJF 2015/08/15
        azimuthPixelSize = self.product.imageAttributes.rasterAttributes.sampledLineSpacing  # ground spacing in meters
        totalProcessedAzimuthBandwidth = self.product.imageGenerationParameters.sarProcessingInformation.totalProcessedAzimuthBandwidth
        prf = orig_prf * np.ceil(
            totalProcessedAzimuthBandwidth / orig_prf
        )  # effective PRF can be double original, suggested by Piyush
        print("effective PRF %f, original PRF %f" % (prf, orig_prf))

        lineFlip = (self.product.imageAttributes.rasterAttributes.
                    lineTimeOrdering.upper() == 'DECREASING')

        if lineFlip:
            dataStopTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeFirstLine
            dataStartTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeLastLine
        else:
            dataStartTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeFirstLine
            dataStopTime = self.product.imageGenerationParameters.sarProcessingInformation.zeroDopplerTimeLastLine

        passDirection = self.product.sourceAttributes.orbitAndAttitude.orbitInformation.passDirection
        height = self.product.imageGenerationParameters.sarProcessingInformation._satelliteHeight

        ####Populate platform
        platform = self.frame.getInstrument().getPlatform()
        platform.setPlanet(Planet(pname="Earth"))
        platform.setMission(mission)
        platform.setPointingDirection(lookSide)
        platform.setAntennaLength(15.0)

        ####Populate instrument
        instrument = self.frame.getInstrument()
        instrument.setRadarFrequency(frequency)
        instrument.setPulseRepetitionFrequency(prf)
        instrument.setPulseLength(pulseLength)
        instrument.setChirpSlope(pulseBandwidth / pulseLength)
        instrument.setIncidenceAngle(incidenceAngle)
        #self.frame.getInstrument().setRangeBias(0)
        instrument.setRangePixelSize(rangePixelSize)
        instrument.setRangeSamplingRate(rangeSamplingRate)
        instrument.setBeamNumber(swath)
        instrument.setPulseLength(pulseLength)

        #Populate Frame
        #self.frame.setSatelliteHeight(height)
        self.frame.setSensingStart(dataStartTime)
        self.frame.setSensingStop(dataStopTime)
        diffTime = DTUtil.timeDeltaToSeconds(dataStopTime -
                                             dataStartTime) / 2.0
        sensingMid = dataStartTime + datetime.timedelta(
            microseconds=int(diffTime * 1e6))
        self.frame.setSensingMid(sensingMid)
        self.frame.setPassDirection(passDirection)
        self.frame.setPolarization(polarization)
        self.frame.setStartingRange(startingRange)
        self.frame.setFarRange(startingRange + (samples - 1) * rangePixelSize)
        self.frame.setNumberOfLines(lines)
        self.frame.setNumberOfSamples(samples)
        self.frame.setProcessingFacility(facility)
        self.frame.setProcessingSoftwareVersion(version)

        # Initialize orbit objects
        # Read into temp orbit first.
        # Radarsat 2 needs orbit extensions.
        tempOrbit = Orbit()

        self.frame.getOrbit().setOrbitSource(
            'Header: ' + self.product.sourceAttributes.orbitAndAttitude.
            orbitInformation.orbitDataFile)
        self.frame.setPassDirection(passDirection)
        stateVectors = self.product.sourceAttributes.orbitAndAttitude.orbitInformation.stateVectors
        for i in range(len(stateVectors)):
            position = [
                stateVectors[i].xPosition, stateVectors[i].yPosition,
                stateVectors[i].zPosition
            ]
            velocity = [
                stateVectors[i].xVelocity, stateVectors[i].yVelocity,
                stateVectors[i].zVelocity
            ]
            vec = StateVector()
            vec.setTime(stateVectors[i].timeStamp)
            vec.setPosition(position)
            vec.setVelocity(velocity)
            tempOrbit.addStateVector(vec)

        planet = self.frame.instrument.platform.planet
        orbExt = OrbitExtender(planet=planet)
        orbExt.configure()
        newOrb = orbExt.extendOrbit(tempOrbit)

        for sv in newOrb:
            self.frame.getOrbit().addStateVector(sv)

# save the Doppler centroid coefficients, converting units from product.xml file
# units in the file are quadratic coefficients in Hz, Hz/sec, and Hz/(sec^2)
# ISCE expects Hz, Hz/(range sample), Hz((range sample)^2
# note that RS2 Doppler values are estimated at time dc.dopplerCentroidReferenceTime,
# so the values might need to be adjusted for ISCE usage
# added EJF 2015/08/17
        dc = self.product.imageGenerationParameters.dopplerCentroid
        poly = dc.dopplerCentroidCoefficients
        # need to convert units
        poly[1] = poly[1] / rangeSamplingRate
        poly[2] = poly[2] / rangeSamplingRate**2
        self.doppler_coeff = poly

        # similarly save Doppler azimuth fm rate values, converting units
        # units in the file are quadratic coefficients in Hz, Hz/sec, and Hz/(sec^2)
        # Guessing that ISCE expects Hz, Hz/(range sample), Hz((range sample)^2
        # note that RS2 Doppler values are estimated at time dc.dopplerRateReferenceTime,
        # so the values might need to be adjusted for ISCE usage
        # added EJF 2015/08/17
        dr = self.product.imageGenerationParameters.dopplerRateValues
        fmpoly = dr.dopplerRateValuesCoefficients
        # need to convert units
        fmpoly[1] = fmpoly[1] / rangeSamplingRate
        fmpoly[2] = fmpoly[2] / rangeSamplingRate**2
        self.azfmrate_coeff = fmpoly

        # now calculate effective PRF from the azimuth line spacing after we have the orbit info EJF 2015/08/15
        # this does not work because azimuth spacing is on ground. Instead use bandwidth ratio calculated above  EJF


#        SCHvelocity = self.frame.getSchVelocity()
#        SCHvelocity = 7550.75  # hard code orbit velocity for now m/s
#        prf = SCHvelocity/azimuthPixelSize
#        instrument.setPulseRepetitionFrequency(prf)

    def extractImage(self, verbose=True):
        '''
        Use gdal to extract the slc.
        '''

        try:
            from osgeo import gdal
        except ImportError:
            raise Exception(
                'GDAL python bindings not found. Need this for RSAT2 / TandemX / Sentinel1A.'
            )

        self.parse()

        width = self.frame.getNumberOfSamples()
        lgth = self.frame.getNumberOfLines()
        lineFlip = (self.product.imageAttributes.rasterAttributes.
                    lineTimeOrdering.upper() == 'DECREASING')
        pixFlip = (self.product.imageAttributes.rasterAttributes.
                   pixelTimeOrdering.upper() == 'DECREASING')

        src = gdal.Open(self.tiff.strip(), gdal.GA_ReadOnly)
        cJ = np.complex64(1.0j)

        ####Images are small enough that we can do it all in one go - Piyush
        real = src.GetRasterBand(1).ReadAsArray(0, 0, width, lgth)
        imag = src.GetRasterBand(2).ReadAsArray(0, 0, width, lgth)

        if (real is None) or (imag is None):
            raise Exception(
                'Input Radarsat2 SLC seems to not be a 2 band Int16 image.')

        data = real + cJ * imag

        real = None
        imag = None
        src = None

        if lineFlip:
            if verbose:
                print('Vertically Flipping data')
            data = np.flipud(data)

        if pixFlip:
            if verbose:
                print('Horizontally Flipping data')
            data = np.fliplr(data)

        data.tofile(self.output)

        ####
        slcImage = isceobj.createSlcImage()
        slcImage.setByteOrder('l')
        slcImage.setFilename(self.output)
        slcImage.setAccessMode('read')
        slcImage.setWidth(width)
        slcImage.setLength(lgth)
        slcImage.setXmin(0)
        slcImage.setXmax(width)
        #        slcImage.renderHdr()
        self.frame.setImage(slcImage)

    def extractDoppler(self):
        '''
        self.parse()
        Extract doppler information as needed by mocomp
        '''
        ins = self.frame.getInstrument()
        dc = self.product.imageGenerationParameters.dopplerCentroid
        quadratic = {}

        r0 = self.frame.startingRange
        fs = ins.getRangeSamplingRate()
        tNear = 2 * r0 / Const.c

        tMid = tNear + 0.5 * self.frame.getNumberOfSamples() / fs
        t0 = dc.dopplerCentroidReferenceTime
        poly = dc.dopplerCentroidCoefficients

        fd_mid = 0.0
        for kk in range(len(poly)):
            fd_mid += poly[kk] * (tMid - t0)**kk

        ####For insarApp
        quadratic['a'] = fd_mid / ins.getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.

        ####For roiApp
        ####More accurate
        from isceobj.Util import Poly1D

        coeffs = poly
        dr = self.frame.getInstrument().getRangePixelSize()
        rref = 0.5 * Const.c * t0
        r0 = self.frame.getStartingRange()
        norm = 0.5 * Const.c / dr

        dcoeffs = []
        for ind, val in enumerate(coeffs):
            dcoeffs.append(val / (norm**ind))

        poly = Poly1D.Poly1D()
        poly.initPoly(order=len(coeffs) - 1)
        poly.setMean((rref - r0) / dr - 1.0)
        poly.setCoeffs(dcoeffs)

        pix = np.linspace(0,
                          self.frame.getNumberOfSamples(),
                          num=len(coeffs) + 1)
        evals = poly(pix)
        fit = np.polyfit(pix, evals, len(coeffs) - 1)
        self.frame._dopplerVsPixel = list(fit[::-1])
        print('Doppler Fit: ', fit[::-1])

        return quadratic
Esempio n. 18
0
class Radarsat1(Sensor):
    """
    Code to read CEOSFormat leader files for Radarsat-1 SAR data.
    The tables used to create this parser are based on document number
    ER-IS-EPO-GS-5902.1 from the European Space Agency.
    """
    family = 'radarsat1'
    logging_name = 'isce.sensor.radarsat1'

    parameter_list = (LEADERFILE, IMAGEFILE, PARFILE) + Sensor.parameter_list

    auxLength = 50

    @logged
    def __init__(self, name=''):
        super().__init__(family=self.__class__.family, name=name)
        self.imageFile = None
        self.leaderFile = None

        #####Soecific doppler functions for RSAT1
        self.doppler_ref_range = None
        self.doppler_ref_azi = None
        self.doppler_predict = None
        self.doppler_DAR = None
        self.doppler_coeff = None

        self.frame = Frame()
        self.frame.configure()

        self.constants = {'polarization': 'HH', 'antennaLength': 15}

    def getFrame(self):
        return self.frame

    def parse(self):
        self.leaderFile = LeaderFile(self, file=self._leaderFile)
        self.leaderFile.parse()

        self.imageFile = ImageFile(self, file=self._imageFile)
        self.imageFile.parse()

        self.populateMetadata()

        if self._parFile:
            self.parseParFile()
        else:
            self.populateCEOSOrbit()

    def populateMetadata(self):
        """
            Create the appropriate metadata objects from our CEOSFormat metadata
        """
        frame = self._decodeSceneReferenceNumber(
            self.leaderFile.sceneHeaderRecord.
            metadata['Scene reference number'])
        try:
            rangePixelSize = Const.c / (2 * self.leaderFile.sceneHeaderRecord.
                                        metadata['Range sampling rate'] * 1e6)
        except ZeroDivisionError:
            rangePixelSize = 0

        ins = self.frame.getInstrument()
        platform = ins.getPlatform()
        platform.setMission(self.leaderFile.sceneHeaderRecord.
                            metadata['Sensor platform mission identifier'])
        platform.setAntennaLength(self.constants['antennaLength'])
        platform.setPointingDirection(-1)
        platform.setPlanet(Planet(pname='Earth'))

        ins.setRadarWavelength(
            self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength'])
        ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord.
                              metadata['Incidence angle at scene centre'])
        ##RSAT-1 does not have PRF for raw data in leader file.
        #        self.frame.getInstrument().setPulseRepetitionFrequency(self.leaderFile.sceneHeaderRecord.metadata['Pulse Repetition Frequency'])
        ins.setRangePixelSize(rangePixelSize)
        ins.setPulseLength(
            self.leaderFile.sceneHeaderRecord.metadata['Range pulse length'] *
            1e-6)
        chirpPulseBandwidth = 15.50829e6  # Is this really not in the CEOSFormat Header?
        ins.setChirpSlope(
            chirpPulseBandwidth /
            (self.leaderFile.sceneHeaderRecord.metadata['Range pulse length'] *
             1e-6))
        ins.setInPhaseValue(7.5)
        ins.setQuadratureValue(7.5)

        self.frame.setFrameNumber(frame)
        self.frame.setOrbitNumber(
            self.leaderFile.sceneHeaderRecord.metadata['Orbit number'])
        self.frame.setProcessingFacility(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing facility identifier'])
        self.frame.setProcessingSystem(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing system identifier'])
        self.frame.setProcessingSoftwareVersion(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing version identifier'])
        self.frame.setPolarization(self.constants['polarization'])
        self.frame.setNumberOfLines(
            self.imageFile.imageFDR.metadata['Number of lines per data set'])
        self.frame.setNumberOfSamples(
            self.imageFile.imageFDR.
            metadata['Number of pixels per line per SAR channel'])

        self.frame.getOrbit().setOrbitSource('Header')
        self.frame.getOrbit().setOrbitQuality(
            self.leaderFile.platformPositionRecord.
            metadata['Orbital elements designator'])

    def populateCEOSOrbit(self):
        from isceobj.Orbit.Inertial import ECI2ECR

        t0 = datetime.datetime(year=self.leaderFile.platformPositionRecord.
                               metadata['Year of data point'],
                               month=self.leaderFile.platformPositionRecord.
                               metadata['Month of data point'],
                               day=self.leaderFile.platformPositionRecord.
                               metadata['Day of data point'])
        t0 = t0 + datetime.timedelta(
            seconds=self.leaderFile.platformPositionRecord.
            metadata['Seconds of day'])

        #####Read in orbit in inertial coordinates
        orb = Orbit()
        for i in range(self.leaderFile.platformPositionRecord.
                       metadata['Number of data points']):
            vec = StateVector()
            t = t0 + datetime.timedelta(
                seconds=(i * self.leaderFile.platformPositionRecord.
                         metadata['Time interval between DATA points']))
            vec.setTime(t)
            dataPoints = self.leaderFile.platformPositionRecord.metadata[
                'Positional Data Points'][i]
            vec.setPosition([
                dataPoints['Position vector X'],
                dataPoints['Position vector Y'],
                dataPoints['Position vector Z']
            ])
            vec.setVelocity([
                dataPoints['Velocity vector X'] / 1000.,
                dataPoints['Velocity vector Y'] / 1000.,
                dataPoints['Velocity vector Z'] / 1000.
            ])
            orb.addStateVector(vec)

        #####Convert orbits from ECI to ECEF frame.
        t0 = orb._stateVectors[0]._time
        ang = self.leaderFile.platformPositionRecord.metadata[
            'Greenwich mean hour angle']

        cOrb = ECI2ECR(orb, GAST=ang, epoch=t0)
        wgsorb = cOrb.convert()

        orb = self.frame.getOrbit()

        for sv in wgsorb:
            orb.addStateVector(sv)
            print(sv)

    def extractImage(self):
        import isceobj
        if (self.imageFile is None) or (self.leaderFile is None):
            self.parse()

        try:
            out = open(self.output, 'wb')
        except IOError as strerr:
            self.logger.error("IOError: %s" % strerr)

        self.imageFile.extractImage(output=out)
        out.close()

        ####RSAT1 is weird. Contains all useful info in RAW data and not leader.
        ins = self.frame.getInstrument()
        ins.setPulseRepetitionFrequency(self.imageFile.prf)
        ins.setPulseLength(self.imageFile.pulseLength)
        ins.setRangeSamplingRate(self.imageFile.rangeSamplingRate)
        ins.setRangePixelSize(Const.c / (2 * self.imageFile.rangeSamplingRate))
        ins.setChirpSlope(self.imageFile.chirpSlope)

        ######
        self.frame.setSensingStart(self.imageFile.sensingStart)
        sensingStop = self.imageFile.sensingStart + datetime.timedelta(
            seconds=((self.frame.getNumberOfLines() - 1) / self.imageFile.prf))
        sensingMid = self.imageFile.sensingStart + datetime.timedelta(
            seconds=0.5 *
            (sensingStop - self.imageFile.sensingStart).total_seconds())
        self.frame.setSensingStop(sensingStop)
        self.frame.setSensingMid(sensingMid)
        self.frame.setNumberOfSamples(self.imageFile.width)
        self.frame.setStartingRange(self.imageFile.startingRange)
        farRange = self.imageFile.startingRange + ins.getRangePixelSize(
        ) * self.imageFile.width * 0.5
        self.frame.setFarRange(farRange)

        rawImage = isceobj.createRawImage()
        rawImage.setByteOrder('l')
        rawImage.setAccessMode('read')
        rawImage.setFilename(self.output)
        rawImage.setWidth(self.imageFile.width)
        rawImage.setXmin(0)
        rawImage.setXmax(self.imageFile.width)
        rawImage.renderHdr()
        self.frame.setImage(rawImage)

    def parseParFile(self):
        '''Parse the par file if any is available.'''
        if self._parFile not in (None, ''):
            par = ParFile(self._parFile)

            ####Update orbit
            svs = par['prep_block']['sensor']['ephemeris']['sv_block'][
                'state_vector']
            datefmt = '%Y%m%d%H%M%S%f'
            for entry in svs:
                sv = StateVector()
                sv.setPosition(
                    [float(entry['x']),
                     float(entry['y']),
                     float(entry['z'])])
                sv.setVelocity([
                    float(entry['xv']),
                    float(entry['yv']),
                    float(entry['zv'])
                ])
                sv.setTime(datetime.datetime.strptime(entry['Date'], datefmt))
                self.frame.orbit.addStateVector(sv)

            self.frame.orbit._stateVectors = sorted(
                self.frame.orbit._stateVectors, key=lambda x: x.getTime())

            doppinfo = par['prep_block']['sensor']['beam'][
                'DopplerCentroidParameters']
            #######Selectively update some values.
            #######Currently used only for doppler centroids.

            self.doppler_ref_range = float(doppinfo['reference_range'])
            self.doppler_ref_azi = datetime.datetime.strptime(
                doppinfo['reference_date'], '%Y%m%d%H%M%S%f')
            self.doppler_predict = float(doppinfo['Predict_doppler'])
            self.doppler_DAR = float(doppinfo['DAR_doppler'])

            coeff = doppinfo['doppler_centroid_coefficients']
            rngOrder = int(coeff['number_of_coefficients_first_dimension']) - 1
            azOrder = int(coeff['number_of_coefficients_second_dimension']) - 1

            self.doppler_coeff = Poly2D.Poly2D()
            self.doppler_coeff.initPoly(rangeOrder=rngOrder,
                                        azimuthOrder=azOrder)
            self.doppler_coeff.setMeanRange(self.doppler_ref_range)
            self.doppler_coeff.setMeanAzimuth(
                secondsSinceMidnight(self.doppler_ref_azi))

            parms = []
            for ii in range(azOrder + 1):
                row = []
                for jj in range(rngOrder + 1):
                    key = 'a%d%d' % (ii, jj)
                    val = float(coeff[key])
                    row.append(val)

                parms.append(row)

            self.doppler_coeff.setCoeffs(parms)

    def extractDoppler(self):
        '''
        Evaluate the doppler polynomial and return the average value for now.
        '''

        rmin = self.frame.getStartingRange()
        rmax = self.frame.getFarRange()
        rmid = 0.5 * (rmin + rmax)
        delr = Const.c / (2 * self.frame.instrument.rangeSamplingRate)

        azmid = secondsSinceMidnight(self.frame.getSensingMid())

        print(rmid, self.doppler_coeff.getMeanRange())
        print(azmid, self.doppler_coeff.getMeanAzimuth())

        if self.doppler_coeff is None:
            raise Exception(
                'ASF PARFILE was not provided. Cannot determine default doppler.'
            )

        dopav = self.doppler_coeff(azmid, rmid)
        prf = self.frame.getInstrument().getPulseRepetitionFrequency()
        quadratic = {}
        quadratic['a'] = dopav / prf
        quadratic['b'] = 0.
        quadratic['c'] = 0.

        ######Set up the doppler centroid computation just like CSK at mid azimuth
        order = self.doppler_coeff._rangeOrder
        rng = np.linspace(rmin, rmax, num=(order + 2))
        pix = (rng - rmin) / delr
        val = [self.doppler_coeff(azmid, x) for x in rng]

        print(rng, val)
        print(delr, pix)
        fit = np.polyfit(pix, val, order)
        self.frame._dopplerVsPixel = list(fit[::-1])
        #        self.frame._dopplerVsPixel = [dopav,0.,0.,0.]
        return quadratic

    def _decodeSceneReferenceNumber(self, referenceNumber):
        return referenceNumber
Esempio n. 19
0
class Risat1_SLC(Sensor):
    """
        Code to read CEOSFormat leader files for Risat-1 SAR data.
    """
    family = "risat1"
    logging_name = 'isce.sensor.Risat1'
    parameter_list = (IMAGEFILE, LEADERFILE, METAFILE,
                      DATATYPE) + Sensor.parameter_list

    @logged
    def __init__(self, name=''):
        super().__init__(family=self.__class__.family, name=name)
        self.imageFile = None
        self.leaderFile = None

        #####Specific doppler functions for RISAT1
        self.doppler_coeff = None
        self.azfmrate_coeff = None
        self.lineDirection = None
        self.pixelDirection = None

        self.frame = Frame()
        self.frame.configure()

        self.constants = {
            'antennaLength': 6,
        }

        self.TxPolMap = {
            1: 'V',
            2: 'H',
            3: 'L',
            4: 'R',
        }

        self.RxPolMap = {
            1: 'V',
            2: 'H',
        }

    def getFrame(self):
        return self.frame

    def parse(self):
        self.leaderFile = LeaderFile(self, file=self._leaderFile)
        self.leaderFile.parse()

        self.imageFile = ImageFile(self, file=self._imageFile)
        self.imageFile.parse()

        self.populateMetadata()

    def populateMetadata(self):
        """
            Create the appropriate metadata objects from our CEOSFormat metadata
        """
        frame = self._decodeSceneReferenceNumber(
            self.leaderFile.sceneHeaderRecord.
            metadata['Scene reference number'])
        try:
            rangePixelSize = Const.c / (2 * self.leaderFile.sceneHeaderRecord.
                                        metadata['Range sampling rate'])
        except ZeroDivisionError:
            rangePixelSize = 0

        print(
            'Average terrain height: ', 1000 * self.leaderFile.
            sceneHeaderRecord.metadata['Average terrain height in km'])

        ins = self.frame.getInstrument()
        platform = ins.getPlatform()
        platform.setMission(self.leaderFile.sceneHeaderRecord.
                            metadata['Sensor platform mission identifier'])
        platform.setAntennaLength(self.constants['antennaLength'])
        platform.setPlanet(Planet(pname='Earth'))

        ins.setRadarWavelength(
            self.leaderFile.sceneHeaderRecord.metadata['Radar wavelength'])
        ins.setIncidenceAngle(self.leaderFile.sceneHeaderRecord.
                              metadata['Incidence angle at scene centre'])
        self.frame.getInstrument().setPulseRepetitionFrequency(
            self.leaderFile.sceneHeaderRecord.
            metadata['Pulse Repetition Frequency'])
        ins.setRangePixelSize(rangePixelSize)
        ins.setRangeSamplingRate(
            self.leaderFile.sceneHeaderRecord.metadata['Range sampling rate'])
        ins.setPulseLength(
            self.leaderFile.sceneHeaderRecord.metadata['Range pulse length'])

        chirpPulseBandwidth = self.leaderFile.processingRecord.metadata[
            'Pulse bandwidth code'] * 1e4
        ins.setChirpSlope(
            chirpPulseBandwidth /
            self.leaderFile.sceneHeaderRecord.metadata['Range pulse length'])
        ins.setInPhaseValue(0.0)
        ins.setQuadratureValue(0.0)

        self.lineDirection = self.leaderFile.sceneHeaderRecord.metadata[
            'Time direction indicator along line direction'].strip()
        self.pixelDirection = self.leaderFile.sceneHeaderRecord.metadata[
            'Time direction indicator along pixel direction'].strip()

        ######RISAT-1 sensor orientation convention is opposite to ours
        lookSide = self.leaderFile.processingRecord.metadata[
            'Sensor orientation']
        if lookSide == 'RIGHT':
            platform.setPointingDirection(1)
        elif lookSide == 'LEFT':
            platform.setPointingDirection(-1)
        else:
            raise Exception('Unknown look side')

        print('Leader file look side: ', lookSide)

        self.frame.setFrameNumber(frame)
        self.frame.setOrbitNumber(
            self.leaderFile.sceneHeaderRecord.metadata['Orbit number'])
        self.frame.setProcessingFacility(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing facility identifier'])
        self.frame.setProcessingSystem(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing system identifier'])
        self.frame.setProcessingSoftwareVersion(
            self.leaderFile.sceneHeaderRecord.
            metadata['Processing version identifier'])
        self.frame.setNumberOfLines(
            self.imageFile.imageFDR.metadata['Number of lines per data set'])
        self.frame.setNumberOfSamples(
            self.imageFile.imageFDR.
            metadata['Number of pixels per line per SAR channel'])

        ######

        self.frame.getOrbit().setOrbitSource('Header')
        self.frame.getOrbit().setOrbitQuality(
            self.leaderFile.platformPositionRecord.
            metadata['Orbital elements designator'])
        t0 = datetime.datetime(year=2000 +
                               self.leaderFile.platformPositionRecord.
                               metadata['Year of data point'],
                               month=self.leaderFile.platformPositionRecord.
                               metadata['Month of data point'],
                               day=self.leaderFile.platformPositionRecord.
                               metadata['Day of data point'])
        t0 = t0 + datetime.timedelta(
            seconds=self.leaderFile.platformPositionRecord.
            metadata['Seconds of day'])

        #####Read in orbit in inertial coordinates
        orb = Orbit()
        deltaT = self.leaderFile.platformPositionRecord.metadata[
            'Time interval between DATA points']
        numPts = self.leaderFile.platformPositionRecord.metadata[
            'Number of data points']

        for i in range(numPts):
            vec = StateVector()
            t = t0 + datetime.timedelta(seconds=i * deltaT)
            vec.setTime(t)

            dataPoints = self.leaderFile.platformPositionRecord.metadata[
                'Positional Data Points'][i]
            pos = [
                dataPoints['Position vector X'],
                dataPoints['Position vector Y'],
                dataPoints['Position vector Z']
            ]
            vel = [
                dataPoints['Velocity vector X'],
                dataPoints['Velocity vector Y'],
                dataPoints['Velocity vector Z']
            ]
            vec.setPosition(pos)
            vec.setVelocity(vel)
            orb.addStateVector(vec)

        #####Convert orbits from ECI to ECR frame
        t0 = orb._stateVectors[0]._time
        ang = self.leaderFile.platformPositionRecord.metadata[
            'Greenwich mean hour angle']

        cOrb = ECI2ECR(orb, GAST=ang, epoch=t0)
        iOrb = cOrb.convert()

        #####Extend the orbits by a few points
        #####Expect large azimuth shifts - absolutely needed
        #####Since CEOS contains state vectors that barely covers scene extent
        planet = self.frame.instrument.platform.planet
        orbExt = OrbitExtender()
        orbExt.configure()
        orbExt._newPoints = 4
        newOrb = orbExt.extendOrbit(iOrb)

        orb = self.frame.getOrbit()

        for sv in newOrb:
            orb.addStateVector(sv)

        self.doppler_coeff = [
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency centroid constant term'],
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency centroid linear term'],
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency centroid quadratic term']
        ]

        self.azfmrate_coeff = [
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency rate constant term'],
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency rate linear term'],
            self.leaderFile.sceneHeaderRecord.
            metadata['Cross track Doppler frequency rate quadratic term']
        ]

    def extractImage(self):
        import isceobj
        if (self.imageFile is None) or (self.leaderFile is None):
            self.parse()

        try:
            out = open(self.output, 'wb')
        except IOError as strerr:
            self.logger.error("IOError: %s" % strerr)

        self.imageFile.extractImage(output=out, dtype=self._dataType)
        out.close()

        self.frame.setSensingStart(self.imageFile.sensingStart)
        self.frame.setSensingStop(self.imageFile.sensingStop)
        sensingMid = self.imageFile.sensingStart + datetime.timedelta(
            seconds=0.5 * (self.imageFile.sensingStop -
                           self.imageFile.sensingStart).total_seconds())
        self.frame.setSensingMid(sensingMid)

        self.frame.setStartingRange(self.imageFile.nearRange)
        self.frame.setFarRange(self.imageFile.farRange)
        #        self.doppler_coeff = self.imageFile.dopplerCoeff
        self.frame.getInstrument().setPulseRepetitionFrequency(
            self.imageFile.prf)

        pol = self.TxPolMap[int(
            self.imageFile.polarization[0])] + self.TxPolMap[int(
                self.imageFile.polarization[1])]
        self.frame.setPolarization(pol)

        rawImage = isceobj.createSlcImage()
        rawImage.setByteOrder('l')
        rawImage.setAccessMode('read')
        rawImage.setFilename(self.output)
        rawImage.setWidth(self.imageFile.width)
        rawImage.setXmin(0)
        rawImage.setXmax(self.imageFile.width)
        rawImage.renderHdr()
        self.frame.setImage(rawImage)

        return

    def extractDoppler(self):
        '''
        Evaluate the doppler polynomial and return the average value for now.
        '''

        ####For insarApp

        quadratic = {}
        quadratic['a'] = self.doppler_coeff[0] / self.frame.getInstrument(
        ).getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.

        ###For roiApp
        ###More accurate
        self.frame._dopplerVsPixel = self.doppler_coeff

        return quadratic

    def _decodeSceneReferenceNumber(self, referenceNumber):
        return referenceNumber
Esempio n. 20
0
class ERS_EnviSAT_SLC(Sensor):

    parameter_list = (ORBIT_TYPE,
                      ORBIT_DIRECTORY,
                      ORBITFILE,
                      IMAGEFILE)           + Sensor.parameter_list

    """
        A Class for parsing ERS instrument and imagery files (Envisat format)
    """

    family = 'ers'
    logging_name = 'isce.sensor.ers_envisat_slc'

    def __init__(self,family='',name=''):
        super(ERS_EnviSAT_SLC, self).__init__(family if family else  self.__class__.family, name=name)
        self._imageFile = None
        #self._instrumentFileData = None #none for ERS
        self._imageryFileData = None
        self.dopplerRangeTime = None
        self.rangeRefTime = None
        self.logger = logging.getLogger("isce.sensor.ERS_EnviSAT_SLC")
        self.frame = None
        self.frameList = []

        #NOTE: copied from ERS_SLC.py... only antennaLength used? -SH
        # Constants are from
        # J. J. Mohr and S. N. Madsen. Geometric calibration of ERS satellite
        # SAR images. IEEE T. Geosci. Remote, 39(4):842-850, Apr. 2001.
        self.constants = {'polarization': 'VV',
                          'antennaLength': 10,
                          'lookDirection': 'RIGHT',
                          'chirpPulseBandwidth': 15.50829e6,
                          'rangeSamplingRate': 18.962468e6,
                          'delayTime':6.622e-6,
                          'iBias': 15.5,
                          'qBias': 15.5}


    def getFrame(self):
        return self.frame

    def parse(self):
        """
            Parse both imagery and create
            objects representing the platform, instrument and scene
        """

        self.frame = Frame()
        self.frame.configure()

        self._imageFile = ImageryFile(fileName=self._imageFileName)
        self._imageryFileData = self._imageFile.parse()

        self.populateMetadata()

    def populateMetadata(self):

        self._populatePlatform()
        self._populateInstrument()
        self._populateFrame()
        #self._populateOrbit()
        if (self._orbitType == 'ODR'):
            self._populateDelftOrbits()
        elif (self._orbitType == 'PRC'):
            self._populatePRCOrbits()
        elif (self._orbitType == 'PDS'):
            self._populatePDSOrbits()
        #else:
        #    self._populateHeaderOrbit() #NOTE: No leader file
        #NOTE: remove?
        self.dopplerRangeTime = self._imageryFileData['doppler']
        self.rangeRefTime = self._imageryFileData['dopplerOrigin'][0] * 1.0e-9
#        print('Doppler confidence: ', 100.0 * self._imageryFileData['dopplerConfidence'][0])

    def _populatePlatform(self):
        """Populate the platform object with metadata"""
        platform = self.frame.getInstrument().getPlatform()

        # Populate the Platform and Scene objects
        platform.setMission("ERS")
        platform.setPointingDirection(-1)
        platform.setAntennaLength(self.constants['antennaLength'])
        platform.setPlanet(Planet(pname="Earth"))

    def _populateInstrument(self):
        """Populate the instrument object with metadata"""
        instrument = self.frame.getInstrument()

        rangeSampleSpacing = Const.c/(2*self._imageryFileData['rangeSamplingRate'])
        pri = self._imageryFileData['pri']


        ####These shouldnt matter for SLC data since data is already focused.
        txPulseLength = 512 / 19207680.000000
        chirpPulseBandwidth = 16.0e6
        chirpSlope = chirpPulseBandwidth/txPulseLength

        instrument.setRangePixelSize(rangeSampleSpacing)
        instrument.setPulseLength(txPulseLength)
        #instrument.setSwath(imageryFileData['SWATH'])
        instrument.setRadarFrequency(self._imageryFileData['radarFrequency'])
        instrument.setChirpSlope(chirpSlope)
        instrument.setRangeSamplingRate(self._imageryFileData['rangeSamplingRate'])
        instrument.setPulseRepetitionFrequency(1.0/pri)
        #instrument.setRangeBias(rangeBias)
        instrument.setInPhaseValue(self.constants['iBias'])
        instrument.setQuadratureValue(self.constants['qBias'])

    def _populateFrame(self):
        """Populate the scene object with metadata"""
        numberOfLines = self._imageryFileData['numLines']
        numberOfSamples = self._imageryFileData['numSamples']
        pri = self._imageryFileData['pri']
        startingRange = Const.c * float(self._imageryFileData['timeToFirstSample']) * 1.0e-9 / 2.0
        rangeSampleSpacing = Const.c/(2*self._imageryFileData['rangeSamplingRate'])
        farRange = startingRange + numberOfSamples*rangeSampleSpacing
        first_line_utc = datetime.datetime.strptime(self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f')
        center_line_utc = datetime.datetime.strptime(self._imageryFileData['FIRST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f')
        last_line_utc = datetime.datetime.strptime(self._imageryFileData['LAST_LINE_TIME'], '%d-%b-%Y %H:%M:%S.%f')
        centerTime = DTUtil.timeDeltaToSeconds(last_line_utc-first_line_utc)/2.0
        center_line_utc = center_line_utc + datetime.timedelta(microseconds=int(centerTime*1e6))

        self.frame.setStartingRange(startingRange)
        self.frame.setFarRange(farRange)
        self.frame.setProcessingFacility(self._imageryFileData['PROC_CENTER'])
        self.frame.setProcessingSystem(self._imageryFileData['SOFTWARE_VER'])
        self.frame.setTrackNumber(int(self._imageryFileData['REL_ORBIT']))
        self.frame.setOrbitNumber(int(self._imageryFileData['ABS_ORBIT']))
        self.frame.setPolarization(self._imageryFileData['MDS1_TX_RX_POLAR'])
        self.frame.setNumberOfSamples(numberOfSamples)
        self.frame.setNumberOfLines(numberOfLines)
        self.frame.setSensingStart(first_line_utc)
        self.frame.setSensingMid(center_line_utc)
        self.frame.setSensingStop(last_line_utc)

    def _populateDelftOrbits(self):
        """Populate an orbit object with the Delft orbits"""
        from isceobj.Orbit.ODR import ODR, Arclist
        self.logger.info("Using Delft Orbits")
        arclist = Arclist(os.path.join(self._orbitDir,'arclist'))
        arclist.parse()
        print(self.frame.getSensingStart())
        print(arclist)
        orbitFile = arclist.getOrbitFile(self.frame.getSensingStart())
        #print(orbitFile)
        odr = ODR(file=os.path.join(self._orbitDir,orbitFile))


        startTimePreInterp = self.frame.getSensingStart() - datetime.timedelta(minutes=60)
        stopTimePreInterp = self.frame.getSensingStop() + datetime.timedelta(minutes=60)
        odr.parseHeader(startTimePreInterp,stopTimePreInterp)
        startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5)
        stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5)
        self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime))
        orbit = odr.trimOrbit(startTime,stopTime)
        self.frame.setOrbit(orbit)

    def _populatePRCOrbits(self):
        """Populate an orbit object the D-PAF PRC orbits"""
        from isceobj.Orbit.PRC import PRC, Arclist
        self.logger.info("Using PRC Orbits")
        arclist = Arclist(os.path.join(self._orbitDir,'arclist'))
        arclist.parse()
        orbitFile = arclist.getOrbitFile(self.frame.getSensingStart())
        self.logger.debug("Using file %s" % (orbitFile))
        prc = PRC(file=os.path.join(self._orbitDir,orbitFile))
        prc.parse()
        startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5)
        stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5)
        self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime))
        fullOrbit = prc.getOrbit()
        orbit = fullOrbit.trimOrbit(startTime,stopTime)
        self.frame.setOrbit(orbit)

    def _populatePDSOrbits(self):
        """
        Populate an orbit object using the ERS-2 PDS format
        """
        from isceobj.Orbit.PDS import PDS
        self.logger.info("Using PDS Orbits")
        pds = PDS(file=self._orbitFile)
        pds.parse()
        startTime = self.frame.getSensingStart() - datetime.timedelta(minutes=5)
        stopTime = self.frame.getSensingStop() + datetime.timedelta(minutes=5)
        self.logger.debug("Extracting orbits between %s and %s" % (startTime,stopTime))
        fullOrbit = pds.getOrbit()
        orbit = fullOrbit.trimOrbit(startTime,stopTime)
        self.frame.setOrbit(orbit)


    def _populateImage(self,outname,width,length):

        #farRange = self.frame.getStartingRange() + width*self.frame.getInstrument().getRangeSamplingRate()
        # Update the NumberOfSamples and NumberOfLines in the Frame object
        self.frame.setNumberOfSamples(width)
        self.frame.setNumberOfLines(length)
        #self.frame.setFarRange(farRange)
        # Create a RawImage object
        rawImage = createSlcImage()
        rawImage.setFilename(outname)
        rawImage.setAccessMode('read')
        rawImage.setByteOrder('l')
        rawImage.setXmin(0)
        rawImage.setXmax(width)
        rawImage.setWidth(width)
        self.frame.setImage(rawImage)

    def extractImage(self):
        from datetime import datetime as dt
        import tempfile as tf

        self.parse()
        width = self._imageryFileData['numSamples']
        length = self._imageryFileData['numLines']
        self._imageFile.extractImage(self.output, width, length)
        self._populateImage(self.output, width, length)

        pass



    def extractDoppler(self):
        """
        Return the doppler centroid as defined in the ASAR file.
        """
        quadratic = {}

        r0 = self.frame.getStartingRange()
        dr = self.frame.instrument.getRangePixelSize()
        width = self.frame.getNumberOfSamples()

        midr = r0 + (width/2.0) * dr
        midtime = 2 * midr/ Const.c - self.rangeRefTime

        fd_mid = 0.0
        tpow = midtime
        for kk in self.dopplerRangeTime:
            fd_mid += kk * tpow
            tpow *= midtime


        ####For insarApp
        quadratic['a'] = fd_mid/self.frame.getInstrument().getPulseRepetitionFrequency()
        quadratic['b'] = 0.
        quadratic['c'] = 0.

        
        ####For roiApp
        ####More accurate
        from isceobj.Util import Poly1D
        
        coeffs = self.dopplerRangeTime
        dr = self.frame.getInstrument().getRangePixelSize()
        rref = 0.5 * Const.c * self.rangeRefTime 
        r0 = self.frame.getStartingRange()
        norm = 0.5*Const.c/dr

        dcoeffs = []
        for ind, val in enumerate(coeffs):
            dcoeffs.append( val / (norm**ind))


        poly = Poly1D.Poly1D()
        poly.initPoly(order=len(coeffs)-1)
        poly.setMean( (rref - r0)/dr - 1.0)
        poly.setCoeffs(dcoeffs)


        pix = np.linspace(0, self.frame.getNumberOfSamples(), num=len(coeffs)+1)
        evals = poly(pix)
        fit = np.polyfit(pix,evals, len(coeffs)-1)
        self.frame._dopplerVsPixel = list(fit[::-1])
        print('Doppler Fit: ', fit[::-1])


        return quadratic
Esempio n. 21
0
class Track(object):
    """A class to represent a collection of temporally continuous radar frame
    objects"""

    logging_name = "isce.Scene.Track"

    @logged
    def __init__(self):
        # These are attributes representing the starting time and stopping
        # time of the track
        # As well as the early and late times (range times) of the track
        self._startTime = datetime.datetime(year=datetime.MAXYEAR,
                                            month=1,
                                            day=1)
        self._stopTime = datetime.datetime(year=datetime.MINYEAR,
                                           month=1,
                                           day=1)
        # Hopefully this number is large
        # enough, Python doesn't appear to have a MAX_FLT variable
        self._nearRange = float_info.max
        self._farRange = 0.0
        self._frames = []
        self._frame = Frame()
        self._lastFile = ''
        return None

    def combineFrames(self, output, frames):
        attitudeOk = True
        for frame in frames:
            self.addFrame(frame)
            if hasattr(frame, '_attitude'):
                att = frame.getAttitude()
                if not att:
                    attitudeOk = False
        self.createInstrument()
        self.createTrack(output)
        self.createOrbit()
        if attitudeOk:
            self.createAttitude()
        return self._frame

    def createAuxFile(self, fileList, output):
        import struct
        from operator import itemgetter
        import os
        import array
        import copy
        dateIndx = []
        cnt = 0
        #first sort the files from earlier to latest. use the first element
        for name in fileList:
            with open(name, 'rb') as fp:
                date = fp.read(16)
            day, musec = struct.unpack('<dd', date)
            dateIndx.append([day, musec, name])
            cnt += 1
        sortedDate = sorted(dateIndx, key=itemgetter(0, 1))

        #we need to make sure that there are not duplicate points in the orbit since some frames overlap
        allL = array.array('d')
        allL1 = array.array('d')
        name = sortedDate[0][2]
        size = os.path.getsize(name) // 8
        with open(name, 'rb') as fp1:
            allL.fromfile(fp1, size)
        lastDay = allL[-2]
        lastMusec = allL[-1]
        for j in range(1, len(sortedDate)):
            name = sortedDate[j][2]
            size = os.path.getsize(name) // 8
            with open(name, 'rb') as fp1:
                allL1.fromfile(fp1, size)
            indxFound = None
            avgPRI = 0
            cnt = 0
            for i in range(len(allL1) // 2):
                if i > 0:
                    avgPRI += allL1[2 * i + 1] - allL1[2 * i - 1]
                    cnt += 1
                if allL1[2 * i] >= lastDay and allL1[2 * i + 1] > lastMusec:
                    avgPRI //= (cnt - 1)
                    if (
                            allL1[2 * i + 1] - lastMusec
                    ) > avgPRI / 2:  # make sure that the distance in pulse is atleast 1/2 PRI
                        indxFound = 2 * i
                    else:  #if not take the next
                        indxFound = 2 * (i + 1)
                        pass
                    break
            if not indxFound is None:
                allL.extend(allL1[indxFound:])
                lastDay = allL[-2]
                lastMusec = allL[-1]
                pass
            pass
        with open(output, 'wb') as fp:
            allL.tofile(fp)
        return

    # Add an additional Frame object to the track
    @type_check(Frame)
    def addFrame(self, frame):
        self.logger.info("Adding Frame to Track")
        self._updateTrackTimes(frame)
        self._frames.append(frame)
        return None

    def createOrbit(self):
        orbitAll = Orbit()
        for i in range(len(self._frames)):
            orbit = self._frames[i].getOrbit()
            #remember that everything is by reference, so the changes applied to orbitAll will be made to the Orbit
            #object in self.frame
            for sv in orbit._stateVectors:
                orbitAll.addStateVector(sv)
            # sort the orbit state vecotrs according to time
            orbitAll._stateVectors.sort(key=lambda sv: sv.time)
        self.removeDuplicateVectors(orbitAll._stateVectors)
        self._frame.setOrbit(orbitAll)

    def removeDuplicateVectors(self, stateVectors):
        i1 = 0
        #remove duplicate state vectors
        while True:
            if i1 >= len(stateVectors) - 1:
                break
            if stateVectors[i1].time == stateVectors[i1 + 1].time:
                stateVectors.pop(i1 + 1)
            #since is sorted by time if is not equal we can pass to the next
            else:
                i1 += 1

    def createAttitude(self):
        attitudeAll = Attitude()
        for i in range(len(self._frames)):
            attitude = self._frames[i].getAttitude()
            #remember that everything is by reference, so the changes applied to attitudeAll will be made to the Attitude object in self.frame
            for sv in attitude._stateVectors:
                attitudeAll.addStateVector(sv)
            # sort the attitude state vecotrs according to time
            attitudeAll._stateVectors.sort(key=lambda sv: sv.time)
        self.removeDuplicateVectors(attitudeAll._stateVectors)
        self._frame.setAttitude(attitudeAll)

    def createInstrument(self):
        # the platform is already part of the instrument
        ins = self._frames[0].getInstrument()
        self._frame.setInstrument(ins)

    # sometime the startLine computed below from the sensingStart is not
    #precise and the image are missaligned.
    #for each pair do an exact mach by comparing the lines around lineStart
    #file1,2 input files, startLine1 is the estimated start line in the first file
    #line1 = last line used in the first file
    #width = width of the files
    #frameNum1,2 number of the frames in the sequence of frames to stitch
    #returns a more accurate line1
    def findOverlapLine(self, file1, file2, line1, width, frameNum1,
                        frameNum2):
        import numpy as np
        import array
        fin2 = open(file2, 'rb')
        arr2 = array.array('b')
        #read full line at the beginning of second file
        arr2.fromfile(fin2, width)
        buf2 = np.array(arr2, dtype=np.int8)
        numTries = 30
        # start around line1 and try numTries around line1
        # see searchlist to see which lines it searches
        searchNumLines = 2
        #make a sliding window that search for the searchSize samples inside buf2
        searchSize = 500
        max = 0
        indx = None
        fin1 = open(file1, 'rb')
        for i in range(numTries):
            # example line1 = 0,searchNumLine = 2 and i = 0 search = [-2,-1,0,1], i = 1, serach =  [-4,-3,2,3]
            search = list(
                range(line1 - (i + 1) * searchNumLines,
                      line1 - i * searchNumLines))
            search.extend(
                list(
                    range(line1 + i * searchNumLines,
                          line1 + (i + 1) * searchNumLines)))
            for k in search:
                arr1 = array.array('b')
                #seek to the line k and read +- searchSize/2 samples from the middle of the line
                fin1.seek(k * width + (width - searchSize) // 2, 0)
                arr1.fromfile(fin1, searchSize)
                buf1 = np.array(arr1, dtype=np.int8)
                found = False
                for i in np.arange(width - searchSize):
                    lenSame = len(
                        np.nonzero(buf1 == buf2[i:i + searchSize])[0])
                    if lenSame > max:
                        max = lenSame
                        indx = k
                        if (lenSame == searchSize):
                            found = True
                            break
                if (found):
                    break
            if (found):
                break
        if not found:
            self.logger.warning(
                "Cannot find perfect overlap between frame %d and frame %d. Using acquisition time to find overlap position."
                % (frameNum1, frameNum2))
        fin1.close()
        fin2.close()
        print('Match found: ', indx)
        return indx

    def reAdjustStartLine(self, sortedList, width):
        """ Computed the adjusted starting lines based on matching in overlapping regions """
        from operator import itemgetter
        import os

        #first one always starts from zero
        startLine = [sortedList[0][0]]
        outputs = [sortedList[0][1]]
        for i in range(1, len(sortedList)):
            # endLine of the first file. we use all the lines of the first file up to endLine
            endLine = sortedList[i][0] - sortedList[i - 1][0]
            indx = self.findOverlapLine(sortedList[i - 1][1], sortedList[i][1],
                                        endLine, width, i - 1, i)
            #if indx is not None than indx is the new start line
            #otherwise we use startLine  computed from acquisition time
            if (indx is not None) and (indx + sortedList[i - 1][0] !=
                                       sortedList[i][0]):
                startLine.append(indx + sortedList[i - 1][0])
                outputs.append(sortedList[i][1])
                self.logger.info(
                    "Changing starting line for frame %d from %d to %d" %
                    (i, endLine, indx))
            else:
                startLine.append(sortedList[i][0])
                outputs.append(sortedList[i][1])

        return startLine, outputs

    # Create the actual Track data by concatenating data from
    # all of the Frames objects together
    def createTrack(self, output):
        import os
        from operator import itemgetter
        from isceobj import Constants as CN
        from ctypes import cdll, c_char_p, c_int, c_ubyte, byref
        lib = cdll.LoadLibrary(os.path.dirname(__file__) + '/concatenate.so')
        # Perhaps we should check to see if Xmin is 0, if it is not, strip off the header
        self.logger.info(
            "Adjusting Sampling Window Start Times for all Frames")
        # Iterate over each frame object, and calculate the number of samples with which to pad it on the left and right
        outputs = []
        totalWidth = 0
        auxList = []
        for frame in self._frames:
            # Calculate the amount of padding
            thisNearRange = frame.getStartingRange()
            thisFarRange = frame.getFarRange()
            left_pad = int(
                round((thisNearRange - self._nearRange) *
                      frame.getInstrument().getRangeSamplingRate() /
                      (CN.SPEED_OF_LIGHT / 2.0))) * 2
            right_pad = int(
                round((self._farRange - thisFarRange) *
                      frame.getInstrument().getRangeSamplingRate() /
                      (CN.SPEED_OF_LIGHT / 2.0))) * 2
            width = frame.getImage().getXmax()
            if width - int(width) != 0:
                raise ValueError("frame Xmax is not an integer")
            else:
                width = int(width)

            input = frame.getImage().getFilename()
            #            tempOutput = os.path.basename(os.tmpnam()) # Some temporary filename
            with tempfile.NamedTemporaryFile(dir='.') as f:
                tempOutput = f.name

            pad_value = int(frame.getInstrument().getInPhaseValue())

            if totalWidth < left_pad + width + right_pad:
                totalWidth = left_pad + width + right_pad
            # Resample this frame with swst_resample
            input_c = c_char_p(bytes(input, 'utf-8'))
            output_c = c_char_p(bytes(tempOutput, 'utf-8'))
            width_c = c_int(width)
            left_pad_c = c_int(left_pad)
            right_pad_c = c_int(right_pad)
            pad_value_c = c_ubyte(pad_value)
            lib.swst_resample(input_c, output_c, byref(width_c),
                              byref(left_pad_c), byref(right_pad_c),
                              byref(pad_value_c))
            outputs.append(tempOutput)
            auxList.append(frame.auxFile)

        #this step construct the aux file withe the pulsetime info for the all set of frames
        self.createAuxFile(auxList, output + '.aux')
        # This assumes that all of the frames to be concatenated are sampled at the same PRI
        prf = self._frames[0].getInstrument().getPulseRepetitionFrequency()
        # Calculate the starting output line of each scene
        i = 0
        lineSort = []
        # the listSort has 2 elements: a line start number which is the position of that specific frame
        # computed from acquisition time and the  corresponding file name
        for frame in self._frames:
            startLine = int(
                round(
                    DTU.timeDeltaToSeconds(frame.getSensingStart() -
                                           self._startTime) * prf))
            lineSort.append([startLine, outputs[i]])
            i += 1

        sortedList = sorted(
            lineSort,
            key=itemgetter(0))  # sort by line number i.e. acquisition time
        startLines, outputs = self.reAdjustStartLine(sortedList, totalWidth)

        self.logger.info("Concatenating Frames along Track")
        # this is a hack since the length of the file could be actually different from the one computed using start and stop time. it only matters the last frame added
        import os

        fileSize = os.path.getsize(outputs[-1])

        numLines = fileSize // totalWidth + startLines[-1]
        totalLines_c = c_int(numLines)
        # Next, call frame_concatenate
        width_c = c_int(
            totalWidth
        )  # Width of each frame (with the padding added in swst_resample)
        numberOfFrames_c = c_int(len(self._frames))
        inputs_c = (c_char_p * len(outputs))(
        )  # These are the inputs to frame_concatenate, but the outputs from swst_resample
        for kk in range(len(outputs)):
            inputs_c[kk] = bytes(outputs[kk], 'utf-8')
        output_c = c_char_p(bytes(output, 'utf-8'))
        startLines_c = (c_int * len(startLines))()
        startLines_c[:] = startLines
        lib.frame_concatenate(output_c, byref(width_c), byref(totalLines_c),
                              byref(numberOfFrames_c), inputs_c, startLines_c)

        # Clean up the temporary output files from swst_resample
        for file in outputs:
            os.unlink(file)

        orbitNum = self._frames[0].getOrbitNumber()
        first_line_utc = self._startTime
        last_line_utc = self._stopTime
        centerTime = DTU.timeDeltaToSeconds(last_line_utc -
                                            first_line_utc) / 2.0
        center_line_utc = first_line_utc + datetime.timedelta(
            microseconds=int(centerTime * 1e6))
        procFac = self._frames[0].getProcessingFacility()
        procSys = self._frames[0].getProcessingSystem()
        procSoft = self._frames[0].getProcessingSoftwareVersion()
        pol = self._frames[0].getPolarization()
        xmin = self._frames[0].getImage().getXmin()

        self._frame.setOrbitNumber(orbitNum)
        self._frame.setSensingStart(first_line_utc)
        self._frame.setSensingMid(center_line_utc)
        self._frame.setSensingStop(last_line_utc)
        self._frame.setStartingRange(self._nearRange)
        self._frame.setFarRange(self._farRange)
        self._frame.setProcessingFacility(procFac)
        self._frame.setProcessingSystem(procSys)
        self._frame.setProcessingSoftwareVersion(procSoft)
        self._frame.setPolarization(pol)
        self._frame.setNumberOfLines(numLines)
        self._frame.setNumberOfSamples(width)
        # add image to frame
        rawImage = isceobj.createRawImage()
        rawImage.setByteOrder('l')
        rawImage.setFilename(output)
        rawImage.setAccessMode('r')
        rawImage.setWidth(totalWidth)
        rawImage.setXmax(totalWidth)
        rawImage.setXmin(xmin)
        self._frame.setImage(rawImage)

    # Extract the early, late, start and stop times from a Frame object
    # And use this information to update
    def _updateTrackTimes(self, frame):

        if (frame.getSensingStart() < self._startTime):
            self._startTime = frame.getSensingStart()
        if (frame.getSensingStop() > self._stopTime):
            self._stopTime = frame.getSensingStop()
        if (frame.getStartingRange() < self._nearRange):
            self._nearRange = frame.getStartingRange()
        if (frame.getFarRange() > self._farRange):
            self._farRange = frame.getFarRange()
            pass
        pass

    pass
Esempio n. 22
0
class ICEYE_SLC(Sensor):
    """
    A class representing a Level1Product meta data.
    Level1Product(hdf5=h5filename) will parse the hdf5
    file and produce an object with attributes for metadata.
    """
    parameter_list = (HDF5, APPLY_SLANT_RANGE_PHASE) + Sensor.parameter_list
    logging_name = 'isce.Sensor.ICEYE_SLC'
    family = 'iceye_slc'

    def __init__(self, family='', name=''):
        super(ICEYE_SLC,
              self).__init__(family if family else self.__class__.family,
                             name=name)
        self.frame = Frame()
        self.frame.configure()
        # Some extra processing parameters unique to CSK SLC (currently)
        self.dopplerRangeTime = []
        self.dopplerAzimuthTime = []
        self.azimuthRefTime = None
        self.rangeRefTime = None
        self.rangeFirstTime = None
        self.rangeLastTime = None

        self.lookMap = {'RIGHT': -1, 'LEFT': 1}
        return

    def __getstate__(self):
        d = dict(self.__dict__)
        del d['logger']
        return d

    def __setstate__(self, d):
        self.__dict__.update(d)
        self.logger = logging.getLogger('isce.Sensor.ICEYE_SLC')
        return

    def getFrame(self):
        return self.frame

    def parse(self):
        try:
            fp = h5py.File(self.hdf5, 'r')
        except Exception as strerr:
            self.logger.error("IOError: %s" % strerr)
            return None

        self.populateMetadata(fp)
        fp.close()

    def populateMetadata(self, file):
        """
            Populate our Metadata objects
        """

        self._populatePlatform(file)
        self._populateInstrument(file)
        self._populateFrame(file)
        self._populateOrbit(file)
        self._populateExtras(file)

    def _populatePlatform(self, file):
        platform = self.frame.getInstrument().getPlatform()

        platform.setMission(file['satellite_name'][()])
        platform.setPointingDirection(
            self.lookMap[file['look_side'][()].upper()])
        platform.setPlanet(Planet(pname="Earth"))

        ####This is an approximation for spotlight mode
        ####In spotlight mode, antenna length changes with azimuth position
        platform.setAntennaLength(2 * file['azimuth_ground_spacing'][()])

        assert (file['range_looks'][()] == 1)
        assert (file['azimuth_looks'][()] == 1)

    def _populateInstrument(self, file):
        instrument = self.frame.getInstrument()

        rangePixelSize = file['slant_range_spacing'][()]
        instrument.setRadarWavelength(Const.c / file['carrier_frequency'][()])
        instrument.setPulseRepetitionFrequency(file['processing_prf'][()])
        instrument.setRangePixelSize(rangePixelSize)
        instrument.setPulseLength(file['chirp_duration'][()])
        instrument.setChirpSlope(file['chirp_bandwidth'][()] /
                                 file['chirp_duration'][()])
        instrument.setRangeSamplingRate(file['range_sampling_rate'][()])

        incangle = file['local_incidence_angle']
        instrument.setIncidenceAngle(incangle[incangle.size // 2])

    def _populateFrame(self, file):

        rft = file['first_pixel_time'][()]
        slantRange = rft * Const.c / 2.0
        self.frame.setStartingRange(slantRange)

        sensingStart = datetime.datetime.strptime(
            file['zerodoppler_start_utc'][()].decode('utf-8'),
            '%Y-%m-%dT%H:%M:%S.%f')
        sensingStop = datetime.datetime.strptime(
            file['zerodoppler_end_utc'][()].decode('utf-8'),
            '%Y-%m-%dT%H:%M:%S.%f')
        sensingMid = sensingStart + 0.5 * (sensingStop - sensingStart)

        self.frame.setPassDirection(file['orbit_direction'][()])
        self.frame.setOrbitNumber(file['orbit_absolute_number'][()])
        self.frame.setProcessingFacility('ICEYE')
        self.frame.setProcessingSoftwareVersion(
            str(file['processor_version'][()]))
        self.frame.setPolarization(file['polarization'][()])
        self.frame.setNumberOfLines(file['number_of_azimuth_samples'][()])
        self.frame.setNumberOfSamples(file['number_of_range_samples'][()])
        self.frame.setSensingStart(sensingStart)
        self.frame.setSensingMid(sensingMid)
        self.frame.setSensingStop(sensingStop)

        rangePixelSize = self.frame.getInstrument().getRangePixelSize()
        farRange = slantRange + (self.frame.getNumberOfSamples() -
                                 1) * rangePixelSize
        self.frame.setFarRange(farRange)

    def _populateOrbit(self, file):
        import numpy as np
        orbit = self.frame.getOrbit()

        orbit.setReferenceFrame('ECR')
        orbit.setOrbitSource('Header')
        t = file['state_vector_time_utc'][:]
        position = np.zeros((t.size, 3))
        position[:, 0] = file['posX'][:]
        position[:, 1] = file['posY'][:]
        position[:, 2] = file['posZ'][:]

        velocity = np.zeros((t.size, 3))
        velocity[:, 0] = file['velX'][:]
        velocity[:, 1] = file['velY'][:]
        velocity[:, 2] = file['velZ'][:]

        for ii in range(t.size):
            vec = StateVector()
            vec.setTime(
                datetime.datetime.strptime(t[ii][0].decode('utf-8'),
                                           '%Y-%m-%dT%H:%M:%S.%f'))
            vec.setPosition(
                [position[ii, 0], position[ii, 1], position[ii, 2]])
            vec.setVelocity(
                [velocity[ii, 0], velocity[ii, 1], velocity[ii, 2]])
            orbit.addStateVector(vec)

    def _populateExtras(self, file):
        """
        Populate some of the extra fields unique to processing TSX data.
        In the future, other sensors may need this information as well,
        and a re-organization may be necessary.
        """
        import numpy as np
        self.dcpoly = np.mean(file['dc_estimate_coeffs'][:], axis=0)

    def extractImage(self):
        import numpy as np
        import h5py

        self.parse()

        fid = h5py.File(self.hdf5, 'r')

        si = fid['s_i']
        sq = fid['s_q']

        nLines = si.shape[0]
        spectralShift = 2 * self.frame.getInstrument().getRangePixelSize(
        ) / self.frame.getInstrument().getRadarWavelength()
        spectralShift -= np.floor(spectralShift)
        phsShift = np.exp(-1j * 2 * np.pi * spectralShift *
                          np.arange(si.shape[1]))
        with open(self.output, 'wb') as fout:
            for ii in range(nLines):
                line = (si[ii, :] + 1j * sq[ii, :])
                if self.applySlantRangePhase:
                    line *= phsShift
                line.astype(np.complex64).tofile(fout)

        fid.close()

        slcImage = isceobj.createSlcImage()
        slcImage.setFilename(self.output)
        slcImage.setXmin(0)
        slcImage.setXmax(self.frame.getNumberOfSamples())
        slcImage.setWidth(self.frame.getNumberOfSamples())
        slcImage.setAccessMode('r')
        self.frame.setImage(slcImage)

    def extractDoppler(self):
        """
        Return the doppler centroid as defined in the HDF5 file.
        """
        import numpy as np

        quadratic = {}

        rangePixelSize = self.frame.getInstrument().getRangePixelSize()
        rt0 = self.frame.getStartingRange() / (2 * Const.c)
        rt1 = rt0 + ((self.frame.getNumberOfSamples() - 1) *
                     rangePixelSize) / (2 * Const.c)

        ####insarApp style
        quadratic['a'] = np.polyval(self.dcpoly, 0.5 *
                                    (rt0 + rt1)) / self.frame.PRF
        quadratic['b'] = 0.
        quadratic['c'] = 0.

        ####For roiApp more accurate
        ####Convert stuff to pixel wise coefficients
        x = np.linspace(rt0, rt1, num=len(self.dcpoly) + 1)
        pix = np.linspace(0,
                          self.frame.getNumberOfSamples(),
                          num=len(self.dcpoly) + 1)
        evals = np.polyval(self.dcpoly, x)
        fit = np.polyfit(pix, evals, len(self.dcpoly) - 1)
        self.frame._dopplerVsPixel = list(fit[::-1])
        print('Doppler Fit: ', self.frame._dopplerVsPixel)

        return quadratic