Exemplo n.º 1
0
class ODR(object):
    """A class to parse Orbital Data Records (ODR) generated by Delft"""

    logging_name = 'isceobj.Orbit.ODR'

    @logged
    def __init__(self, file=None):
        self._file = file
        self._format = None
        self._satellite = None
        self._arcNumber = None
        self._cycleLength = None
        self._numberOfRecords = None
        self._version = None
        self._ephemeris = Orbit()
        self._ephemeris.setOrbitSource('ODR')
        self._ephemeris.setReferenceFrame('ECR')
        self.grs80 = Ellipsoid.Ellipsoid(
            *AstronomicalHandbook.PlanetsData.ellipsoid['Earth']['GRS-80'])

        return None

    #jng added the start and stop time. The computation of the velocities seems pretty time comsuming, so limit the orbit data extraction only to startTime nad stopTime
    def parseHeader(self, startTime=None, stopTime=None):
        fp = None
        try:
            fp = open(self._file, 'rb')
        except IOError as strerr:
            self.logger.error(strerr)
        buffer = fp.read(16)
        # Header 1
        (format, satellite,
         dataStartTimeSeconds) = struct.unpack('>4s8si', buffer)
        buffer = fp.read(16)
        # Header 2
        (cycleLength, number, numberOfRecords,
         version) = struct.unpack('>4i', buffer)

        self._format = format.decode('utf-8')
        self._satellite = satellite.decode('utf-8')
        self._arcNumber = number
        self._cycleLength = cycleLength * 1e3  # In cycle length in days
        self._numberOfRecords = numberOfRecords
        self._version = version

        positions = []
        for i in range(numberOfRecords):
            buffer = fp.read(16)
            if not startTime == None:
                position = self.parseDataRecords(buffer)
                if position['time'] < startTime:
                    continue

            if not stopTime == None:
                position = self.parseDataRecords(buffer)
                if position['time'] > stopTime:
                    continue

            positions.append(self.parseDataRecords(buffer))

        self.createStateVectors(positions)
        fp.close()

    def parseDataRecords(self, buffer):
        """Parse the individual data records for this ODR file"""
        (timeSeconds, latitude, longitude,
         height) = struct.unpack('>4i', buffer)
        time = self._utcSecondsToDatetime(timeSeconds)
        if (self._format == '@ODR'):
            latitude = latitude * 1e-6
            longitude = longitude * 1e-6
        elif (self._format == 'xODR'):
            latitude = latitude * 1e-7
            longitude = longitude * 1e-7
        height = height * 1e-3

        xyz = self._convertToXYZ(latitude, longitude, height)
        return ({'time': time, 'x': xyz[0], 'y': xyz[1], 'z': xyz[2]})

    def createStateVectors(self, positions):
        """Calculate the satellite velocity from the position data and create StateVector objects"""

        for i in range(len(positions)):
            t0 = positions[i]['time']
            x0 = positions[i]['x']
            y0 = positions[i]['y']
            z0 = positions[i]['z']

            sv = StateVector()
            sv.setTime(t0)
            sv.setPosition([x0, y0, z0])
            sv.setVelocity([0.0, 0.0, 0.0])
            self._ephemeris.addStateVector(sv)
        self._calculateVelocities()

    def _calculateVelocities(self):
        for sv in self._ephemeris:
            t0 = sv.getTime()
            t1 = t0 + datetime.timedelta(seconds=-0.5)
            t2 = t0 + datetime.timedelta(seconds=0.5)
            try:
                sv1 = self._ephemeris.interpolateOrbit(t1, method='legendre')
                sv2 = self._ephemeris.interpolateOrbit(t2, method='legendre')
            except ValueError:
                continue
            if (not sv1) or (not sv2):
                continue
            v1 = sv1.getPosition()
            v2 = sv2.getPosition()
            vx = (v2[0] - v1[0])
            vy = (v2[1] - v1[1])
            vz = (v2[2] - v1[2])
            sv.setVelocity([vx, vy, vz])

    def trimOrbit(self, startTime, stopTime):
        """Trim the list of state vectors to encompass the time span [startTime:stopTime]"""

        newOrbit = Orbit()
        newOrbit.setOrbitSource('ODR')
        newOrbit.setReferenceFrame('ECR')
        for sv in self._ephemeris:
            if ((sv.getTime() > startTime) and (sv.getTime() < stopTime)):
                newOrbit.addStateVector(sv)

        return newOrbit

    def getEphemeris(self):
        return self._ephemeris

    def _convertToXYZ(self, latitude, longitude, height):
        # The latitude, longitude and height are referenced to the center of mass of the satellite above the GRS80 ellipsoid
        xyz = self.grs80.llh_to_xyz([latitude, longitude, height])
        return xyz

    def _utcSecondsToDatetime(self, seconds):
        """All of the ODR records are in UTC seconds from 1 Jan. 1985"""
        dataTime = datetime.datetime(year=1985, month=1, day=1)
        dataTime = dataTime + datetime.timedelta(seconds=seconds)
        return dataTime
Exemplo n.º 2
0
class OrbitInfo(object):
    '''Class for storing metadata about a SAR scene.'''
    def __init__(self, fm):
        '''Initialize with a FrameMetadata object'''
        self._lookDict = {'right': -1, 'left': 1}
        self.direction = fm.direction
        self.fd = fm.doppler
        self.tStart = fm.sensingStart
        self.tStop = fm.sensingStop
        self.lookSide = self._lookDict[fm.lookDirection]
        self.prf = fm.prf
        self.rng = fm.startingRange

        self.coherenceThreshold = 0.2
        self.orbVec = None
        self.tMid = self.tStart + sum(
            [self.tStop - self.tStart,
             datetime.timedelta()], datetime.timedelta()) / 2
        self.pos = None
        self.vel = None
        self.peg = None
        self.rds = None
        self.hgt = None
        self.clook = None
        self.slook = None
        self.baseline = {
            'horz': fm.horizontalBaseline,
            'vert': fm.verticalBaseline,
            'total': 0
        }
        self.coherence = None
        self.planet = Planet(pname='Earth')
        self.unpackOrbitVectors(fm.orbit)
        self.computePeg()
        self.computeLookAngle()

    def getBaseline(self):
        return self.baseline

    def getCoherence(self):
        return self.coherence

    def unpackOrbitVectors(self, orb):
        self.orbVec = Orbit(source='json', quality='good')
        self.orbVec._referenceFrame = 'WGS-84'
        relTims = orb[0]
        satPos = orb[1]
        satVel = orb[2]
        refTime = orb[3]

        for kk in range(len(satPos)):
            vecTime = refTime + datetime.timedelta(seconds=relTims[kk])
            tempVec = StateVector(time=vecTime,
                                  position=satPos[kk],
                                  velocity=satVel[kk])
            self.orbVec.addStateVector(tempVec)

        stateVec = self.orbVec.interpolateOrbit(self.tMid, 'hermite')
        self.pos = stateVec.getPosition()
        self.vel = stateVec.getVelocity()
        return

    def computeLookAngle(self):
        self.clook = (2 * self.hgt * self.rds + self.hgt**2 +
                      self.rng**2) / (2 * self.rng * (self.rds + self.hgt))
        self.slook = numpy.sqrt(1 - self.clook**2)
        #        print('Estimated Look Angle: %3.2f degrees'%(np.arccos(self.clook)*180.0/np.pi))
        return

    def computePeg(self):

        shortOrb = Orbit()
        for i in range(-10, 10):
            time = self.tMid + datetime.timedelta(seconds=(i / self.prf))
            sv = self.orbVec.interpolateOrbit(time, method='hermite')
            shortOrb.addStateVector(sv)

        objPeg = stdproc.createGetpeg()
        objPeg.wireInputPort(name='planet', object=self.planet)
        objPeg.wireInputPort(name='Orbit', object=shortOrb)

        stdWriter = create_writer("log", "", True, filename="orbitInfo.log")
        stdWriter.setFileTag("getpeg", "log")
        stdWriter.setFileTag("getpeg", "err")
        stdWriter.setFileTag("getpeg", "log")

        objPeg.setStdWriter(stdWriter)
        objPeg.estimatePeg()

        self.peg = objPeg.getPeg()
        self.rds = objPeg.getPegRadiusOfCurvature()
        self.hgt = objPeg.getAverageHeight()
        return

    def computeBaseline(self, slave):
        '''
        Compute baseline between current object and another orbit object.
        This is meant to be used during data ingest.
        '''

        mpos = numpy.array(self.pos)
        mvel = numpy.array(self.vel)

        #######From the ROI-PAC scripts
        rvec = mpos / numpy.linalg.norm(mpos)
        crp = numpy.cross(rvec, mvel) / numpy.linalg.norm(mvel)
        crp = crp / numpy.linalg.norm(crp)
        vvec = numpy.cross(crp, rvec)
        mvel = numpy.linalg.norm(mvel)

        spos = numpy.array(slave.pos)
        svel = numpy.array(slave.vel)
        svel = numpy.linalg.norm(svel)

        dx = spos - mpos
        z_offset = slave.prf * numpy.dot(dx, vvec) / mvel

        slave_time = slave.tMid - datetime.timedelta(seconds=z_offset /
                                                     slave.prf)

        ####Remove these checks to deal with scenes from same track but not exactly overlaid
        #        if slave_time < slave.tStart:
        #            raise Exception('Out of bounds. Try the previous frame in time.')
        #        elif slave.tStop < slave_time:
        #            raise Exception('Out of bounds. Try the next frame in time.')

        try:
            svector = slave.orbVec.interpolateOrbit(slave_time,
                                                    method='hermite')
        except:
            raise Exception(
                'Error in interpolating orbits. Possibly using non geo-located images.'
            )

        spos = numpy.array(svector.getPosition())
        svel = numpy.array(svector.getVelocity())
        svel = numpy.linalg.norm(svel)

        dx = spos - mpos
        hb = numpy.dot(dx, crp)
        vb = numpy.dot(dx, rvec)

        csb = self.lookSide * hb * self.clook + vb * self.slook

        self.baseline = {'horz': hb, 'vert': vb, 'total': csb}

    def computeCoherence(self, slave, Bcrit=400., Tau=180.0, Doppler=0.4):
        '''
        This is meant to be estimate the coherence. This is for estimating which pairs to process.

        I assume that baseline dict is already available in the json input. baseline dict is w.r.t master and slave baseline is already precomputed w.r.t master.

        Typically: process a pair if Rho > 0.3
        '''
        Bperp = numpy.abs(
            self.lookSide *
            (self.baseline['horz'] - slave.horizontalBaseline) * self.clook +
            (self.baseline['vert'] - slave.verticalBaseline) * self.slook)
        Btemp = numpy.abs(self.tStart.toordinal() -
                          slave.sensingStart.toordinal()) * 1.0
        Bdop = numpy.abs(
            (self.fd * self.prf - slave.doppler * slave.prf) / self.prf)

        geomRho = (1 - numpy.clip(Bperp / Bcrit, 0., 1.))
        tempRho = numpy.exp(-1.0 * Btemp / Tau)
        dopRho = Bdop < Doppler

        self.coherence = geomRho * tempRho * dopRho

    def computeCoherenceNoRef(self, slave, Bcrit=400., Tau=180.0, Doppler=0.4):
        '''
            This is meant to be estimate the coherence. This is for estimating which pairs to process.  Ignores baseline values in json and computes baseline between given pair. Master is not involved.

             Typically: process a pair if Rho > 0.3
        '''

        self.computeBaseline(OrbitInfo(slave))
        Bperp = numpy.abs(self.lookSide * self.baseline['horz'] * self.clook +
                          self.baseline['vert'] * self.slook)
        Btemp = numpy.abs(self.tStart.toordinal() -
                          slave.sensingStart.toordinal()) * 1.0
        Bdop = numpy.abs(
            (self.fd * self.prf - slave.doppler * slave.prf) / self.prf)

        print(('Bperp: %f (m) , Btemp: %f days, Bdop:  %f (frac PRF)' %
               (Bperp, Btemp, Bdop)))
        geomRho = (1 - numpy.clip(Bperp / Bcrit, 0., 1.))
        tempRho = numpy.exp(-1.0 * Btemp / Tau)
        dopRho = Bdop < Doppler
        self.coherence = geomRho * tempRho * dopRho
        print(('Expected Coherence: %f' % (self.coherence)))

    def isCoherent(self,
                   slave,
                   Bcrit=400.,
                   Tau=180,
                   Doppler=0.4,
                   threshold=0.3):
        #### Change this line to self.computeCoherence to go back to original.
        self.computeCoherenceNoRef(slave, Bcrit, Tau, Doppler)

        ret = False
        if (self.coherence >= threshold):
            ret = True
        return ret
Exemplo n.º 3
0
class OrbitTest(unittest.TestCase):
    def setUp(self):
        logging.basicConfig()
        self.linearOrbit = Orbit()
        self.quadOrbit = Orbit()

        linpos, linvel = self.generateLinearSV(10, [[1.0, 2.0, 3.0]],
                                               [[1.0 / 60.0
                                                 for j in range(3)]])
        quadpos, quadvel = self.generateQuadraticSV(10, [[1.0, 2.0, 3.0]], 0.1)

        dt = datetime.datetime(year=2010, month=1, day=1)

        for i in range(10):
            linsv = StateVector()
            quadsv = StateVector()
            linsv.setTime(dt)
            quadsv.setTime(dt)
            linsv.setPosition(linpos[i])
            linsv.setVelocity(linvel[i])
            quadsv.setPosition(quadpos[i])
            quadsv.setVelocity(quadvel[i])
            self.linearOrbit.addStateVector(linsv)
            self.quadOrbit.addStateVector(quadsv)

            dt = dt + datetime.timedelta(minutes=1)

    def tearDown(self):
        del self.linearOrbit
        del self.quadOrbit

    def generateLinearSV(self, num, pos, vel):
        for i in range(1, num):
            sv = [0.0 for j in range(3)]
            for j in range(3):
                sv[j] = pos[i - 1][j] + vel[i - 1][j] * 60.0
            pos.append(sv)
            vel.append(vel[0])
        return pos, vel

    def generateQuadraticSV(self, num, pos, rate):
        vel = [[0.0 for j in range(3)]]
        for t in range(1, num):
            newPos = [0.0 for j in range(3)]
            newVel = [0.0 for j in range(3)]
            for j in range(3):
                newPos[j] = pos[0][j] + rate * (t**2)
                newVel[j] = 2.0 * rate * t / 60.0
            pos.append(newPos)
            vel.append(newVel)
        return pos, vel

    def testAddStateVector(self):
        a = None
        self.assertRaises(TypeError, self.linearOrbit.addStateVector, a)

    def testLinearInterpolateOrbit(self):
        ans = [2.5, 3.5, 4.5]
        sv = self.linearOrbit.interpolateOrbit(datetime.datetime(year=2010,
                                                                 month=1,
                                                                 day=1,
                                                                 hour=0,
                                                                 minute=1,
                                                                 second=30),
                                               method='linear')
        pos = sv.getPosition()
        for i in range(3):
            self.assertAlmostEquals(pos[i], ans[i], 5)

        ans = [1.225, 2.225, 3.225]
        sv = self.quadOrbit.interpolateOrbit(datetime.datetime(year=2010,
                                                               month=1,
                                                               day=1,
                                                               hour=0,
                                                               minute=1,
                                                               second=30),
                                             method='linear')
        pos = sv.getPosition()
        for i in range(3):
            self.assertAlmostEquals(pos[i], ans[i], 5)

    def testHermiteInterpolateOrbit(self):
        ans = [2.5, 3.5, 4.5]
        sv = self.linearOrbit.interpolateOrbit(datetime.datetime(year=2010,
                                                                 month=1,
                                                                 day=1,
                                                                 hour=0,
                                                                 minute=1,
                                                                 second=30),
                                               method='hermite')
        pos = sv.getPosition()
        for i in range(3):
            self.assertAlmostEquals(pos[i], ans[i], 5)

        ans = [1.225, 2.225, 3.225]
        sv = self.quadOrbit.interpolateOrbit(datetime.datetime(year=2010,
                                                               month=1,
                                                               day=1,
                                                               hour=0,
                                                               minute=1,
                                                               second=30),
                                             method='hermite')
        pos = sv.getPosition()
        for i in range(3):
            self.assertAlmostEquals(pos[i], ans[i], 5)

    def testLegendreInterpolateOrbit(self):
        ans = [4.5, 5.5, 6.5]
        sv = self.linearOrbit.interpolateOrbit(datetime.datetime(year=2010,
                                                                 month=1,
                                                                 day=1,
                                                                 hour=0,
                                                                 minute=3,
                                                                 second=30),
                                               method='legendre')
        pos = sv.getPosition()
        for i in range(3):
            self.assertAlmostEquals(pos[i], ans[i], 5)

        ans = [2.225, 3.225, 4.225]
        sv = self.quadOrbit.interpolateOrbit(datetime.datetime(year=2010,
                                                               month=1,
                                                               day=1,
                                                               hour=0,
                                                               minute=3,
                                                               second=30),
                                             method='legendre')
        pos = sv.getPosition()
        for i in range(3):
            self.assertAlmostEquals(pos[i], ans[i], 5)

    def testInterpolateOrbitOutOfBounds(self):
        dt = datetime.datetime(year=2010, month=1, day=2)
        self.assertRaises(ValueError, self.linearOrbit.interpolateOrbit, dt)