def test_sep_against_slalib_dsep(): """Results from sep should match those from slalib.dsep""" # Random positions. import random import math random.seed(12345) alpha = [random.uniform(0, 2 * math.pi) for i in range(100)] delta = [random.uniform(-math.pi / 2, math.pi / 2) for i in range(100)] alpha1 = [random.uniform(0, 2 * math.pi) for i in range(100)] delta1 = [random.uniform(-math.pi / 2, math.pi / 2) for i in range(100)] # Code used to generate result from pyslalib: # s = [slalib.sla_dsep(alpha[i], delta[i], alpha1[i], delta1[i]) # for i in range(100)] s = [ 2.3488832415605776, 1.1592942993972908, 1.6727782224088137, 1.9310273037619246, 1.961534390837681, 1.5150119839396818, 1.8524526916856978, 2.116947088206131, 0.9750943461637399, 0.8331152895856854, 2.4690444308150243, 0.8640444988019701, 1.041460475452765, 1.9245098805162162, 2.7727507743449507, 1.1760229988483686, 1.6418575515189582, 1.0798127458770757, 2.705734045454533, 2.711202832152844, 2.4387778718976763, 0.1675761464872016, 0.7614806222975763, 1.7781491597763561, 2.029672021455121, 2.4349201303097403, 1.2603565818807192, 2.05499965347367, 0.6224811898002452, 0.8126836325942026, 0.7539982342941834, 1.6809458707673535, 1.975972151791415, 0.7115429070168364, 1.8079386355215084, 0.7830659699492306, 1.233553087948177, 2.08588792306906, 0.2779525335855478, 1.458433197949138, 1.2964042308707935, 1.117425142370921, 1.6383665060581982, 0.21787615812753383, 1.6859098755220057, 1.2253004206853584, 1.472817142187865, 0.6648294675219921, 2.982945161877018, 0.45704974384275243, 1.1584539180661326, 2.8484175031722643, 1.0402706684988297, 0.7079258905264588, 0.7808758533750498, 0.5608700573233222, 1.8505539643075692, 2.494182944528214, 0.8296145526473544, 2.2901089789186297, 1.7477923358131886, 2.1499080375112816, 1.1529753011873909, 1.807265859808323, 2.5770854449349865, 1.172037115203078, 2.7438561146081937, 0.2216663532818151, 1.4502352305471127, 2.2334298247493645, 1.9946613229884687, 1.1362010677143621, 0.9530063759328101, 0.6782653608813761, 0.9421358945224116, 1.970340302154089, 0.31583484463019296, 0.5945806070431309, 1.9894690263497685, 0.5114702873070847, 3.059530134272125, 0.09988794964432562, 2.1732721685109437, 2.054896439114964, 1.0130957019858804, 1.6899941268950893, 1.4002698103226345, 1.3736478209061835, 1.7281316524003778, 1.7041224372124824, 2.7245561902753233, 1.676900403298997, 0.5940433957880709, 2.4371934329915814, 2.189360172634095, 1.127368860507556, 0.49285131033236657, 2.6159861791852204, 0.878592556336548, 2.875063431097953 ] s1 = [ sep(a1, b1, a2, b2) for a1, b1, a2, b2 in zip(alpha, delta, alpha1, delta1) ] d = [i - j for i, j in zip(s, s1)] assert abs(min(d)) <= 1e-8 assert abs(max(d)) <= 1e-8
def getSeparation(x1: float, y1: float, x2: float, y2: float, z: float, mode: str) -> float: """Returns angular separation between two angles on a unit sphere. :param x1: :param y1: :param x2: :param y2: :param z: depth, in mm :param mode: whether coordinates are passed in mm or degrees :return: angle in degrees """ if mode == 'fromCartesian': lon1 = cmath.polar(complex(x1, z))[1] - math.pi / 2 lat1 = cmath.polar(complex(y1, z))[1] - math.pi / 2 lon2 = cmath.polar(complex(x2, z))[1] - math.pi / 2 lat2 = cmath.polar(complex(y2, z))[1] - math.pi / 2 sep = angles.sep(lon1, lat1, lon2, lat2) elif mode == 'fromPolar': sep = angles.sep(math.radians(x1), math.radians(y1), math.radians(x2), math.radians(y2)) return math.degrees(sep)
def convolve(self, x, y, z, inweight): """ convolve a measurement onto a range of grid coordinates """ nwidth = int(4.1 * self.FWHM * self.dpi) ix = self.ii(x) jy = self.jj(y) x0 = angles.d2r(x) # convert to radians if x0 < self.xminrad: x0 = x0 + (2. * np.pi) elif x0 > self.xmaxrad: x0 = x0 - (2. * np.pi) y0 = angles.d2r(y) for iii in range(-nwidth, nwidth): iix = ix + iii if iix < 0: iix = self.img_width + iix elif iix >= self.img_width: iix = iix - self.img_width xx = self.xx(iix) rx = angles.d2r(xx) # convert to radians for jjj in range(-nwidth, nwidth): jjy = jy + jjj if jjy < 0: jjy = self.img_height + jjy elif jjy >= self.img_height: jjy = jjy - self.img_height yy = self.yy(jjy) ry = angles.d2r(yy) # conver to radians if ry < self.yminrad: ry = ry + (2. * np.pi) elif ry > self.ymaxrad: ry = ry - (2. * np.pi) # finally get angular separation in degrees r = angles.r2d(angles.sep(x0, y0, rx, ry)) # if r > 4.*self.FWHM: # round convolving function if r > 3. * self.FWHM: # round convolving function continue # add the colvolved measurement to the grid. self.xy(iix, jjy, z, r, inweight) return
def friend(ob1, ob2): # determines the friendship between two clumps flag = "NO" # Initial assumption = NO """ Projected Sky Separation """ # calculates the angular separation between two centroids of the clumps t1 = (cat['ra'][ob1], cat['dec'][ob1]) t2 = (cat['ra'][ob2], cat['dec'][ob2]) angrad = sep(d2r(t1[0]), d2r(t1[1]), d2r(t2[0]), d2r(t2[1])) angarcmin = (angrad * 180 * 60) / float(np.pi) """ Redshift check""" # checks redshift consistency of the two clumps. # If their redshift difference is consistent with zero then yes. # What todo : Old Method # z1, z2 = gcat[gindex[id1]]['Z'], gcat[gindex[id2]]['Z'] # corresponding member redshifts # m1, m2 = np.mean(z1), np.mean(z2) # mean redshifts of the clumps # var1, var2 = (0.061**2) * np.sum((1+z1)**2), (0.061**2) * np.sum((1+z2)**2) # variances # er1, er2 = np.sqrt(var1 / float(len(z1))), np.sqrt(var2 / float(len(z2))) # errors id1, id2 = cat['id'][ob1], cat['id'][ ob2] # clump ids (actually dog ids) res1 = gfit_to_pdf(id1, gindex) res2 = gfit_to_pdf(id2, gindex) m1, m2 = abs(res1[0]), abs(res2[0]) er1, er2 = abs(res1[1]), abs(res2[1]) if m1 > m2: d = m1 - m2 # difference of the mean else: d = m2 - m1 d_er = np.sqrt(er1**2 + er2**2) # error on the difference. low, high = d - d_er, d + d_er # minimum and maximum difference. """ Decision """ if angarcmin < aperture: if low <= 0 <= high: flag = "YES" # friend if angular separation is less than the aperture radius # and if their 0 belongs to the range [min_diff, max_diff]. return flag
print "Telescope Az, El: ", rs.telaz, rs.telel # convert to MHz yv = rs.ydataA * scalefactor if doFlag: hv = interpolate.lines( linelist, linewidth, xv, yv) # interpolate rfi spectra[nRead, : ] = hv else: spectra[nRead, : ] = yv # now record the coordinates to compare distances. azs[nRead] = rs.telaz els[nRead] = rs.telel ras[nRead] = rs.ra decs[nRead] = rs.dec # print rs.ra, rs.dec aTheta = angles.sep(angles.d2r(rs.ra), angles.d2r(rs.dec), ra0, dec0) thetas[nRead] = aTheta # keep track of minimum angular distance if aTheta < minTheta: minTheta = aTheta iTheta = nRead if aTheta < onTheta: if nOn == 0: onSpectra = copy.deepcopy( rs) else: onSpectra.ydataA = onSpectra.ydataA + rs.ydataA nOn = nOn + 1 nRead = nRead + 1 if aTheta > offThetaA and aTheta < offThetaB:
def azel_to_antenna_angles(self, pdat, cont_track_method= None): """ From a table of az/el pointings, compute a new table that minimises the amount of movements while keeping the off-pointing within the antenna beamwidth Note: this method does *not* interpolate, it just uses nearest neighbour so pdat must be at sufficient time resolution. Also transform antenna pointing vectors in such a way that the antenna will track continously throughout the pass. We do this by checking if the antenna ever needs to enter both the NE and NW quarters, and if so, depending on the antenna rotator capabilities we can use one of 2 methods to achieve a continous (up to 3 quadrant) track. * flipover: We move the antenna in the 90 -- 180 degree extended elevation range * extended_azimuth: We move the antenna in the 360 -- 540 degree extended azimuth range 4 quadrant tracking is not currently supported. If the trajectory enters 4 quadrants, or if the antenna capabilities do not meet the requirements for flipover or extended_azimuth, then the antenna will be commanded in the "normal" 0-360 az and 0-90 el range and there may be discontinuities. args: pdat (DataFrame): must have at least an az and el column. cont_track_method (str): Try to force a continous tracking method. If omited a method will be chosen based on antenna capabilities. """ if not isinstance(pdat, DataFrame): raise Error("pdat must be a DataFrame, got {}".format(type(pdat))) if 'az'not in pdat.columns or 'el' not in pdat.columns: raise Error("pdat must have at least an az and el column") # # Transform antenna pointing vectors in such a way that the antenna will track continously throughout # the pass. We do this by checking if the antenna ever needs to enter both the NE and NW quarters, and # if so, depending on the antenna rotator capabilities we can use one of 2 methods to achieve a continous # (up to 3 quadrant) track. # * flipover: We move the antenna in the 90 -- 180 degree extended elevation range # * extended_azimuth: We move the antenna in the 360 -- 540 degree extended azimuth range # # 4 quadrant tracking is not currently supported. If the trajectory enters 4 quadrants, or if the antenna # capabilities do not meet the requirements for flipover or continue, then the antenna will be commanded # in the "normal" 0-360 az and 0-90 el range and there may be discontinuities. # if cont_track_method is None: # TODO (maybe one day): Enable 4 quadrant continous tracking by utilising extended range (360->450 deg) if self.MAX_AZ >= 540: cont_track_method = 'extended_azimuth' elif self.MAX_EL >= 180: cont_track_method = 'flipover' else: cont_track_method = 'none' # Compute quadrants the trajectory passes through quadrants = set([('N' if p.az < 90 or p.az > 270 else 'S') + ('E' if p.az < 180 else 'W') for _, p in pdat.iterrows()]) # Note NE and NW in quadrants and len(q) <=3 implies that SW and SE cant both be passed through and so the below # works. It would *not* work if the track crossed the SW-SE boundary. if len(quadrants) <= 3 and 'NE' in quadrants and 'NW' in quadrants and cont_track_method == 'flipover': # Make sure antenna tracks continously when crossing NE->NW boundary by flipping antenna over # i.e by applying elevation angles between 180 -> 90, and adjusting azimuth appropriately. log.info('Antenna track crosses between NE and NW quadrant. Using "flipover" method for continous tracking') pdat = pdat.copy() pdat.az -= 180 pdat.loc[pdat.az < 0, 'az'] += 360 pdat.el = 180 - pdat.el elif len(quadrants) <= 3 and 'NE' in quadrants and 'NW' in quadrants and cont_track_method == 'extended_azimuth': # Make sure antenna tracks continously when crossing NE-->NW boundary by using the 180-->540 azimuth # range instead of 0 --> 360 # log.info('Antenna track crosses between NE and NW quadrant. Using "extended_azimuth" method for continous tracking') pdat = pdat.copy() pdat.loc[pdat.az < 180, 'az'] += 360 else: if len(quadrants) > 3: log.warning("4 Quadrant continous tracking is not currently supported.") az = pdat.az el = pdat.el ant_p = DataFrame(columns=pdat.columns) ant_p = ant_p.append(pdat.iloc[0]) R2D = 180.0/pi D2R = pi/180.0 for k,r in pdat.iterrows(): s = angles.sep(ant_p.iloc[-1].az*D2R, ant_p.iloc[-1].el*D2R, r.az*D2R, r.el*D2R)*R2D if (s >= self.BEAMWIDTH/2.2): #<--- half beamwdith less 10% margin ant_p = ant_p.append(r) if len(ant_p) > 1: t = ant_p.index[:-1:2] ant_p = ant_p.iloc[1::2] ant_p.index =t elif len(ant_p) == 0: raise Error("Failed to compute any antenna points") return ant_p
def sep_tuple(t1, t2): # distances between two coordinates, stored in two tuples # works fine, but will not use angrad = sep(d2r(t1[0]), d2r(t1[1]), d2r(t2[0]), d2r(t2[1])) angarcmin = (angrad * 180 * 60) / float(np.pi) # in arcmin return angarcmin
def test_sep_against_slalib_dsep(): """Results from sep should match those from slalib.dsep""" # Random positions. import random import math random.seed(12345) alpha = [random.uniform(0, 2 * math.pi) for i in range(100)] delta = [random.uniform(-math.pi / 2, math.pi / 2) for i in range(100)] alpha1 = [random.uniform(0, 2 * math.pi) for i in range(100)] delta1 = [random.uniform(-math.pi / 2, math.pi / 2) for i in range(100)] # Code used to generate result from pyslalib: # s = [slalib.sla_dsep(alpha[i], delta[i], alpha1[i], delta1[i]) # for i in range(100)] s = [2.3488832415605776, 1.1592942993972908, 1.6727782224088137, 1.9310273037619246, 1.961534390837681, 1.5150119839396818, 1.8524526916856978, 2.116947088206131, 0.9750943461637399, 0.8331152895856854, 2.4690444308150243, 0.8640444988019701, 1.041460475452765, 1.9245098805162162, 2.7727507743449507, 1.1760229988483686, 1.6418575515189582, 1.0798127458770757, 2.705734045454533, 2.711202832152844, 2.4387778718976763, 0.1675761464872016, 0.7614806222975763, 1.7781491597763561, 2.029672021455121, 2.4349201303097403, 1.2603565818807192, 2.05499965347367, 0.6224811898002452, 0.8126836325942026, 0.7539982342941834, 1.6809458707673535, 1.975972151791415, 0.7115429070168364, 1.8079386355215084, 0.7830659699492306, 1.233553087948177, 2.08588792306906, 0.2779525335855478, 1.458433197949138, 1.2964042308707935, 1.117425142370921, 1.6383665060581982, 0.21787615812753383, 1.6859098755220057, 1.2253004206853584, 1.472817142187865, 0.6648294675219921, 2.982945161877018, 0.45704974384275243, 1.1584539180661326, 2.8484175031722643, 1.0402706684988297, 0.7079258905264588, 0.7808758533750498, 0.5608700573233222, 1.8505539643075692, 2.494182944528214, 0.8296145526473544, 2.2901089789186297, 1.7477923358131886, 2.1499080375112816, 1.1529753011873909, 1.807265859808323, 2.5770854449349865, 1.172037115203078, 2.7438561146081937, 0.2216663532818151, 1.4502352305471127, 2.2334298247493645, 1.9946613229884687, 1.1362010677143621, 0.9530063759328101, 0.6782653608813761, 0.9421358945224116, 1.970340302154089, 0.31583484463019296, 0.5945806070431309, 1.9894690263497685, 0.5114702873070847, 3.059530134272125, 0.09988794964432562, 2.1732721685109437, 2.054896439114964, 1.0130957019858804, 1.6899941268950893, 1.4002698103226345, 1.3736478209061835, 1.7281316524003778, 1.7041224372124824, 2.7245561902753233, 1.676900403298997, 0.5940433957880709, 2.4371934329915814, 2.189360172634095, 1.127368860507556, 0.49285131033236657, 2.6159861791852204, 0.878592556336548, 2.875063431097953] s1 = [sep(a1, b1, a2, b2) for a1, b1, a2, b2 in zip(alpha, delta, alpha1, delta1)] d = [i - j for i, j in zip(s, s1)] assert abs(min(d)) <= 1e-8 assert abs(max(d)) <= 1e-8