def testWrap(self): for wrap in (-1000, -10, -1, 0, 1, 10, 1000): for offset in (-360, -180, -90, 0, 90, 180, 270, 360): for epsMult in (-3, -2, -1, 0, 1, 2, 3): ang = offset + (wrap * 360) ang += ang * DoubleEpsilon * epsMult sinAng = sind(ang) cosAng = cosd(ang) pvt = PVT(ang, ang, 35.0) # pick anything for vel and time posAng = wrapPos(ang) self.assertGreaterEqual(posAng, 0.0) self.assertLess(posAng, 360.0) # prove that posAng and ang are the same angle # sin and cos are a sanity check on wrapCtr self.assertAlmostEqual(wrapCtr(posAng - ang), 0) self.assertAlmostEqual(sind(posAng), sinAng) self.assertAlmostEqual(cosd(posAng), cosAng) posPvt = wrapPos(pvt) self.assertEqual(posPvt.pos, posAng) self.assertEqual(posPvt.vel, pvt.vel) self.assertEqual(posPvt.t, pvt.t) ctrAng = wrapCtr(ang) self.assertGreaterEqual(ctrAng, -180.0) self.assertLess(ctrAng, 180.0) # prove that ctrAng and ang are the same angle self.assertAlmostEqual(wrapCtr(ctrAng - ang), 0) self.assertAlmostEqual(sind(ctrAng), sinAng) self.assertAlmostEqual(cosd(ctrAng), cosAng) ctrPvt = wrapCtr(pvt) self.assertEqual(ctrPvt.pos, ctrAng) self.assertEqual(ctrPvt.vel, pvt.vel) self.assertEqual(ctrPvt.t, pvt.t) for refAngBase in (-180, 0, 180, 360): for refEpsMult in (-3, -2, -1, 0, 1, 2, 3): refAng = refAngBase refAng += refAng * refEpsMult * DoubleEpsilon nearAng = wrapNear(ang, refAng) self.assertGreaterEqual(nearAng - refAng, -180) self.assertLess(nearAng - refAng, 180) # prove that nearAng and ang are the same angle self.assertAlmostEqual(wrapCtr(nearAng - ang), 0) self.assertAlmostEqual(sind(nearAng), sinAng) self.assertAlmostEqual(cosd(nearAng), cosAng)
def makePVTFromPair(posPair, tai, deltaT, isAngle): pos = posPair[0] if (isAngle): vel = coordConv.wrapCtr(posPair[1] - posPair[0]) / deltaT else: vel = (posPair[1] - posPair[0]) / deltaT return coordConv.PVT(pos, vel, tai)
def measureOrientationToErr(): """Measure error in Coord.orientationTo for tiny offsets For best results modify Coord::orientationTo to not short-circuit tiny values of sinVal, cosVal """ errDict = {} # dict of distArcSec: (max orient error, max(sinVal, cosVal)) for fromPolarAng in (-89, -72, -45.0, -30, 0.01, 12.5, 31, 47, 56, 68, 89): for fromEquatAng in (0, 41.0): # should not matter fromCoord = coordConv.Coord(fromEquatAng, fromPolarAng) for fromOrient in (-90, -72, -45.0, -30, 0.01, 0, 12.5, 31, 45, 56, 68, 89): # offset by such small distances that toOrient=fromOrient # by 1e-6 the error is starting to go up, indicating that the approximation is failing for distArcSec in (5e-5, 1e-4, 2e-4, 3e-4, 4e-4, 5e-4, 1e-3, 1e-2): toCoord, dumToOrient = fromCoord.offset(fromOrient, distArcSec / 3600) toOrient = coordConv.wrapCtr(180 + toCoord.orientationTo(fromCoord)) # expect fromOrient = toOrient newErrArcSec = abs(toOrient - fromOrient) * 3600 oldErrArcSec = errDict.get(distArcSec, (0, 0))[0] if newErrArcSec > oldErrArcSec: toU = toCoord.getVecPos() toU /= numpy.linalg.norm(toU) fromU = fromCoord.getVecPos() fromU /= numpy.linalg.norm(fromU) sinVal = (toU[1] * fromU[0]) - (toU[0] * fromU[1]) cosVal = (toU[2] * ((fromU[0] * fromU[0]) + (fromU[1] * fromU[1]))) \ - (fromU[2] * ((toU[0] * fromU[0]) + (toU[1] * fromU[1]))) errDict[distArcSec] = (newErrArcSec, max(sinVal, cosVal)) distKeys = sorted(errDict.keys()) print "Note that by 0.01 arcsec the error creeps up, indicating that the approximation toOrient=fromOrient is failing" for distArcSec in distKeys: errArcSec, maxSinCos = errDict[distArcSec] print "distArcSec=%0.3g arcsec, maxErr=%0.3g arcsec, maxSin/Cos=%0.3g" % (distArcSec, errArcSec, maxSinCos)
def refPolarFromXY(x, y, tai): """Reference implementation of PVT.polarFromXY """ atPole = False rArr = [] thetaArr = [] for testTAI in (tai, tai + DeltaT): ap, r, theta = coordConv.polarFromXY(x.getPos(testTAI), y.getPos(testTAI)) rArr.append(r) thetaArr.append(theta) atPole = atPole or ap rPVT = coordConv.PVT() rPVT.pos = rArr[0] rPVT.vel = (rArr[1] - rArr[0]) / DeltaT rPVT.t = tai thetaPVT = coordConv.PVT() thetaPVT.pos = thetaArr[0] thetaPVT.vel = coordConv.wrapCtr(thetaArr[1] - thetaArr[0]) / DeltaT thetaPVT.t = tai return atPole, rPVT, thetaPVT
def measureOrientationToErr(): """Measure error in Coord.orientationTo for tiny offsets For best results modify Coord::orientationTo to not short-circuit tiny values of sinVal, cosVal """ errDict = {} # dict of distArcSec: (max orient error, max(sinVal, cosVal)) for fromPolarAng in (-89, -72, -45.0, -30, 0.01, 12.5, 31, 47, 56, 68, 89): for fromEquatAng in (0, 41.0): # should not matter fromCoord = coordConv.Coord(fromEquatAng, fromPolarAng) for fromOrient in (-90, -72, -45.0, -30, 0.01, 0, 12.5, 31, 45, 56, 68, 89): # offset by such small distances that toOrient=fromOrient # by 1e-6 the error is starting to go up, indicating that the approximation is failing for distArcSec in (5e-5, 1e-4, 2e-4, 3e-4, 4e-4, 5e-4, 1e-3, 1e-2): toCoord, dumToOrient = fromCoord.offset( fromOrient, distArcSec / 3600) toOrient = coordConv.wrapCtr( 180 + toCoord.orientationTo(fromCoord)) # expect fromOrient = toOrient newErrArcSec = abs(toOrient - fromOrient) * 3600 oldErrArcSec = errDict.get(distArcSec, (0, 0))[0] if newErrArcSec > oldErrArcSec: toU = toCoord.getVecPos() toU /= numpy.linalg.norm(toU) fromU = fromCoord.getVecPos() fromU /= numpy.linalg.norm(fromU) sinVal = (toU[1] * fromU[0]) - (toU[0] * fromU[1]) cosVal = (toU[2] * ((fromU[0] * fromU[0]) + (fromU[1] * fromU[1]))) \ - (fromU[2] * ((toU[0] * fromU[0]) + (toU[1] * fromU[1]))) errDict[distArcSec] = (newErrArcSec, max(sinVal, cosVal)) distKeys = sorted(errDict.keys()) print "Note that by 0.01 arcsec the error creeps up, indicating that the approximation toOrient=fromOrient is failing" for distArcSec in distKeys: errArcSec, maxSinCos = errDict[distArcSec] print "distArcSec=%0.3g arcsec, maxErr=%0.3g arcsec, maxSin/Cos=%0.3g" % ( distArcSec, errArcSec, maxSinCos)