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
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
Beispiel #3
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
Beispiel #4
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
Beispiel #5
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
Beispiel #6
0
class UAVSAR_RPI(Sensor):
    """
    A class representing a UAVSAR SLC.
    """

    family = 'uavsar_rpi'
    logging_name = 'isce.Sensor.UAVSAR_RPI'
    lookMap = {'RIGHT': -1, 'LEFT': 1}

    parameter_list = (METADATAFILE, ) + Sensor.parameter_list

    def __init__(self, name=''):
        #        print("UAVSAR_RPI: self.family, name = ", self.family, name)
        super().__init__(family=self.family, name=name)
        self.frame = Frame()
        self.frame.configure()
        return

    def _populatePlatform(self, **kwargs):
        #        print("UAVSAR_RPI._populatePlatform")
        platform = self.frame.getInstrument().getPlatform()
        platform.setMission('UAVSAR')
        platform.setPointingDirection(
            self.lookMap[self.metadata['Radar Look Direction'].upper()])
        platform.setPlanet(Planet(pname="Earth"))
        platform.setAntennaLength(1.5)  # Thierry Michel
        return

    def _populateInstrument(self, **kwargs):
        #        print("UAVSAR_RPI._populateInstrument")
        instrument = self.frame.getInstrument()
        instrument.setRadarWavelength(self.metadata['Center Wavelength'])
        fudgefactor = 1.0 / 1.0735059946800756
        instrument.setPulseRepetitionFrequency(
            fudgefactor * 1.0 /
            self.metadata['Average Pulse Repetition Interval'])
        #        print("instrument.getPulseRepetitionFrequency() = ",
        #            instrument.getPulseRepetitionFrequency(),
        #            type(instrument.getPulseRepetitionFrequency()))
        instrument.setRangePixelSize(
            self.metadata['Single Look Complex Data Range Spacing'])
        instrument.setAzimuthPixelSize(
            self.metadata['Single Look Complex Data Azimuth Spacing'])
        instrument.setPulseLength(self.metadata['Pulse Length'])
        instrument.setChirpSlope(-self.metadata['Bandwidth'] /
                                 self.metadata['Pulse Length'])
        from isceobj.Constants.Constants import SPEED_OF_LIGHT
        instrument.setRangeSamplingRate(SPEED_OF_LIGHT / 2.0 /
                                        instrument.getRangePixelSize())
        instrument.setIncidenceAngle(
            0.5 * (self.metadata['Average Look Angle in Near Range'] +
                   self.metadata['Average Look Angle in Far Range']))

        return

    def _populateFrame(self, **kwargs):
        #        print("UAVSAR_RPI._populateFrame")

        if self.metadata['UAVSAR RPI Annotation File Version Number']:
            #            print("UAVSAR_RPI._populateFrame, pair = True")
            if self.name.lower() == 'reference':
                sip1 = str(1)
            else:
                sip1 = str(2)
            print("UAVSAR_RPI._populateFrame, 1-based index = ", sip1)
            self._populateFrameFromPair(sip1)
        else:
            #            print("UAVSAR_RPI._populateFrame, pair = False")
            self._populateFrameSolo()

        pass

    def _populateFrameFromPair(self, sip1):
        #        print("UAVSAR_RPI._populateFrameFromPair: metadatafile = ",
        #            self.metadataFile)

        #Get the Start, Mid, and Stop times
        import datetime
        tStart = datetime.datetime.strptime(
            self.metadata['Start Time of Acquisition for Pass ' + sip1],
            "%d-%b-%Y %H:%M:%S %Z")
        tStop = datetime.datetime.strptime(
            self.metadata['Stop Time of Acquisition for Pass ' + sip1],
            "%d-%b-%Y %H:%M:%S %Z")
        dtMid = DTU.timeDeltaToSeconds(tStop - tStart) / 2.
        #        print("dtMid = ", dtMid)
        tMid = tStart + datetime.timedelta(microseconds=int(dtMid * 1e6))
        #        print("tStart = ", tStart)
        #        print("tMid   = ", tMid)
        #        print("tStop  = ", tStop)
        frame = self.frame
        frame.setSensingStart(tStart)
        frame.setSensingStop(tStop)
        frame.setSensingMid(tMid)
        frame.setNumberOfLines(
            int(self.metadata['Single Look Complex Data Azimuth Lines']))
        frame.setNumberOfSamples(
            int(self.metadata['Single Look Complex Data Range Samples']))
        frame.setPolarization(self.metadata['Polarization'])
        frame.C0 = self.metadata['Single Look Complex Data at Near Range']
        frame.S0 = self.metadata['Single Look Complex Data Starting Azimuth']
        frame.nearLookAngle = self.metadata['Average Look Angle in Near Range']
        frame.farLookAngle = self.metadata['Average Look Angle in Far Range']
        #        print("frame.nearLookAngle = ", math.degrees(frame.nearLookAngle))
        #        frame.setStartingAzimuth(frame.S0)
        self.extractDoppler()
        frame.setStartingRange(self.startingRange)
        frame.platformHeight = self.platformHeight
        #        print("platformHeight, startingRange = ", self.platformHeight, frame.getStartingRange())
        width = frame.getNumberOfSamples()
        deltaRange = frame.instrument.getRangePixelSize()
        nearRange = frame.getStartingRange()
        midRange = nearRange + (width / 2.) * deltaRange
        frame.setFarRange(nearRange + width * deltaRange)

        frame.peg = self.peg
        #        print("frame.peg = ", frame.peg)
        frame.procVelocity = self.velocity
        #        print("frame.procVelocity = ", frame.procVelocity)

        from isceobj.Location.Coordinate import Coordinate
        frame.terrainHeight = self.terrainHeight
        frame.upperLeftCorner = Coordinate()
        frame.upperLeftCorner.setLatitude(
            math.degrees(self.metadata['Approximate Upper Left Latitude']))
        frame.upperLeftCorner.setLongitude(
            math.degrees(self.metadata['Approximate Upper Left Longitude']))
        frame.upperLeftCorner.setHeight(self.terrainHeight)
        frame.upperRightCorner = Coordinate()
        frame.upperRightCorner.setLatitude(
            math.degrees(self.metadata['Approximate Upper Right Latitude']))
        frame.upperRightCorner.setLongitude(
            math.degrees(self.metadata['Approximate Upper Right Longitude']))
        frame.upperRightCorner.setHeight(self.terrainHeight)
        frame.lowerRightCorner = Coordinate()
        frame.lowerRightCorner.setLatitude(
            math.degrees(self.metadata['Approximate Lower Right Latitude']))
        frame.lowerRightCorner.setLongitude(
            math.degrees(self.metadata['Approximate Lower Right Longitude']))
        frame.lowerRightCorner.setHeight(self.terrainHeight)
        frame.lowerLeftCorner = Coordinate()
        frame.lowerLeftCorner.setLatitude(
            math.degrees(self.metadata['Approximate Lower Left Latitude']))
        frame.lowerLeftCorner.setLongitude(
            math.degrees(self.metadata['Approximate Lower Left Longitude']))
        frame.lowerLeftCorner.setHeight(self.terrainHeight)

        frame.nearLookAngle = math.degrees(
            self.metadata['Average Look Angle in Near Range'])
        frame.farLookAngle = math.degrees(
            self.metadata['Average Look Angle in Far Range'])

        return

    def _populateFrameSolo(self):
        print("UAVSAR_RPI._populateFrameSolo")

    def _populateExtras(self):
        pass

    def _populateOrbit(self, **kwargs):
        """
        Create the orbit as the reference orbit defined by the peg
        """
        #        print("UAVSAR_RPI._populateOrbit")
        numExtra = 10
        deltaFactor = 200
        dt = deltaFactor * 1.0 / self.frame.instrument.getPulseRepetitionFrequency(
        )
        t0 = (self.frame.getSensingStart() -
              datetime.timedelta(microseconds=int(numExtra * dt * 1e6)))
        ds = deltaFactor * self.frame.instrument.getAzimuthPixelSize()
        s0 = self.platformStartingAzimuth - numExtra * ds
        #        print("populateOrbit: t0, startingAzimuth, platformStartingAzimuth, s0, ds = ",
        #            t0, self.frame.S0, self.platformStartingAzimuth, s0, ds)
        h = self.platformHeight
        v = [self.velocity, 0., 0.]
        #        print("t0, dt = ", t0, dt)
        #        print("s0, ds, h = ", s0, ds, h)
        #        print("v = ", v[0])
        platform = self.frame.getInstrument().getPlatform()
        elp = platform.getPlanet().get_elp()
        elp.setSCH(self.peg.latitude, self.peg.longitude, self.peg.heading)
        orbit = self.frame.getOrbit()
        orbit.setOrbitSource('Header')
        #        print("_populateOrbit: self.frame.numberOfLines, numExtra = ", self.frame.getNumberOfLines(), numExtra)
        for i in range(self.frame.getNumberOfLines() + numExtra):
            vec = OrbitStateVector()
            t = t0 + datetime.timedelta(microseconds=int(i * dt * 1e6))
            vec.setTime(t)
            posSCH = [s0 + i * ds * (elp.pegRadCur + h) / elp.pegRadCur, 0., h]
            velSCH = v
            posXYZ, velXYZ = elp.schdot_to_xyzdot(posSCH, velSCH)
            vec.setPosition(posXYZ)
            vec.setVelocity(velXYZ)
            orbit.addStateVector(vec)
#            if i%1000 == 0 or i>self.frame.getNumberOfLines()+numExtra-3 or i < 3:
#                print("vec = ", vec)

        return

    def populateMetadata(self):
        self._populatePlatform()
        self._populateInstrument()
        self._populateFrame()
        #        self.extractDoppler()
        self._populateOrbit()

    def extractImage(self):
        from iscesys.Parsers import rdf
        self.metadata = rdf.parse(self.metadataFile)
        self.populateMetadata()

        slcImage = isceobj.createSlcImage()
        if self.name == 'reference' or self.name == 'scene1':
            self.slcname = self.metadata['Single Look Complex Data of Pass 1']
        elif self.name == 'secondary' or self.name == 'scene2':
            self.slcname = self.metadata['Single Look Complex Data of Pass 2']
        else:
            print("Unrecognized sensor.name = ", sensor.name)
            import sys
            sys.exit(0)
        slcImage.setFilename(self.slcname)
        slcImage.setXmin(0)
        slcImage.setXmax(self.frame.getNumberOfSamples())
        slcImage.setWidth(self.frame.getNumberOfSamples())
        slcImage.setAccessMode('r')
        self.frame.setImage(slcImage)
        return

    def extractDoppler(self):
        #        print("UAVSAR_RPI._extractDoppler")

        #Recast the Near, Mid, and Far Reskew Doppler values
        #into three RDF records because they were not parsed
        #correctly by the RDF parser; it was parsed as a string.
        #Use the RDF parser on the individual Doppler values to
        #do the unit conversion properly.

        #The units, and values parsed from the metadataFile
        key = "Reskew Doppler Near Mid Far"
        u = self.metadata.data[key].units.split(',')
        v = map(float, self.metadata.data[key].value.split())
        k = ["Reskew Doppler " + x for x in ("Near", "Mid", "Far")]

        #Use the interactive RDF accumulator to create an RDF object
        #for the near, mid, and far Doppler values
        from iscesys.Parsers.rdf import iRDF
        dop = iRDF.RDFAccumulator()
        for z in zip(k, u, v):
            dop("%s (%s) = %f" % z)

        self.dopplerVals = {}
        for r in dop.record_list:
            self.dopplerVals[r.key.split()[-1]] = r.field.value
        self.dopplerVals['Mid'] = self.dopplerVals['Mid']
        self.dopplerVals['Far'] = self.dopplerVals['Far']

        #        print("UAVSAR_RPI: dopplerVals = ", self.dopplerVals)

        #quadratic model using Near, Mid, Far range doppler values
        #UAVSAR has a subroutine to compute doppler values at each pixel
        #that should be used instead.
        frame = self.frame
        instrument = frame.getInstrument()
        width = frame.getNumberOfSamples()
        deltaRange = instrument.getRangePixelSize()
        nearRangeBin = 0.
        midRangeBin = float(int((width - 1.0) / 2.0))
        farRangeBin = width - 1.0

        import numpy
        A = numpy.matrix([[1.0, nearRangeBin, nearRangeBin**2],
                          [1.0, midRangeBin, midRangeBin**2],
                          [1.0, farRangeBin, farRangeBin**2]])
        d = numpy.matrix([
            self.dopplerVals['Near'], self.dopplerVals['Mid'],
            self.dopplerVals['Far']
        ]).transpose()
        coefs = (numpy.linalg.inv(A) * d).transpose().tolist()[0]
        prf = instrument.getPulseRepetitionFrequency()
        #        print("UAVSAR_RPI.extractDoppler: self.dopplerVals = ", self.dopplerVals)
        #        print("UAVSAR_RPI.extractDoppler: prf = ", prf)
        #        print("UAVSAR_RPI.extractDoppler: A, d = ", A, d)
        #        print("UAVSAR_RPI.extractDoppler: coefs = ", coefs)
        coefs = {'a': coefs[0] / prf, 'b': coefs[1] / prf, 'c': coefs[2] / prf}
        #        print("UAVSAR_RPI.extractDoppler: coefs normalized by prf = ", coefs)

        #Set the coefs in frame._dopplerVsPixel because that is where DefaultDopp looks for them
        self.frame._dopplerVsPixel = coefs

        return coefs

    @property
    def terrainHeight(self):
        return self.metadata['Global Average Terrain Height']

    @property
    def platformHeight(self):
        return self.metadata['Global Average Altitude']

    @property
    def platformStartingAzimuth(self):
        #        r, a = self.getStartingRangeAzimuth()
        #        return a
        h = self.platformHeight
        peg = self.peg
        platform = self.frame.getInstrument().getPlatform()
        elp = platform.getPlanet().get_elp()
        elp.setSCH(peg.latitude, peg.longitude, peg.heading)
        rc = elp.pegRadCur
        range = self.startingRange
        wavl = self.frame.getInstrument().getRadarWavelength()
        fd = self.dopplerVals['Near']
        v = self.velocity
        tanbeta = (fd * wavl / v) * range * (rc + h) / (range**2 -
                                                        (rc + h)**2 - rc**2)
        beta = math.atan(tanbeta)
        #        th = self.metadata['Global Average Terrain Height']
        #        sinTheta = math.sqrt( 1 - ((h-th)/range)**2 )
        #        squint = math.radians(self.squintAngle)
        #        c0 = self.startingRange*sinTheta*math.cos(squint)
        #        print("platformStartingAzimuth: c0 = ", c0)
        #        gamma = c0/rc
        #        cosbeta = -(range**2-(rc+h)**2-rc**2)/(2.*rc*(rc+h)*math.cos(gamma))
        #        sinbeta = -fd*range*wavl/(2.*rc*v*math.cos(gamma))
        #        beta = math.atan2(sinbeta,cosbeta)
        t = beta * (rc + h) / v
        pDS = v * t
        azimuth = self.frame.S0  #- pDS + 473.
        return azimuth

    @property
    def startingRange(self):
        #         r, a = self.getStartingRangeAzimuth()
        #         return r
        return self.metadata['Single Look Complex Data at Near Range']

    @property
    def squintAngle(self):
        """
        Update this to use the sphere rather than planar approximation.
        """
        startingRange = self.startingRange
        h = self.platformHeight
        v = self.velocity
        prf = self.frame.getInstrument().getPulseRepetitionFrequency()
        wavelength = self.frame.getInstrument().getRadarWavelength()

        if h > startingRange:
            raise ValueError("Spacecraft Height too large (%s>%s)" %
                             (h, startingRange))

        sinTheta = math.sqrt(1 - (h / startingRange)**2)
        fd = self.dopplerVals['Near']
        sinSquint = fd / (2.0 * v * sinTheta) * wavelength
        #        print("calculateSquint: h = ", h)
        #        print("calculateSquint: startingRange = ", startingRange)
        #        print("calculateSquint: sinTheta = ", sinTheta)
        #        print("calculateSquint: self.dopplerVals['Near'] = ", self.dopplerVals['Near'])
        #        print("calculateSquint: prf = ", prf)
        #        print("calculateSquint: fd = ", fd)
        #        print("calculateSquint: v = ", v)
        #        print("calculateSquint: wavelength = ", wavelength)
        #        print("calculateSquint: sinSquint = ", sinSquint)

        if sinSquint**2 > 1:
            raise ValueError(
                "Error in One or More of the Squint Calculation Values\n" +
                "Doppler Centroid: %s\nVelocity: %s\nWavelength: %s\n" %
                (fd, v, wavelength))
        self.squint = math.degrees(
            math.atan2(sinSquint, math.sqrt(1 - sinSquint**2)))
        #jng squint is also used later on from the frame, just add it here
        self.frame.squintAngle = math.radians(self.squint)
        #        print("UAVSAR_RPI: self.frame.squintAngle = ", self.frame.squintAngle)
        return self.squint

    def getStartingRangeAzimuth(self):
        peg = self.peg
        platform = self.frame.getInstrument().getPlatform()
        elp = platform.getPlanet().get_elp()
        elp.setSCH(peg.latitude, peg.longitude, peg.heading)
        rc = elp.pegRadCur
        #        assert(abs(rc-6370285.323386391) < 0.1)
        h = self.platformHeight
        #        assert(abs(h-12494.4008) < 0.01)
        #        c0 = self.frame.C0
        #        assert(abs(c0-13450.0141) < 0.01)
        fd = self.dopplerVals['Near']
        #        assert(abs(fd-84.21126622) < 0.01)
        wavl = self.frame.getInstrument().getRadarWavelength()
        #        assert(abs((wavl-23.8403545e-2) /wavl) < 0.01)
        gamma = c0 / rc
        v = self.velocity
        #        assert(abs(v-234.84106135055598) < 0.01)
        A = (fd * wavl / v)**2 * (1 + h / rc)**2
        B = 1. + (1. + h / rc)**2
        C = 2.0 * (1 + h / rc) * math.cos(gamma)
        #        assert(abs(A-0.0073370197515515235) < 0.00001)
        #        assert(abs(B-2.003926560005551) < 0.0001)
        #        assert(abs(C-2.0039182464710574) < 0.0001)
        A2B = A / 2. - B
        D = (A / 2. - B)**2 - (B**2 - C**2)
        x2p = -(A / 2. - B) + math.sqrt(D)
        x2m = -(A / 2. - B) - math.sqrt(D)
        #        assert(abs(x2m-8.328781731403723e-06) < 1.e-9)
        range = rc * math.sqrt(x2m)
        #        assert(abs(range-18384.406963585432) < 0.1)

        sinbeta = -fd * range * wavl / (2. * rc * v * math.cos(gamma))
        cosbeta = -(range**2 -
                    (rc + h)**2 - rc**2) / (2. * rc *
                                            (rc + h) * math.cos(gamma))
        #        assert(abs(sinbeta**2+cosbeta**2 - 1.0) < 0.00001)
        beta = math.atan2(sinbeta, cosbeta)
        #        assert(abs(beta+0.00012335892779153295) < 0.000001)
        t = beta * (rc + h) / v
        #        assert(abs(t+3.3527904301617375) < 0.001)
        pDS = v * t
        #        assert(abs(pDS+787.3728631051696) < 0.01)
        azimuth = self.frame.S0  #self.frame.getStartingAzimuth() #- pDS

        return range, azimuth

    @property
    def heightDt(self):
        """
        Delta(height)/Delta(Time) from frame start-time to mid-time
        """
        return 0.0

    @property
    def velocity(self):
        platform = self.frame.getInstrument().getPlatform()
        elp = platform.getPlanet().get_elp()
        peg = self.peg
        elp.setSCH(peg.latitude, peg.longitude, peg.heading)
        rc = elp.pegRadCur
        scale = (elp.pegRadCur + self.platformHeight) / elp.pegRadCur
        ds_ground = self.frame.instrument.getAzimuthPixelSize()
        dt = 1.0 / self.frame.instrument.getPulseRepetitionFrequency()
        v = scale * ds_ground / dt
        return v

    @property
    def peg(self):
        peg = [
            math.degrees(self.metadata['Peg Latitude']),
            math.degrees(self.metadata['Peg Longitude']),
            math.degrees(self.metadata['Peg Heading'])
        ]

        platform = self.frame.getInstrument().getPlatform()
        elp = platform.getPlanet().get_elp()
        elp.setSCH(*peg)
        rc = elp.pegRadCur

        from isceobj.Location.Peg import Peg
        return Peg(latitude=peg[0],
                   longitude=peg[1],
                   heading=peg[2],
                   radiusOfCurvature=rc)
class UAVSAR_mlcStack(Component):
    """
    A class representing a UAVSAR SLC.
    """

    family = 'uavsar_mlcstack'
    logging_name = 'isce.Sensor.UAVSAR_mlcStack'
    lookMap = {'RIGHT': -1, 'LEFT': 1}

    parameter_list = (METADATAFILE, SEGMENT_INDEX)

    @logged
    def __init__(self, name=''):
        super().__init__(family=self.family, name=name)
        self.frame = Frame()
        self.frame.configure()
        self._elp = None
        self._peg = None
        elp = self.elp
        return

    def _populatePlatform(self, **kwargs):
        platform = self.frame.getInstrument().getPlatform()
        platform.setMission('UAVSAR')
        platform.setPointingDirection(
            self.lookMap[self.metadata['Look Direction'].upper()])
        platform.setPlanet(Planet(pname="Earth"))
        platform.setAntennaLength(self.metadata['Antenna Length'])
        return

    def _populateInstrument(self, **kwargs):
        instrument = self.frame.getInstrument()
        instrument.setRadarWavelength(self.metadata['Center Wavelength'])
        instrument.setPulseRepetitionFrequency(
            1.0 / self.metadata['Average Pulse Repetition Interval'])
        instrument.setRangePixelSize(
            self.metadata['1x1 SLC Range Pixel Spacing'])
        instrument.setAzimuthPixelSize(
            self.metadata['1x1 SLC Azimuth Pixel Spacing'])
        instrument.setPulseLength(self.metadata['Pulse Length'])
        instrument.setChirpSlope(-self.metadata['Bandwidth'] /
                                 self.metadata['Pulse Length'])
        from isceobj.Constants.Constants import SPEED_OF_LIGHT
        instrument.setRangeSamplingRate(SPEED_OF_LIGHT / 2.0 /
                                        instrument.getRangePixelSize())
        instrument.setIncidenceAngle(0.5 *
                                     (self.metadata['Minimum Look Angle'] +
                                      self.metadata['Maximum Look Angle']))

        return

    def _populateFrame(self):
        #Get the Start, Mid, and Stop times
        import datetime
        tStart = datetime.datetime.strptime(
            self.metadata['Start Time of Acquisition'], "%d-%b-%Y %H:%M:%S %Z")
        tStop = datetime.datetime.strptime(
            self.metadata['Stop Time of Acquisition'], "%d-%b-%Y %H:%M:%S %Z")
        dtMid = DTU.timeDeltaToSeconds(tStop - tStart) / 2.
        tMid = tStart + datetime.timedelta(microseconds=int(dtMid * 1e6))

        frame = self.frame
        frame._frameNumber = 1
        frame._trackNumber = 1
        frame.setSensingStart(tStart)
        frame.setSensingStop(tStop)
        frame.setSensingMid(tMid)
        frame.setNumberOfLines(int(self.metadata['slc_1_1x1_mag.set_rows']))
        frame.setNumberOfSamples(int(self.metadata['slc_1_1x1_mag.set_cols']))
        frame.setPolarization(self.metadata['Polarization'])
        frame.C0 = self.metadata['slc_1_1x1_mag.col_addr']
        frame.S0 = self.metadata['Segment {} Data Starting Azimuth'.format(
            self.segment_index)]
        frame.nearLookAngle = self.metadata['Minimum Look Angle']
        frame.farLookAngle = self.metadata['Maximum Look Angle']
        frame.setStartingRange(self.startingRange)
        frame.platformHeight = self.platformHeight
        width = frame.getNumberOfSamples()
        deltaRange = frame.instrument.getRangePixelSize()
        nearRange = frame.getStartingRange()
        midRange = nearRange + (width / 2.) * deltaRange
        frame.setFarRange(nearRange + width * deltaRange)
        #self.extractDoppler()
        frame._ellipsoid = self.elp
        frame.peg = self.peg
        frame.procVelocity = self.velocity

        from isceobj.Location.Coordinate import Coordinate
        frame.upperLeftCorner = Coordinate()

        #The corner latitude, longitudes are given as a pair
        #of values in degrees at each corner (without rdf unit specified)
        llC = []
        for ic in range(1, 5):
            key = 'Segment {0} Data Approximate Corner {1}'.format(
                self.segment_index, ic)
            self.logger.info("key = {}".format(key))
            self.logger.info("metadata[key] = {}".format(
                self.metadata[key], type(self.metadata[key])))
            llC.append(list(map(float, self.metadata[key].split(','))))

        frame.terrainHeight = self.terrainHeight
        frame.upperLeftCorner.setLatitude(llC[0][0])
        frame.upperLeftCorner.setLongitude(llC[0][1])
        frame.upperLeftCorner.setHeight(self.terrainHeight)

        frame.upperRightCorner = Coordinate()
        frame.upperRightCorner.setLatitude(llC[1][0])
        frame.upperRightCorner.setLongitude(llC[1][1])
        frame.upperRightCorner.setHeight(self.terrainHeight)

        frame.lowerRightCorner = Coordinate()
        frame.lowerRightCorner.setLatitude(llC[2][0])
        frame.lowerRightCorner.setLongitude(llC[2][1])
        frame.lowerRightCorner.setHeight(self.terrainHeight)

        frame.lowerLeftCorner = Coordinate()
        frame.lowerLeftCorner.setLatitude(llC[3][0])
        frame.lowerLeftCorner.setLongitude(llC[3][1])
        frame.lowerLeftCorner.setHeight(self.terrainHeight)

        frame.nearLookAngle = math.degrees(self.metadata['Minimum Look Angle'])
        frame.farLookAngle = math.degrees(self.metadata['Maximum Look Angle'])

        return

    def _populateFrameSolo(self):
        self.logger.info("UAVSAR_mlcStack._populateFrameSolo")

    def _populateExtras(self):
        pass

    def _populateOrbit(self, **kwargs):
        """
        Create the orbit as the reference orbit defined by the peg
        """
        numgroup = 1000
        prf = self.frame.instrument.getPulseRepetitionFrequency()
        daz = self.frame.instrument.getAzimuthPixelSize()
        vel = daz * prf
        t0 = self.frame.getSensingStart()

        nlines = int((self.frame.getSensingStop() - t0).total_seconds() * prf)

        #make sure the elp property has been called
        elp = self.elp
        orbit = self.frame.getOrbit()
        orbit.setOrbitSource('Header')

        for i in range(-5 * numgroup,
                       int(nlines / numgroup) * numgroup + 5 * numgroup,
                       numgroup):
            delt = int(i * 1.0e6 / prf)
            torb = self.frame.getSensingStart() + datetime.timedelta(
                microseconds=delt)
            ###Need to compute offset
            ###While taking into account, rounding off in time
            ds = delt * 1.0e-6 * vel

            vec = OrbitStateVector()
            vec.setTime(torb)

            posSCH = [self.frame.S0 + ds, 0.0, self.platformHeight]
            velSCH = [self.velocity, 0., 0.]
            posXYZ, velXYZ = elp.schdot_to_xyzdot(posSCH, velSCH)
            vec.setPosition(posXYZ)
            vec.setVelocity(velXYZ)
            orbit.addStateVector(vec)

        return
        #t0 = (self.frame.getSensingStart() -
        #datetime.timedelta(microseconds=delta))
        #ds = deltaFactor*self.frame.instrument.getAzimuthPixelSize()
        #s0 = self.platformStartingAzimuth - numExtra*ds
        #self.logger.info("populateOrbit: frame.sensingStart, frame.sensingStop  = ", self.frame.getSensingStart(),
        #self.frame.getSensingStop())
        #self.logger.info("populateOrbit: deltaFactor, numExtra, dt = ", deltaFactor, numExtra, dt)
        #self.logger.info("populateOrbit: t0, startingAzimuth, platformStartingAzimuth, s0, ds = ",
        #t0, self.frame.S0, self.platformStartingAzimuth, s0, ds)
        #h = self.platformHeight
        #v = [self.velocity, 0., 0.]
        #self.logger.info("t0, dt = ", t0, dt)
        #self.logger.info("s0, ds, h = ", s0, ds, h)
        #self.logger.info("elp.pegRadCur = ", self.elp.pegRadCur)
        #self.logger.info("v = ", v[0])
        #platform = self.frame.getInstrument().getPlatform()
        #elp = self.elp   #make sure the elp property has been called
        #orbit = self.frame.getOrbit()
        #orbit.setOrbitSource('Header')

        #for i in range(int(self.frame.getNumberOfLines()/deltaFactor)+1000*numExtra+1):
        #vec = OrbitStateVector()
        #t = t0 + datetime.timedelta(microseconds=int(i*dt*1e6))
        #vec.setTime(t)
        #posSCH = [s0 + i*ds , 0., h]
        #velSCH = v
        #posXYZ, velXYZ = self.elp.schdot_to_xyzdot(posSCH, velSCH)
        #sch_pos, sch_vel = elp.xyzdot_to_schdot(posXYZ, velXYZ)

        #vec.setPosition(posXYZ)
        #vec.setVelocity(velXYZ)
        #orbit.addStateVector(vec)
        #return

    def populateMetadata(self):
        self._populatePlatform()
        self._populateInstrument()
        self._populateFrame()
        #self.extractDoppler()
        self._populateOrbit()

    def parse(self):
        from iscesys.Parsers import rdf
        self.metadata = rdf.parse(self.metadataFile)
        self.populateMetadata()

    def extractImage(self):
        self.parse()
        slcImage = isceobj.createSlcImage()
        self.slcname = self.metadata['slc_{}_1x1'.format(self.segment_index)]
        slcImage.setFilename(self.slcname)
        slcImage.setXmin(0)
        slcImage.setXmax(self.frame.getNumberOfSamples())
        slcImage.setWidth(self.frame.getNumberOfSamples())
        slcImage.setLength(self.frame.getNumberOfLines())  #add sk
        slcImage.setAccessMode('r')
        self.frame.setImage(slcImage)
        return

    def extractDoppler(self):
        """
        Read doppler values from the doppler file and fit a polynomial
        """
        frame = self.frame
        instrument = frame.getInstrument()
        rho0 = frame.getStartingRange()
        drho = instrument.getRangePixelSize(
        )  #full res value, not spacing in the dop file
        prf = instrument.getPulseRepetitionFrequency()
        self.logger.info("extractDoppler: rho0, drho, prf = {}, {}, {}".format(
            rho0, drho, prf))
        dopfile = self.metadata['dop']
        f = open(dopfile, 'r')
        x = f.readlines()  #first line is a header

        import numpy
        z = numpy.array(
            [list(map(float, e)) for e in list(map(str.split, x[1:]))])
        rho = z[:, 0]
        dop = z[:, 1]
        #rho0 = rho[0]
        #drho = (rho[1] - rho[0])/2.0
        rhoi = [(r - rho0) / drho for r in rho]
        polydeg = 6  #2  #Quadratic is built in for now
        fit = numpy.polynomial.polynomial.polyfit(rhoi,
                                                  dop,
                                                  polydeg,
                                                  rcond=1.e-9,
                                                  full=True)

        coefs = fit[0]
        res2 = fit[1][0]  #sum of squared residuals
        self.logger.info("coeffs = {}".format(coefs))
        self.logger.info("rms residual = {}".format(numpy.sqrt(res2 /
                                                               len(dop))))
        o = open("dop.txt", 'w')
        for i, d in zip(rhoi, dop):
            val = polyval(coefs, i)
            res = d - val
            o.write("{0} {1} {2} {3}\n".format(i, d, val, res))
            dopfile = self.metadata['dop']

        self.dopplerVals = {
            'Near': polyval(coefs, 0)
        }  #need this temporarily in this module

        self.logger.info(
            "UAVSAR_mlcStack.extractDoppler: self.dopplerVals = {}".format(
                self.dopplerVals))
        self.logger.info(
            "UAVSAR_mlcStack.extractDoppler: prf = {}".format(prf))

        #The doppler file values are in units rad/m.  divide by 2*pi rad/cycle to convert
        #to cycle/m.  Then multiply by velocity to get Hz and divide by prf for dimensionless
        #doppler coefficients
        dop_scale = self.velocity / 2.0 / math.pi
        coefs = [x * dop_scale for x in coefs]
        #Set the coefs in frame._dopplerVsPixel because that is where DefaultDopp looks for them
        self.frame._dopplerVsPixel = coefs

        return coefs

    @property
    def terrainHeight(self):
        #The peg point incorporates the actual terrainHeight
        return 0.0

    @property
    def platformHeight(self):
        h = self.metadata['Global Average Altitude']
        #Reduce the platform height by the terrain height because the
        #peg radius of curvature includes the terrain height
        h -= self.metadata['Global Average Terrain Height']
        return h

    @property
    def platformStartingAzimuth(self):
        azimuth = self.frame.S0
        return azimuth

    @property
    def startingRange(self):
        return self.metadata['Image Starting Slant Range']

    @property
    def squintAngle(self):
        """
        Update this to use the sphere rather than planar approximation.
        """
        startingRange = self.startingRange
        h = self.platformHeight
        v = self.velocity
        prf = self.frame.getInstrument().getPulseRepetitionFrequency()
        wavelength = self.frame.getInstrument().getRadarWavelength()

        if h > startingRange:
            raise ValueError("Spacecraft Height too large (%s>%s)" %
                             (h, startingRange))

        sinTheta = math.sqrt(1 - (h / startingRange)**2)
        fd = self.dopplerVals['Near']
        sinSquint = fd / (2.0 * v * sinTheta) * wavelength

        if sinSquint**2 > 1:
            raise ValueError(
                "Error in One or More of the Squint Calculation Values\n" +
                "Doppler Centroid: %s\nVelocity: %s\nWavelength: %s\n" %
                (fd, v, wavelength))
        self.squint = math.degrees(
            math.atan2(sinSquint, math.sqrt(1 - sinSquint**2)))
        #squint is also required in the frame.
        self.frame.squintAngle = math.radians(self.squint)
        return self.squint

    @property
    def heightDt(self):
        """
        Delta(height)/Delta(Time) from frame start-time to mid-time
        """
        return 0.0

    @property
    def velocity(self):
        v = self.metadata['Average Along Track Velocity']
        platform = self.frame.getInstrument().getPlatform()
        elp = self.elp
        peg = self.peg
        scale = (elp.pegRadCur + self.platformHeight) / elp.pegRadCur
        ds_ground = self.frame.instrument.getAzimuthPixelSize()
        dt = 1.0 / self.frame.instrument.getPulseRepetitionFrequency()
        v1 = scale * ds_ground / dt
        return v1

    @property
    def elp(self):
        if not self._elp:
            planet = Planet(pname="Earth")
            self._elp = planet.get_elp()
        return self._elp

    @property
    def peg(self):
        if not self._peg:
            peg = [
                math.degrees(self.metadata['Peg Latitude']),
                math.degrees(self.metadata['Peg Longitude']),
                math.degrees(self.metadata['Peg Heading'])
            ]
            th = self.metadata['Global Average Terrain Height']
            platform = self.frame.getInstrument().getPlatform()
            self.elp.setSCH(peg[0], peg[1], peg[2], th)
            rc = self.elp.pegRadCur

            from isceobj.Location.Peg import Peg
            self._peg = Peg(latitude=peg[0],
                            longitude=peg[1],
                            heading=peg[2],
                            radiusOfCurvature=rc)
            self.logger.info(
                "UAVSAR_mlcStack: peg radius of curvature = {}".format(
                    self.elp.pegRadCur))
            self.logger.info("UAVSAR_mlcStack: terrain height = {}".format(th))

        return self._peg
Beispiel #8
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
Beispiel #9
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