def Br_for_ml(r, th, ph, g, h, m, l, a=6371.2): """ Calculates the Br contribution for one set of m,l, using the potential field. Inputs ------ r: radius location (km) th: latitude location (radians) ph: longitude location (radians) g: Gauss coefficient (cos term) h: Gauss coefficient (sin term) m: Order of calculation l: Degree of calculation a: Radius (km) at which Gauss coefficients are calculated Returns ------- Br contribution in Tesla at a particular point from a particular degree and order. """ return (l + 1.) * a**(l + 2.) / abs(r)**(l + 2.) * ( g * _cos(m * ph) + h * _sin(m * ph)) * Pml(_cos(th), l, m)
def Br_for_ml(r,th,ph,g,h,m,l, a=6371.2): """ Calculates the Br contribution for one set of m,l, using the potential field. Inputs ------ r: radius location (km) th: latitude location (radians) ph: longitude location (radians) g: Gauss coefficient (cos term) h: Gauss coefficient (sin term) m: Order of calculation l: Degree of calculation a: Radius (km) at which Gauss coefficients are calculated Returns ------- Br contribution in Tesla at a particular point from a particular degree and order. """ return (l+1.)*a**(l+2.)/abs(r)**(l+2.)*(g*_cos(m*ph) + h*_sin(m*ph))*Pml(_cos(th), l, m)
def _dphi_Br_for_ml_complex(self, r, th, ph, c, m, l, a=6371.2): """ Calculates the d_phi(Br)/(R*sin(th)) contribution for one set of m,l, using the potential field. Inputs ------ r: radius location (km) th: latitude location (radians) ph: longitude location (radians) c: complex gauss coefficient m: Order of calculation l: Degree of calculation a: Radius (km) at which Gauss coefficients are calculated Returns ------- d_phi(Br)/(R*sin(th)) in Tesla/m at a particular point from a particular degree and order. """ return 1j*m/(r*_sin(th))*self._Br_for_ml_complex(r, th, ph, c, m, l, a=a)
def rcosfir(beta, sps, span=None): """Generates a raised cosine FIR filter. :param beta: shape of the raised cosine filter (0-1) :param sps: number of samples per symbol :param span: length of the filter in symbols (None => automatic selection) >>> import arlpy >>> rc = arlpy.comms.rcosfir(0.25, 6) >>> bb = arlpy.comms.modulate(arlpy.comms.random_data(100), arlpy.comms.psk()) >>> pb = arlpy.comms.upconvert(bb, 6, 27000, 18000, rc) """ if beta < 0 or beta > 1: raise ValueError('Beta must be between 0 and 1') if span is None: # from http://www.commsys.isy.liu.se/TSKS04/lectures/3/MichaelZoltowski_SquareRootRaisedCosine.pdf # since this recommendation is for root raised cosine filter, it is conservative for a raised cosine filter span = 33 - int(44 * beta) if beta < 0.68 else 4 delay = int(span * sps / 2) t = _np.arange(-delay, delay + 1, dtype=_np.float) / sps denom = 1 - (2 * beta * t)**2 eps = _np.finfo(float).eps idx1 = _np.nonzero(_np.abs(denom) > _sqrt(eps)) b = _np.full_like(t, beta * _sin(_pi / (2 * beta)) / (2 * sps)) b[idx1] = _np.sinc(t[idx1]) * _cos( _pi * beta * t[idx1]) / denom[idx1] / sps b /= _sqrt(_np.sum(b**2)) return b
def rrcosfir(beta, sps, span=None): """Generates a root raised cosine FIR filter. :param beta: shape of the root raised cosine filter (0-1) :param sps: number of samples per symbol :param span: length of the filter in symbols (None => automatic selection) >>> import arlpy >>> rrc = arlpy.comms.rrcosfir(0.25, 6) >>> bb = arlpy.comms.modulate(arlpy.comms.random_data(100), arlpy.comms.psk()) >>> pb = arlpy.comms.upconvert(bb, 6, 27000, 18000, rrc) """ if beta < 0 or beta > 1: raise ValueError('Beta must be between 0 and 1') if span is None: # from http://www.commsys.isy.liu.se/TSKS04/lectures/3/MichaelZoltowski_SquareRootRaisedCosine.pdf span = 33 - int(44 * beta) if beta < 0.68 else 4 delay = int(span * sps / 2) t = _np.arange(-delay, delay + 1, dtype=_np.float) / sps b = _np.empty_like(t) b[delay] = -1 / (_pi * sps) * (_pi * (beta - 1) - 4 * beta) eps = _np.finfo(float).eps idx2 = _np.nonzero(_np.abs(_np.abs(4 * beta * t) - 1) < _sqrt(eps)) if len(idx2) > 0: b[idx2] = (_pi * (beta + 1) * _sin(_pi * (beta + 1) / (4 * beta)) - 4 * beta * _sin(_pi * (beta - 1) / (4 * beta)) + _pi * (beta - 1) * _cos(_pi * (beta - 1) / (4 * beta))) / (2 * _pi * sps) ind = _np.arange(len(t)) ind = _np.delete(ind, _np.append(idx2, delay)) nind = t[ind] b[ind] = -4 * beta / sps * (_cos((1 + beta) * _pi * nind) + _sin( (1 - beta) * _pi * nind) / (4 * beta * nind)) / (_pi * ( (4 * beta * nind)**2 - 1)) b /= _sqrt(_np.sum(b**2)) return b
def _do_dispersal(spp, parent_midpoint_x, parent_midpoint_y, dispersal_distance_distr_param1, dispersal_distance_distr_param2, mu_dir=0, kappa_dir=0): within_landscape = False while not within_landscape: # choose direction using movement surface, if applicable if spp._disp_surf: # and use those choices to draw movement directions direction = spp._disp_surf._draw_directions( [int(parent_midpoint_x)], [int(parent_midpoint_y)])[0] # else, choose direction using a random walk with a uniform vonmises elif not spp._disp_surf: direction = _r_vonmises(mu_dir, kappa_dir) if spp.dispersal_distance_distr == 'levy': distance = _s_levy.rvs(loc=spp.dispersal_distance_distr_param1, scale=spp.dispersal_distance_distr_param2) elif spp.dispersal_distance_distr == 'wald': distance = _wald(mean=dispersal_distance_distr_param1, scale=dispersal_distance_distr_param2) elif spp.dispersal_distance_distr == 'lognormal': distance = _lognormal(mean=spp.dispersal_distance_distr_param1, sigma=spp.dispersal_distance_distr_param2) # decompose distance into x and y components dist_x = _cos(direction) * distance dist_y = _sin(direction) * distance # multiply the x and y distances by the land's resolution-ratios, # if they're not 1 and 1 (e.g. using a non-square-resolution raster) if spp._land_res_ratio[0] != 1: dist_x *= spp._land_res_ratio[0] if spp._land_res_ratio[1] != 1: dist_y *= spp._land_res_ratio[1] offspring_x = parent_midpoint_x + dist_x offspring_y = parent_midpoint_y + dist_y offspring_x = np.clip(offspring_x, a_min=0, a_max=spp._land_dim[0] - 0.001) offspring_y = np.clip(offspring_y, a_min=0, a_max=spp._land_dim[1] - 0.001) within_landscape = ( (offspring_x > 0 and offspring_x < spp._land_dim[0]) and (offspring_y > 0 and offspring_y < spp._land_dim[1])) return (offspring_x, offspring_y)
def _do_movement(spp): # get individuals' coordinates (soon to be their old coords, so # 'old_x' and 'old_y') old_x, old_y = [ a.flatten() for a in np.split(spp._get_coords(), 2, axis=1) ] # and get their cells (by rounding down to the int) old_x_cells, old_y_cells = [ a.flatten() for a in np.split(spp._get_cells(), 2, axis=1) ] # choose direction using movement surface, if applicable if spp._move_surf: # and use those choices to draw movement directions direction = spp._move_surf._draw_directions(old_x_cells, old_y_cells) # NOTE: Pretty sure that I don't need to constrain values output # for the Gaussian KDE that is approximating the von Mises mixture # distribution to 0<=val<=2*pi, because e.g. cos(2*pi + 1) = cos(1), # etc... # NOTE: indexed out of move_surf as y then x because becuase the # list of lists (like a numpy array structure) is indexed i then j, # i.e. vertical, then horizontal # else, choose direction using a random walk with a uniform vonmises elif not spp._move_surf: direction = _r_vonmises(spp.direction_distr_mu, spp.direction_distr_kappa, size=len(old_x)) # choose distance # NOTE: Instead of lognormal, could use something with long right tail # for Levy-flight type movement, same as below if spp.movement_distance_distr == 'levy': distance = _s_levy.rvs(loc=spp.movement_distance_distr_param1, scale=spp.movement_distance_distr_param2, size=len(old_x)) elif spp.movement_distance_distr == 'wald': distance = _wald(mean=spp.movement_distance_distr_param1, scale=spp.movement_distance_distr_param2, size=len(old_x)) elif spp.movement_distance_distr == 'lognormal': distance = _lognormal(mean=spp.movement_distance_distr_param1, sigma=spp.movement_distance_distr_param2, size=len(old_x)) # decompose distance into x and y components dist_x = _cos(direction) * distance dist_y = _sin(direction) * distance # multiply the x and y distances by the land's resolution-ratios, # if they're not 1 and 1 (e.g. a non-square-resolution raster was read in) if spp._land_res_ratio[0] != 1: dist_x *= spp._land_res_ratio[0] if spp._land_res_ratio[1] != 1: dist_y *= spp._land_res_ratio[1] # create the new locations by adding x- and y-dim line segments to their # current positions, using trig then clip the values to be within the # landscape dimensions # NOTE: subtract a small value to avoid having the dimension itself set # as a coordinate, when the coordinates are converted to np.float32 new_x = old_x + dist_x new_x = np.clip(new_x, a_min=0, a_max=spp._land_dim[0] - 0.001) new_y = old_y + dist_y new_y = np.clip(new_y, a_min=0, a_max=spp._land_dim[1] - 0.001) # then feed the new locations into each individual's set_pos method [ind._set_pos(x, y) for ind, x, y in zip(spp.values(), new_x, new_y)]
def sin(x, unit='rad'): if unit == 'rad': return _sin(x) elif unit == 'deg': return _sin(deg_to_rad(x))