def elaz2radec_lst(el, az, lst, lat = 38.43312) : """DO NOT USE THIS ROUTINE FOR ANTHING THAT NEEDS TO BE RIGHT. IT DOES NOT CORRECT FOR PRECESSION. Calculates the Ra and Dec from elavation, aximuth, LST and Latitude. This function is vectorized with numpy so should be fast. Standart numpy broadcasting should also work. All angles in degrees, lst in seconds. Latitude defaults to GBT. """ # Convert everything to radians. el = sp.radians(el) az = sp.radians(az) lst = sp.array(lst, dtype = float)*2*sp.pi/86400 lat = sp.radians(lat) # Calculate dec. dec = sp.arcsin(sp.sin(el)*sp.sin(lat) + sp.cos(el)*sp.cos(lat)*sp.cos(az)) # Calculate the hour angle ha = sp.arccos((sp.sin(el) - sp.sin(lat)*sp.sin(dec)) / (sp.cos(lat)*sp.cos(dec))) ra = sp.degrees(lst - ha) % 360 return ra, sp.degrees(dec)
def elaz2radec_lst(el, az, lst, lat=38.43312): """DO NOT USE THIS ROUTINE FOR ANTHING THAT NEEDS TO BE RIGHT. IT DOES NOT CORRECT FOR PRECESSION. Calculates the Ra and Dec from elavation, aximuth, LST and Latitude. This function is vectorized with numpy so should be fast. Standart numpy broadcasting should also work. All angles in degrees, lst in seconds. Latitude defaults to GBT. """ # Convert everything to radians. el = sp.radians(el) az = sp.radians(az) lst = sp.array(lst, dtype=float) * 2 * sp.pi / 86400 lat = sp.radians(lat) # Calculate dec. dec = sp.arcsin( sp.sin(el) * sp.sin(lat) + sp.cos(el) * sp.cos(lat) * sp.cos(az)) # Calculate the hour angle ha = sp.arccos( (sp.sin(el) - sp.sin(lat) * sp.sin(dec)) / (sp.cos(lat) * sp.cos(dec))) ra = sp.degrees(lst - ha) % 360 return ra, sp.degrees(dec)
def transformPicture(self, accelData): x, y, z = accelData[0], accelData[1], accelData[2] offset = 512 # rotate if self.wm.buttons["A"]: self.c += 1 print(self.c) if self.c % 2 == 0: centeredZ = z - offset centeredX = x - offset rot_angle = int( -(scipy.degrees(scipy.arctan2(centeredZ, centeredX)) - 90)) if rot_angle < 0: rot_angle = 360 + rot_angle self.image.setPixmap( self.pixmap.transformed( QtGui.QTransform().rotate(rot_angle), 1).scaledToHeight(400)) # zoom if self.wm.buttons["Down"]: centeredZ = z - offset centeredY = y - offset tilt_angle = scipy.degrees(scipy.arctan2(centeredZ, centeredY)) - 90 scale_val = abs(tilt_angle / 100) self.image.setPixmap( self.pixmap.transformed(QtGui.QTransform().scale( scale_val, scale_val)))
def main(): satstress_test_dir = os.path.dirname(os.path.abspath(__file__)) test_outfile = os.path.join(satstress_test_dir, "test_nsr_diurnal.pkl") test_satellite = os.path.join("input", "Europa.satellite") # Create a new satellite object, as defined by the input file: the_sat = satstress.Satellite(open(test_satellite, 'r')) # Create a StressCalc object, that calculates both the NSR and Diurnal # stresses on the Satellite just instantiated: the_stresses = satstress.StressCalc( [satstress.Diurnal(the_sat), satstress.NSR(the_sat)]) # do a series of calculations, varying all the inputs at each iteration theta = 0.0 phi = 0.0 t = 0.0 # a list to store the calculation results in for later checking Taulist = [] while the_stresses.stresses[1].Delta( ) > 0.01 and t < 2.0 * scipy.pi / the_sat.mean_motion(): print("""Tau(theta = %g, phi = %g, time = %g, Delta = %g) = """ % (scipy.degrees(theta), scipy.degrees(phi), t, the_stresses.stresses[1].Delta())) Taulist.append(the_stresses.tensor(theta=theta, phi=phi, t=0)) print Taulist[-1], "\n" theta = theta + scipy.pi / 23.0 phi = phi + scipy.pi / 11.0 t = t + (scipy.pi / 11.0) / the_sat.mean_motion() # Re-construct the NSR stress (and the_stresses StressCalc object) # changing the forcing period, so that we can have the NSR stresses # vary with each iteration too. the_sat.nsr_period = the_sat.nsr_period / 1.5 the_stresses = satstress.StressCalc( [satstress.Diurnal(the_sat), satstress.NSR(the_sat)]) # Now we want to compare this against reference output, just to make sure # that we're getting the right numbers... pickledTau = pickle.load(open(test_outfile, 'r')) for (tau1, tau2) in zip(Taulist, pickledTau): if tau1.all() != tau2.all(): print("\nTest failed. :(\n") sys.exit(1) print("\nTest passed! :)\n") sys.exit()
def matrixToEuler(m,order='Aerospace',inDegrees=True): if order == 'Aerospace' or order == 'ZYX': sp = -m[2,0] if sp < (1-EPS): if sp > (-1+EPS): p = arcsin(sp) r = arctan2(m[2,1],m[2,2]) y = arctan2(m[1,0],m[0,0]) else: p = -pi/2. r = 0 y = pi-arctan2(-m[0,1],m[0,2]) else: p = pi/2. y = arctan2(-m[0,1],m[0,2]) r = 0 if inDegrees: return degrees((y,p,r)) else: return (y,p,r) elif order == 'BVH' or order == 'ZXY': sx = m[2,1] if sx < (1-EPS): if sx > (-1+EPS): x = arcsin(sx) z = arctan2(-m[0,1],m[1,1]) y = arctan2(-m[2,0],m[2,2]) else: x = -pi/2 y = 0 z = -arctan2(m[0,2],m[0,0]) else: x = pi/2 y = 0 z = arctan2(m[0,2],m[0,0]) if inDegrees: return degrees((z,x,y)) else: return (z,x,y) elif order == "ZXZ": x = arccos(m[2,2]) z2 = arctan2(m[2,0],m[2,1]) z1 = arctan2(m[0,2],-m[1,2]) if inDegrees: return degrees((z1,x,z2)) else: return (z1,x,z2)
def _update_strain(self): self.e = (self.exy - self.eyx) / 2 self.k = (self.exx + self.eyy) * 1000000. / 2 self.strain = scipy.sqrt((self.exx - self.eyy) * (self.exx - self.eyy) + (self.exy + self.eyx) * (self.exy + self.eyx)) * 1000000. self.k_max = self.k + self.strain / 2 self.k_min = self.k - self.strain / 2 self.az = scipy.degrees(2 * scipy.arctan2(self.exy + self.eyx, self.eyy - self.exx))
def apparent_elevation(theta_true, height): """ Calculate the apparent elevation of the target. :param theta_true: The true elevation angle (degrees). :param height: The height of the radar (km). :return: The apparent elevation angle of the target (degrees). """ def integrand(z): """ Determine the integrand for calculating the apparent elevation angle. :param z: The altitude (km). :return: The integrand. """ # Effective radius of the Earth (km) re = 6378.137 # Standard values a = 0.000315 b = 0.1361 # Refractive index and derivative as a function of altitude n_z = 1. + a * exp(-b * z) np_z = -(a * b * exp(-b * z)) # Refractive index at the given height n_h = 1. + a * exp(-b * height) tan_phi = tan( arccos(((re + height) * n_h) / ((re + z) * n_z) * cos(radians(theta_true)))) return np_z / (n_z * tan_phi) return theta_true - degrees(integrate.romberg(integrand, height, 1000))
def edgeStrength(self, phgeo, mask, kernelw): edges = canny(phgeo, sigma=kernelw) bounds = find_boundaries(edges, mode='thick') slopedeg = degrees(self.slope(phgeo)) histv, _ = np.histogram(abs(slopedeg[(bounds & mask)]), bins=self._slopeBins) return histv
def _update_canvas(self): """ Update the figure when the user changes an input value. :return: """ frequency = float(self.frequency.text()) cone_half_angle = radians(float(self.cone_half_angle.text())) base_radius = float(self.base_radius.text()) # Set the incident angles incident_angle = linspace(0, pi, 1801) # Calculate the radar cross section rcs = array([ radar_cross_section(frequency, cone_half_angle, base_radius, ia) for ia in incident_angle ]) # Clear the axes for the updated plot self.axes1.clear() # Display the results self.axes1.plot(degrees(incident_angle), 10 * log10(rcs[:, 0]), '', label='VV') self.axes1.plot(degrees(incident_angle), 10 * log10(rcs[:, 1]), '--', label='HH') # Set the plot title and labels self.axes1.set_title('RCS vs Incident Angle', size=14) self.axes1.set_ylabel('RCS (dBsm)', size=12) self.axes1.set_xlabel('Incident Angle (deg)', size=12) # Set the tick label size self.axes1.tick_params(labelsize=12) # Set the legend self.axes1.legend(loc='upper right', prop={'size': 10}) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Update the canvas self.my_canvas.draw()
def _update_canvas(self): """ Update the figure when the user changes an input value :return: """ # Get the parameters from the form frequency = float(self.frequency.text()) number_of_elements = int(self.number_of_elements.text()) scan_angle = float(self.scan_angle.text()) element_spacing = float(self.element_spacing.text()) side_lobe_level = float(self.side_lobe_level.text()) # Get the selected antenna from the form antenna_type = self.antenna_type.currentText() # Set the angular span theta = linspace(0.0, pi, 1000) # Set up the args kwargs = { 'number_of_elements': number_of_elements, 'scan_angle': radians(scan_angle), 'element_spacing': element_spacing, 'frequency': frequency, 'theta': theta, 'window_type': antenna_type, 'side_lobe_level': side_lobe_level } # Get the array factor af = linear_array.array_factor(**kwargs) # Clear the axes for the updated plot self.axes1.clear() # Create the line plot self.axes1.plot(degrees(theta), 20.0 * log10(abs(af) + finfo(float).eps), '') # Set the y axis limit self.axes1.set_ylim(-80, 5) # Set the x and y axis labels self.axes1.set_xlabel("Theta (degrees)", size=12) self.axes1.set_ylabel("Array Factor (dB)", size=12) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Set the plot title and labels self.axes1.set_title('Linear Array Antenna Pattern', size=14) # Set the tick label size self.axes1.tick_params(labelsize=12) # Update the canvas self.my_canvas.draw()
def errorAngle(actual,estimate): error = actual*estimate.conjugate() error.normalise() # Cast error to float so that we can deal with fixed point numbers # throws an error otherwise eAngle = degrees(2*arccos(float(error.w))) eAngle = abs(eAngle - 360) if eAngle > 180 else eAngle return eAngle
def collectData(self, accelData): if self.count < 32: self.count += 1 x, z = accelData[0], accelData[2] rot_angle = int(-(scipy.degrees(scipy.arctan2(z - 512, x - 512)) - 90)) self.list.append(rot_angle) else: self.transformPicture(accelData) self.count = 0 self.list = []
def _update_strain(self): self.e = (self.exy - self.eyx) / 2 self.k = (self.exx + self.eyy) * 1000000. / 2 self.strain = scipy.sqrt((self.exx - self.eyy) * (self.exx - self.eyy) + (self.exy + self.eyx) * (self.exy + self.eyx)) * 1000000. self.k_max = self.k + self.strain / 2 self.k_min = self.k - self.strain / 2 self.az = scipy.degrees( 2 * scipy.arctan2(self.exy + self.eyx, self.eyy - self.exx))
def nichols_plot(sys_list, omega=None, grid=None): """Nichols plot for a system Plots a Nichols plot for the system over a (optional) frequency range. Parameters ---------- sys_list : list of LTI, or LTI List of linear input/output systems (single system is OK) omega : array_like Range of frequencies (list or bounds) in rad/sec grid : boolean, optional True if the plot should include a Nichols-chart grid. Default is True. Returns ------- None """ # Get parameter values grid = config._get_param('nichols', 'grid', grid, True) # If argument was a singleton, turn it into a list if not getattr(sys_list, '__iter__', False): sys_list = (sys_list, ) # Select a default range if none is provided if omega is None: omega = default_frequency_range(sys_list) for sys in sys_list: # Get the magnitude and phase of the system mag_tmp, phase_tmp, omega = sys.freqresp(omega) mag = np.squeeze(mag_tmp) phase = np.squeeze(phase_tmp) # Convert to Nichols-plot format (phase in degrees, # and magnitude in dB) x = unwrap(sp.degrees(phase), 360) y = 20 * sp.log10(mag) # Generate the plot plt.plot(x, y) plt.xlabel('Phase (deg)') plt.ylabel('Magnitude (dB)') plt.title('Nichols Plot') # Mark the -180 point plt.plot([-180], [0], 'r+') # Add grid if grid: nichols_grid()
def calSquareDegree_conver(sqdeg,dec0): """ input sqdeg: unit in deg. dec0: dec center in decimal deg. assume decw = sqrt(sqdeg) return: raw ref:http://en.wikipedia.org/wiki/Solid_angle """ sa = sqdeg/((180./S.pi)**2) decw = S.sqrt(sqdeg) raw = S.degrees(sa /(S.sin(S.radians(dec0+decw/2.) ) - S.sin(S.radians(dec0-decw/2.)))) return raw
def stopRecordingRot(self): self.wm.accelerometer.unregister_callback(self.recordAccel) for value in self.currentGestureData: x, y, z = value[0], value[1], value[2] rot_angle = int(-(sp.degrees(sp.arctan2(z-512, x-512)) - 90)) self.rotList.append(rot_angle) print(self.rotList) self.currentGestureData = [] direction = self.getDirection() if direction == 1: self.callback(2) else: self.callback(-2)
def nichols_plot(syslist, omega=None, grid=True): """Nichols plot for a system Plots a Nichols plot for the system over a (optional) frequency range. Parameters ---------- syslist : list of LTI, or LTI List of linear input/output systems (single system is OK) omega : array_like Range of frequencies (list or bounds) in rad/sec grid : boolean, optional True if the plot should include a Nichols-chart grid. Default is True. Returns ------- None """ # If argument was a singleton, turn it into a list if (not getattr(syslist, '__iter__', False)): syslist = (syslist,) # Select a default range if none is provided if omega is None: omega = default_frequency_range(syslist) for sys in syslist: # Get the magnitude and phase of the system mag_tmp, phase_tmp, omega = sys.freqresp(omega) mag = np.squeeze(mag_tmp) phase = np.squeeze(phase_tmp) # Convert to Nichols-plot format (phase in degrees, # and magnitude in dB) x = unwrap(sp.degrees(phase), 360) y = 20*sp.log10(mag) # Generate the plot plt.plot(x, y) plt.xlabel('Phase (deg)') plt.ylabel('Magnitude (dB)') plt.title('Nichols Plot') # Mark the -180 point plt.plot([-180], [0], 'r+') # Add grid if grid: nichols_grid()
def transformPicture(self, accelData): x, y, z = accelData[0], accelData[1], accelData[2] offset = 512 # rotate if self.wm.buttons["A"]: self.c += 1 print(self.c) if self.c % 2 == 0: centeredZ = z - offset centeredX = x - offset rot_angle = int(-(scipy.degrees(scipy.arctan2(centeredZ, centeredX)) - 90)) if rot_angle < 0: rot_angle = 360 + rot_angle self.image.setPixmap(self.pixmap.transformed( QtGui.QTransform().rotate(rot_angle), 1).scaledToHeight(400)) # zoom if self.wm.buttons["Down"]: centeredZ = z - offset centeredY = y - offset tilt_angle = scipy.degrees(scipy.arctan2(centeredZ, centeredY)) - 90 scale_val = abs(tilt_angle / 100) self.image.setPixmap(self.pixmap.transformed(QtGui.QTransform().scale(scale_val, scale_val)))
def __init__(self, foilid, material, top_radius_cm, bottom_radius_cm, angle_rad): self.foilid = foilid self.material = material self.top_radius_cm = top_radius_cm self.bottom_radius_cm = bottom_radius_cm self.angle_rad = angle_rad self.angle_deg = scipy.degrees(self.angle_rad) self.geo_area_cm2 = self.getGeometricalArea() self.use_flag_mark = ' ' self.roughness_A = 0.0 self.n_spoke1 = 0 self.n_spoke2 = 0 self.spoke1_wid = 0.0 self.spoke2_wid = 0.0
def zoomPicture(self, accelData): y, z = accelData[1], accelData[2] offset = 512 centeredZ = z - offset centeredY = y - offset tilt_angle = scipy.degrees(scipy.arctan2(centeredZ, centeredY)) - 90 if tilt_angle <= -90: tilt_angle = 360 + tilt_angle scale_val = (tilt_angle / 100) + 1 if scale_val < 0: scale_val = -scale_val self.image.setPixmap( self.pixmap.transformed( QtGui.QTransform().scale(scale_val, scale_val), QtCore.Qt.SmoothTransformation)) self.drawingPixmap = self.image.pixmap() self.resetUndoRedoStack()
def main(): satstress_test_dir = os.path.dirname(os.path.abspath(__file__)) test_outfile = os.path.join(satstress_test_dir, "test_nsr_diurnal.pkl") test_satellite = os.path.join("input", "Europa.satellite") # Create a new satellite object, as defined by the input file: the_sat = satstress.Satellite(open(test_satellite,'r')) # Create a StressCalc object, that calculates both the NSR and Diurnal # stresses on the Satellite just instantiated: the_stresses = satstress.StressCalc([satstress.Diurnal(the_sat), satstress.NSR(the_sat)]) # do a series of calculations, varying all the inputs at each iteration theta = 0.0 phi = 0.0 t = 0.0 # a list to store the calculation results in for later checking Taulist = [] while the_stresses.stresses[1].Delta() > 0.01 and t < 2.0*scipy.pi/the_sat.mean_motion(): print("""Tau(theta = %g, phi = %g, time = %g, Delta = %g) = """ % (scipy.degrees(theta), scipy.degrees(phi), t, the_stresses.stresses[1].Delta())) Taulist.append(the_stresses.tensor(theta=theta, phi=phi, t=0)) print Taulist[-1], "\n" theta = theta + scipy.pi/23.0 phi = phi + scipy.pi/11.0 t = t + (scipy.pi/11.0)/the_sat.mean_motion() # Re-construct the NSR stress (and the_stresses StressCalc object) # changing the forcing period, so that we can have the NSR stresses # vary with each iteration too. the_sat.nsr_period = the_sat.nsr_period / 1.5 the_stresses = satstress.StressCalc([satstress.Diurnal(the_sat), satstress.NSR(the_sat)]) # Now we want to compare this against reference output, just to make sure # that we're getting the right numbers... pickledTau = pickle.load(open(test_outfile, 'r')) for (tau1, tau2) in zip(Taulist, pickledTau): if tau1.all() != tau2.all(): print("\nTest failed. :(\n") sys.exit(1) print("\nTest passed! :)\n") sys.exit()
def angsep(x1,y1,x2,y2): # """ # spherical angle separation, aka haversine formula # input and output are in degrees # """ dlat = sp.radians(y2 - y1) dlon = sp.radians(x2 - x1) y1 = sp.radians(y1) y2 = sp.radians(y2) a = sp.sin(dlat/2.)*sp.sin(dlat/2.) + sp.cos(y1)*sp.cos(y2)*sp.sin(dlon/2.)*sp.sin(dlon/2.) #if a<0 or a>1.: print 'a:',a,x1,y1,x2,y2,dlat,dlon,'!!!!!' try: c = 2*sp.arctan2(sp.sqrt(a), sp.sqrt(1.-a)) except: print '!!!:',a,x1,y1,x2,y2,dlat,dlon,'!!!!!' c=0 pass return sp.degrees(c)
def obsolete_calc_azimuth(lat1, lon1, lat2, lon2): """NOT USED Calculate a trace azimuth given start and end positions. lat1 latitude of start point lon1 longitude of start point lat2 latitude of end point lon2 longitude of end point Returns azimuth at start point in degrees, in range [0, 360). """ lat1 = radians(lat1) lon1 = radians(lon1) lat2 = radians(lat2) lon2 = radians(lon2) numerator = sin(lon1 - lon2) * cos(lat2) denominator = sin(arccos((sin(lat2) * sin(lat1)) + (cos(lat1) * cos(lat2) * cos(lon2 - lon1)))) azimuth = degrees(arcsin(numerator / denominator)) return azimuth
def obsolete_calc_azimuth(lat1, lon1, lat2, lon2): """NOT USED Calculate a trace azimuth given start and end positions. lat1 latitude of start point lon1 longitude of start point lat2 latitude of end point lon2 longitude of end point Returns azimuth at start point in degrees, in range [0, 360). """ lat1 = radians(lat1) lon1 = radians(lon1) lat2 = radians(lat2) lon2 = radians(lon2) numerator = sin(lon1 - lon2) * cos(lat2) denominator = sin( arccos((sin(lat2) * sin(lat1)) + (cos(lat1) * cos(lat2) * cos(lon2 - lon1)))) azimuth = degrees(arcsin(numerator / denominator)) return azimuth
def obsolete_calc_azimuth3(lat1, lon1, lat2, lon2): """NOT USED Calculate a trace azimuth given start and end positions. lat1 latitude of start point lon1 longitude of start point lat2 latitude of end point lon2 longitude of end point Returns azimuth at start point in degrees, in range [0, 360). """ x = (lon1 - lon2) * (cos(lat1)) y = lat1 - lat2 if y == 0: azimuth = 90 elif x == 0: azimuth = 0 else: azimuth = degrees(arctan2(x, y)) return azimuth
def plot_ellipse(ax, x, y, a, b, ang, **kwargs): """Plot ellipse(s) on the specified axis. Parameters ---------- ax : axis Axis to plot on. x : float X coordinate of center. All ellipses have same center. y : float Y coordinate of center. All ellipses have same center. a : float or 1d array Major axis of ellipse(s). b : float or 1d array Minor axis of ellipse(s). ang : float Angle of ellipse(s), in radian. All ellipses have same angle. """ for av, bv in zip(a, b): ell = Ellipse([x, y], av, bv, angle=scipy.degrees(ang), **kwargs) ax.add_artist(ell)
def _update_canvas(self): """ Update the figure when the user changes an input value. :return: """ frequency = float(self.frequency.text()) nose_radius = float(self.nose_radius.text()) base_radius = float(self.base_radius.text()) length = float(self.length.text()) # Set the incident angles incident_angle = linspace(0, pi, 1801) # Calculate the radar cross section rcs = array([ radar_cross_section(frequency, nose_radius, base_radius, length, ia) for ia in incident_angle ]) # Clear the axes for the updated plot self.axes1.clear() # Display the results self.axes1.plot(degrees(incident_angle), 10 * log10(rcs), '') # Set the plot title and labels self.axes1.set_title('RCS vs Incident Angle', size=14) self.axes1.set_ylabel('RCS (dBsm)', size=12) self.axes1.set_xlabel('Incident Angle (deg)', size=12) # Set the tick label size self.axes1.tick_params(labelsize=12) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Update the canvas self.my_canvas.draw()
def populate_geo_coord_polygon(polygon, number_of_points, seed=None, exclude=None, randoms=None): """Populate a polygon with uniformly distributed points. Takes into account the curvature of the earth. Input: polygon - list of vertices of polygon, vertices in (lat, long) number_of_points - (optional) number of points seed - seed for random number generator (default=None) exclude - list of polygons (inside main polygon) from where points should be excluded randoms - array of numbers between 0 and 1 to be used as the random numbers for calculating the latitude of the points. Obviously is this case the numbers are not random. This should just be used for writing tests. Output: points - list of points inside polygon Examples: populate_polygon( [[0,0], [-40,0], [-40,1], [0,1]], 6, randoms = (0.0, 0.2, 0.4, 0.6, 0.8, 1.0)) will return six not so randomly selected points inside the unit square """ if seed is not None: random.seed(seed) if randoms is None: randoms = random.random(number_of_points) else: # Ensure randoms is a numpy array randoms = array(randoms) # print polygon points = [] # Find outer extent of polygon max_x = min_x = polygon[0][1] max_y = min_y = polygon[0][0] for point in polygon[1:]: x = point[1] if x > max_x: max_x = x if x < min_x: min_x = x y = point[0] if y > max_y: max_y = y if y < min_y: min_y = y max_y_rad = radians(max_y) min_y_rad = radians(min_y) # Do this until we have a points array of points inside the polygon that # greater or equal the number of points requested (we'll slice at return) while len(points) < number_of_points: y_p_rad = arcsin(randoms * abs((sin(max_y_rad) - sin(min_y_rad))) + sin(min_y_rad)) y_p = degrees(y_p_rad) x_p = random.uniform(min_x, max_x, number_of_points) points_p = array([y_p, x_p]).T points_p = points_p[inside_polygon(points_p.tolist(), polygon)] if exclude is not None and len(points_p) > 0: for ex_poly in exclude: points_p = points_p[ outside_polygon(points_p.tolist(), ex_poly)] if len(points_p) > 0: points.extend(points_p.tolist()) randoms = random.random(number_of_points) return points[:number_of_points]
def setFoilDimension(self): print('--- method: %s ---' % sys._getframe().f_code.co_name) if not os.path.exists(self.yamlfile): sys.stderr.write('input parameter_file does not exist.: %s\n' % self.param['foil_dimension_file']) quit() self.foils = [] self.use_foilid_list = [] print( "------------------------------------------------------------------------" ) print("Foil Input Dimension") print( "Foil-ID : Material, Top radi, Bottom radi, Angle, Angle, GeoArea Use?" ) print( " (cm) (cm) (rad) (deg) (cm2) " ) print( "------------------------------------------------------------------------" ) total_geometric_area = 0.0 total_geometric_area_obs1 = 0.0 total_geometric_area_obs2 = 0.0 for line in open(self.param['foil_dimension_file']): cols = line.split() if cols[0] == '#': continue foil_id = len(self.foils) + 1 foil_parab_top_radius = float(cols[0]) # mm foil_parab_bot_radius = float(cols[1]) # mm foil_parab_angle_rad = float(cols[2]) foil_parab_angle_deg = scipy.degrees(foil_parab_angle_rad) foil_parab_bot_radius_cm = 0.1 * foil_parab_bot_radius foil_parab_top_radius_cm = 0.1 * foil_parab_top_radius if foil_parab_angle_deg <= self.param[ 'maximum_incident_angle_deg'] and ( 2.0 * foil_parab_top_radius_cm <= self.param['maximum_diameter_cm']): self.use_foilid_list.append(foil_id) foil_cone_angle_rad = foil_parab_angle_rad # assumed for CubeSat self.foils.append( niresp.xrc.Foil(foil_id, self.material, foil_parab_top_radius_cm, foil_parab_bot_radius_cm, foil_cone_angle_rad)) self.foils[-1].roughness_A = self.param['roughness_A'] self.foils[-1].n_spoke1 = self.param['spoke']['n_spoke1'] self.foils[-1].n_spoke2 = self.param['spoke']['n_spoke2'] self.foils[-1].spoke1_wid = self.param['spoke']['spoke1_wid'] self.foils[-1].spoke2_wid = self.param['spoke']['spoke2_wid'] self.foils[-1].setUseFlag(self.use_foilid_list) self.foils[-1].surface_model = self.param['surface_model'] self.foils[-1].showProperty() foil_geometric_area = (foil_parab_top_radius_cm**2 - foil_parab_bot_radius_cm**2) * np.pi total_geometric_area += foil_geometric_area total_geometric_area_obs1 += foil_geometric_area * self.foils[ -1].getSpokeObsculation() subtraction = float(self.param['spoke']['n_spoke1']) * float( self.param['spoke']['spoke1_wid']) * 10.0 * ( self.foils[-1].top_radius_cm - self.foils[-1].bottom_radius_cm) * 10.0 subtraction += float(self.param['spoke']['n_spoke2']) * float( self.param['spoke']['spoke2_wid']) * 10.0 * ( self.foils[-1].top_radius_cm - self.foils[-1].bottom_radius_cm) * 10.0 value = foil_geometric_area - subtraction total_geometric_area_obs2 += value self.param['use_foilid_list'] = self.use_foilid_list self.param['numof_use_foils'] = len(self.param['use_foilid_list']) print("Total geometric area (cm2):", total_geometric_area) print("after subtracting spoke obsculation: ", total_geometric_area_obs2) obst_1 = float(self.param['spoke']['n_spoke1']) * float( self.param['spoke']['spoke1_wid']) * ( self.foils[-1].top_radius_cm - self.foils[0].bottom_radius_cm) obst_2 = float(self.param['spoke']['n_spoke2']) * float( self.param['spoke']['spoke2_wid']) * ( self.foils[-1].top_radius_cm - self.foils[0].bottom_radius_cm) print( "------------------------------------------------------------------------" )
def _update_canvas(self): """ Update the figure when the user changes an input value. :return: """ # Set up the incident angles incident_angle = linspace(0., 0.5 * pi, 1000) # Set up the keyword args kwargs = { 'frequency': float(self.frequency.text()), 'incident_angle': incident_angle, 'relative_permittivity': self.relative_permittivity, 'relative_permeability': self.relative_permeability, 'conductivity': self.conductivity } # Calculate the reflection and transmission coefficients reflection_coefficient_te, transmission_coefficient_te, reflection_coefficient_tm, \ transmission_coefficient_tm = plane_waves.reflection_transmission(**kwargs) # Clear the axes for the updated plot self.axes1.clear() self.axes2.clear() # Display the reflection coefficients self.axes1.plot(degrees(incident_angle), abs(reflection_coefficient_te), 'b', label='|$\Gamma_{TE}$|') self.axes1.plot(degrees(incident_angle), abs(reflection_coefficient_tm), 'b--', label='|$\Gamma_{TM}$|') # Display the transmission coefficients self.axes2.plot(degrees(incident_angle), abs(transmission_coefficient_te), 'r', label='|$T_{TE}$|') self.axes2.plot(degrees(incident_angle), abs(transmission_coefficient_tm), 'r--', label='|$T_{TM}$|') # Set the plot title and labels self.axes1.set_title('Plane Wave Reflection and Transmission', size=14) self.axes1.set_xlabel('Incident Angle (degrees)', size=12) self.axes1.set_ylabel('|Reflection Coefficient|', size=12) self.axes2.set_ylabel('|Transmission Coefficient|', size=12) # Set the tick label size self.axes1.tick_params(labelsize=12) self.axes2.tick_params(labelsize=12) # Set the legend self.axes1.legend(loc='upper right', prop={'size': 10}) self.axes2.legend(loc='upper left', prop={'size': 10}) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Update the canvas self.my_canvas.draw()
def nichols_grid(cl_mags=None, cl_phases=None): """Nichols chart grid Plots a Nichols chart grid on the current axis, or creates a new chart if no plot already exists. Parameters ---------- cl_mags : array-like (dB), optional Array of closed-loop magnitudes defining the iso-gain lines on a custom Nichols chart. cl_phases : array-like (degrees), optional Array of closed-loop phases defining the iso-phase lines on a custom Nichols chart. Must be in the range -360 < cl_phases < 0 Returns ------- None """ # Default chart size ol_phase_min = -359.99 ol_phase_max = 0.0 ol_mag_min = -40.0 ol_mag_max = default_ol_mag_max = 50.0 # Find bounds of the current dataset, if there is one. if plt.gcf().gca().has_data(): ol_phase_min, ol_phase_max, ol_mag_min, ol_mag_max = plt.axis() # M-circle magnitudes. if cl_mags is None: # Default chart magnitudes # The key set of magnitudes are always generated, since this # guarantees a recognizable Nichols chart grid. key_cl_mags = np.array([-40.0, -20.0, -12.0, -6.0, -3.0, -1.0, -0.5, 0.0, 0.25, 0.5, 1.0, 3.0, 6.0, 12.0]) # Extend the range of magnitudes if necessary. The extended arange # will end up empty if no extension is required. Assumes that closed-loop # magnitudes are approximately aligned with open-loop magnitudes beyond # the value of np.min(key_cl_mags) cl_mag_step = -20.0 # dB extended_cl_mags = np.arange(np.min(key_cl_mags), ol_mag_min + cl_mag_step, cl_mag_step) cl_mags = np.concatenate((extended_cl_mags, key_cl_mags)) # N-circle phases (should be in the range -360 to 0) if cl_phases is None: # Choose a reasonable set of default phases (denser if the open-loop # data is restricted to a relatively small range of phases). key_cl_phases = np.array([-0.25, -45.0, -90.0, -180.0, -270.0, -325.0, -359.75]) if np.abs(ol_phase_max - ol_phase_min) < 90.0: other_cl_phases = np.arange(-10.0, -360.0, -10.0) else: other_cl_phases = np.arange(-10.0, -360.0, -20.0) cl_phases = np.concatenate((key_cl_phases, other_cl_phases)) else: assert ((-360.0 < np.min(cl_phases)) and (np.max(cl_phases) < 0.0)) # Find the M-contours m = m_circles(cl_mags, phase_min=np.min(cl_phases), phase_max=np.max(cl_phases)) m_mag = 20*sp.log10(np.abs(m)) m_phase = sp.mod(sp.degrees(sp.angle(m)), -360.0) # Unwrap # Find the N-contours n = n_circles(cl_phases, mag_min=np.min(cl_mags), mag_max=np.max(cl_mags)) n_mag = 20*sp.log10(np.abs(n)) n_phase = sp.mod(sp.degrees(sp.angle(n)), -360.0) # Unwrap # Plot the contours behind other plot elements. # The "phase offset" is used to produce copies of the chart that cover # the entire range of the plotted data, starting from a base chart computed # over the range -360 < phase < 0. Given the range # the base chart is computed over, the phase offset should be 0 # for -360 < ol_phase_min < 0. phase_offset_min = 360.0*np.ceil(ol_phase_min/360.0) phase_offset_max = 360.0*np.ceil(ol_phase_max/360.0) + 360.0 phase_offsets = np.arange(phase_offset_min, phase_offset_max, 360.0) for phase_offset in phase_offsets: # Draw M and N contours plt.plot(m_phase + phase_offset, m_mag, color='gray', linestyle='dotted', zorder=0) plt.plot(n_phase + phase_offset, n_mag, color='gray', linestyle='dotted', zorder=0) # Add magnitude labels for x, y, m in zip(m_phase[:][-1] + phase_offset, m_mag[:][-1], cl_mags): align = 'right' if m < 0.0 else 'left' plt.text(x, y, str(m) + ' dB', size='small', ha=align, color='gray') # Fit axes to generated chart plt.axis([phase_offset_min - 360.0, phase_offset_max - 360.0, np.min(cl_mags), np.max([ol_mag_max, default_ol_mag_max])])
def __init__(self, like, model, withErrors=False, param1=False, param2=False): self.like = like self.model = model self.params = like.freeParameters() self.vpars = [p.value for p in self.params] self.sigma = sp.array([p.error for p in self.params]) bounds = [p.bounds for p in self.params] print("Minimizing...", self.vpars, "with bounds", bounds) self.res = minimize(self.negloglike, self.vpars, bounds=bounds, method='L-BFGS-B') print(self.res, 'with noErrors =', withErrors) if (withErrors): hess = nd.Hessian(self.negloglike)(self.res.x) eigvl, eigvc = la.eig(hess) print ('Hessian', hess, eigvl,) self.cov = la.inv(hess) print('Covariance matrix \n', self.cov) # set errors: for i, pars in enumerate(self.params): pars.setError(sp.sqrt(self.cov[i, i])) # update with the final result self.result(self.negloglike(self.res.x)) if param1 and param2: for i, par in enumerate(self.like.freeParameters()): if param1 == par.name: par1 = i elif param2 == par.name: par2 = i fig = plt.figure(figsize=(6,6)) ax = fig.add_subplot(111) #, aspect='equal') val,vec = la.eig(self.cov[[par1,par2], :][:, [par1,par2]]) vec=vec.T mn = self.res.x vec[0]*=sp.sqrt(11.83*sp.real(val[0])) vec[1]*=sp.sqrt(11.83*sp.real(val[1])) plt.plot(mn[par1],mn[par2],'bo', label=self.model) plt.plot([mn[par1]-vec[0][0],mn[par1]+vec[0][0]], [mn[par2]-vec[0][1],mn[par2]+vec[0][1]],'r-') plt.plot([mn[par1]-vec[1][0],mn[par1]+vec[1][0]], [mn[par2]-vec[1][1],mn[par2]+vec[1][1]],'r-') def eigsorted(cov): vals, vecs = sp.linalg.eigh(cov) order = vals.argsort()[::-1] return vals[order], vecs[:,order] vals, vecs = eigsorted(self.cov[[par1,par2], :][:, [par1,par2]]) theta = sp.degrees(np.arctan2(*vecs[:,0][::-1])) sigmas = [2.3, 5.99, 11.83] for sigs in sigmas: w, h = 2 * sp.sqrt(vals) * sp.sqrt(sigs) ell = Ellipse(xy=(mn[par1], mn[par2]), width = w, height = h, angle=theta, color='green', lw=4) ell.set_facecolor('none') ax.add_artist(ell) plt.legend(loc='best') plt.title('+'.join(self.like.compositeNames()), fontsize=10) plt.show()
def _update_canvas(self): """ Update the figure when the user changes an input value :return: """ # Get the parameters from the form frequency = float(self.frequency.text()) number_of_elements = int(self.number_of_elements.text()) scan_angle_theta = float(self.scan_angle_theta.text()) scan_angle_phi = float(self.scan_angle_phi.text()) radius = float(self.radius.text()) # Set up the theta and phi arrays n = 360 m = int(n / 8) theta, phi = meshgrid(linspace(0.0 * pi, 0.5 * pi, n), linspace(0.0, 2.0 * pi, n)) # Set up the args kwargs = { 'number_of_elements': number_of_elements, 'scan_angle_theta': radians(scan_angle_theta), 'scan_angle_phi': radians(scan_angle_phi), 'radius': radius, 'frequency': frequency, 'theta': theta, 'phi': phi } # Get the array factor af = circular_uniform.array_factor(**kwargs) # Remove the color bar try: self.cbar.remove() except: # Initial plot pass # Clear the axes for the updated plot self.axes1.clear() # U-V coordinates for plotting the antenna pattern uu = sin(theta) * cos(phi) vv = sin(theta) * sin(phi) if self.plot_type.currentIndex() == 0: # Display the results im = self.axes1.pcolor(uu, vv, abs(af), cmap="jet") self.cbar = self.fig.colorbar(im, ax=self.axes1, orientation='vertical') self.cbar.set_label("Normalized Electric Field (V/m)", size=10) # Set the x- and y-axis labels self.axes1.set_xlabel("U (sines)", size=12) self.axes1.set_ylabel("V (sines)", size=12) elif self.plot_type.currentIndex() == 1: # Create the contour plot self.axes1.contour(uu, vv, abs(af), 20, cmap="jet", vmin=-0.2, vmax=1.0) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Set the x- and y-axis labels self.axes1.set_xlabel("U (sines)", size=12) self.axes1.set_ylabel("V (sines)", size=12) else: # Create the line plot self.axes1.plot(degrees(theta[0]), 20.0 * log10(abs(af[m])), '', label='E Plane') self.axes1.plot(degrees(theta[0]), 20.0 * log10(abs(af[0])), '--', label='H Plane') # Set the y axis limit self.axes1.set_ylim(-60, 5) # Set the x and y axis labels self.axes1.set_xlabel("Theta (degrees)", size=12) self.axes1.set_ylabel("Array Factor (dB)", size=12) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Place the legend self.axes1.legend(loc='upper right', prop={'size': 10}) # Set the plot title and labels self.axes1.set_title('Circular Array - Array Factor', size=14) # Set the tick label size self.axes1.tick_params(labelsize=12) # Update the canvas self.my_canvas.draw()
def _update_canvas(self): """ Update the figure when the user changes an input value :return: """ # Get the parameters from the form frequency = float(self.frequency.text()) guide_width = float(self.guide_width.text()) guide_height = float(self.guide_height.text()) horn_width = float(self.horn_width.text()) horn_height = float(self.horn_height.text()) eplane_effective_length = float(self.eplane_effective_length.text()) hplane_effective_length = float(self.hplane_effective_length.text()) # Get the selected antenna from the form antenna_type = self.antenna_type.currentIndex() # Set the range and angular span r = 1.0e9 # Set up the theta and phi arrays n = 400 m = int(n / 4) theta, phi = meshgrid(linspace(0.0, 0.5 * pi, n), linspace(0.0, 2.0 * pi, n)) # Get the antenna parameters and antenna pattern for the selected antenna if antenna_type == 0: total_power_radiated = e_plane_sectoral.power_radiated( guide_width, horn_height) directivity = e_plane_sectoral.directivity( guide_width, horn_height, eplane_effective_length, frequency) _, et, ep, _, _, _ = e_plane_sectoral.far_fields( guide_width, horn_height, eplane_effective_length, frequency, r, theta, phi) elif antenna_type == 1: total_power_radiated = h_plane_sectoral.power_radiated( guide_height, horn_width) directivity = h_plane_sectoral.directivity( guide_height, horn_width, hplane_effective_length, frequency) _, et, ep, _, _, _ = h_plane_sectoral.far_fields( guide_height, horn_width, hplane_effective_length, frequency, r, theta, phi) else: total_power_radiated = pyramidal.power_radiated( horn_width, horn_height) directivity = pyramidal.directivity(horn_width, horn_height, eplane_effective_length, hplane_effective_length, frequency) _, et, ep, _, _, _ = pyramidal.far_fields(horn_width, horn_height, eplane_effective_length, hplane_effective_length, frequency, r, theta, phi) # Populate the form with the correct values self.total_radiated_power.setText( '{:.2e}'.format(total_power_radiated)) self.directivity.setText('{:.2f}'.format(directivity)) # Remove the color bar try: self.cbar.remove() except: # Initial plot pass # Clear the axes for the updated plot self.axes1.clear() # U-V coordinates for plotting the antenna pattern uu = sin(theta) * cos(phi) vv = sin(theta) * sin(phi) # Normalized electric field magnitude for plotting e_mag = sqrt(abs(et * et + ep * ep)) e_mag /= amax(e_mag) if self.plot_type.currentIndex() == 0: # Display the results im = self.axes1.pcolor(uu, vv, e_mag, cmap="jet") self.cbar = self.fig.colorbar(im, ax=self.axes1, orientation='vertical') self.cbar.set_label("Normalized Electric Field(V/m)", size=10) # Set the x- and y-axis labels self.axes1.set_xlabel("U (sines)", size=12) self.axes1.set_ylabel("V (sines)", size=12) elif self.plot_type.currentIndex() == 1: # Create the contour plot self.axes1.contour(uu, vv, e_mag, 20, cmap="jet", vmin=-0.2, vmax=1.0) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Set the x- and y-axis labels self.axes1.set_xlabel("U (sines)", size=12) self.axes1.set_ylabel("V (sines)", size=12) else: # Create the line plot self.axes1.plot(degrees(theta[0]), 20.0 * log10(e_mag[m]), '', label='E Plane') self.axes1.plot(degrees(theta[0]), 20.0 * log10(e_mag[0]), '--', label='H Plane') # Set the y axis limit self.axes1.set_ylim(-40, 5) # Set the x and y axis labels self.axes1.set_xlabel("Theta (degrees)", size=12) self.axes1.set_ylabel("Normalized |E| (dB)", size=12) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Place the legend self.axes1.legend(loc='upper right', prop={'size': 10}) # Set the plot title and labels self.axes1.set_title('Horn Antenna Pattern', size=14) # Set the tick label size self.axes1.tick_params(labelsize=12) # Update the canvas self.my_canvas.draw()
def nichols_grid(cl_mags=None, cl_phases=None): """Nichols chart grid Parameters ---------- cl_mags : array-like (dB), optional Array of closed-loop magnitudes defining the iso-gain lines on a custom Nichols chart. cl_phases : array-like (degrees), optional Array of closed-loop phases defining the iso-phase lines on a custom Nichols chart. Must be in the range -360 < cl_phases < 0 Returns ------- None """ # Default chart size ol_phase_min = -359.99 ol_phase_max = 0.0 ol_mag_min = -40.0 ol_mag_max = default_ol_mag_max = 50.0 # M-circle magnitudes. if cl_mags is None: # Default chart magnitudes key_cl_mags = np.array([ -40.0, -20.0, -12.0, -6.0, -3.0, -1.0, -0.5, 0.0, 0.25, 0.5, 1.0, 3.0, 6.0, 12.0, ]) # Extend the range of magnitudes if necessary. cl_mag_step = -20.0 # dB extended_cl_mags = np.arange(np.min(key_cl_mags), ol_mag_min + cl_mag_step, cl_mag_step) cl_mags = np.concatenate((extended_cl_mags, key_cl_mags)) else: cl_mags = np.array(cl_mags) # N-circle phases (should be in the range -360 to 0) if cl_phases is None: # Choose a reasonable set of default phases key_cl_phases = np.array( [-0.25, -45.0, -90.0, -180.0, -270.0, -325.0, -359.75]) if np.abs(ol_phase_max - ol_phase_min) < 90.0: other_cl_phases = np.arange(-10.0, -360.0, -10.0) else: other_cl_phases = np.arange(-10.0, -360.0, -20.0) cl_phases = np.concatenate((key_cl_phases, other_cl_phases)) else: cl_phases = np.array(cl_phases) assert (-360.0 < np.min(cl_phases)) and (np.max(cl_phases) < 0.0) # Find the M-contours m = m_circles(cl_mags, phase_min=np.min(cl_phases), phase_max=np.max(cl_phases)) m_mag = 20 * sp.log10(np.abs(m)) m_phase = sp.mod(sp.degrees(sp.angle(m)), -360.0) # Unwrap # Find the N-contours n = n_circles(cl_phases, mag_min=np.min(cl_mags), mag_max=np.max(cl_mags)) n_mag = 20 * sp.log10(np.abs(n)) n_phase = sp.mod(sp.degrees(sp.angle(n)), -360.0) # Unwrap # Plot the contours behind other plot elements. # The "phase offset" is used to produce copies of the chart phase_offset_min = 360.0 * np.ceil(ol_phase_min / 360.0) phase_offset_max = 360.0 * np.ceil(ol_phase_max / 360.0) + 360.0 phase_offsets = np.arange(phase_offset_min, phase_offset_max, 360.0) data_m_mag = [] data_n_mag = [] for phase_offset in phase_offsets: for indice in range(m_mag.shape[1]): name = "{} dB".format(cl_mags[indice]) data_m_mag.append({ "x": m_phase[:, indice] + phase_offset, "y": m_mag[:, indice], "name": name, }) for indice in range(n_mag.shape[1]): name = "{} deg".format(cl_phases[indice]) data_n_mag.append({ "x": n_phase[:, indice] + phase_offset, "y": n_mag[:, indice], "name": name, }) return data_m_mag, data_n_mag
def _update_canvas(self): """ Update the figure when the user changes an input value. :return: """ frequency = float(self.frequency.text()) theta_inc = float(self.theta_inc.text()) phi_inc = float(self.phi_inc.text()) phi_obs = float(self.phi_obs.text()) # Set the scattering angles theta = self.theta_obs.text().split(',') theta_obs = linspace(radians(float(theta[0])), radians(float(theta[1])), 721) # Monostatic or bistatic mb = self.type.currentText() rcs_theta = [] rcs_phi = [] kwargs = {'frequency': array([frequency]), 'vertices': self.vertices, 'faces': self.faces, 'phi_inc': radians(phi_inc), 'phi_obs': radians(phi_obs)} b = scattering_matrix.ScatteringMatrix(**kwargs) if mb == 'Monostatic': for to in theta_obs: b.theta_inc = to b.theta_obs = to sm = b.get_scattering_matrix() rcs_theta.append(20.0 * log10(abs(sm[0]) + 1e-10)) rcs_phi.append(20.0 * log10(abs(sm[3]) + 1e-10)) else: b.theta_inc = radians(theta_inc) for to in theta_obs: b.theta_obs = to sm = b.get_scattering_matrix() rcs_theta.append(20.0 * log10(abs(sm[0]) + 1e-10)) rcs_phi.append(20.0 * log10(abs(sm[3]) + 1e-10)) # Clear the axes for the updated plot self.axes1.clear() # Display the results self.axes1.plot(degrees(theta_obs), rcs_phi, '', label='TE$^z$') self.axes1.plot(degrees(theta_obs), rcs_theta, '--', label='TM$^z$') # Set the plot title and labels self.axes1.set_title('Physical Optics RCS vs Observation Angle', size=14) self.axes1.set_ylabel('RCS (dBsm)', size=12) self.axes1.set_xlabel('Observation Angle (deg)', size=12) self.axes1.set_ylim(-40, max(rcs_theta) + 3) # Set the tick label size self.axes1.tick_params(labelsize=12) # Set the legend self.axes1.legend(loc='best', prop={'size': 10}) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Update the canvas self.my_canvas.draw()
def _update_canvas(self): """ Update the figure when the user changes an input value :return: """ # Get the parameters from the form frequency = float(self.frequency.text()) width = float(self.width.text()) height = float(self.height.text()) # Get the selected antenna from the form antenna_type = self.antenna_type.currentIndex() # Set the range and angular span r = 1.0e9 # Set up the theta and phi arrays n = 200 m = int(n / 4) theta, phi = meshgrid(linspace(finfo(float).eps, 0.5 * pi, n), linspace(finfo(float).eps, 2.0 * pi, n)) # Get the antenna parameters and antenna pattern for the selected antenna if antenna_type == 0: half_power_eplane, half_power_hplane, first_null_eplane, first_null_hplane = \ rectangular_uniform_ground_plane.beamwidth(width, height, frequency) directivity = rectangular_uniform_ground_plane.directivity( width, height, frequency) sidelobe_level_eplane = rectangular_uniform_ground_plane.side_lobe_level( ) sidelobe_level_hplane = sidelobe_level_eplane _, et, ep, _, _, _ = rectangular_uniform_ground_plane.far_fields( width, height, frequency, r, theta, phi) elif antenna_type == 1: half_power_eplane, half_power_hplane, first_null_eplane, first_null_hplane = \ rectangular_uniform_free_space.beamwidth(width, height, frequency) directivity = rectangular_uniform_free_space.directivity( width, height, frequency) sidelobe_level_eplane = rectangular_uniform_free_space.side_lobe_level( ) sidelobe_level_hplane = sidelobe_level_eplane _, et, ep, _, _, _ = rectangular_uniform_free_space.far_fields( width, height, frequency, r, theta, phi) else: half_power_eplane, half_power_hplane, first_null_eplane, first_null_hplane = \ rectangular_te10_ground_plane.beamwidth(width, height, frequency) directivity = rectangular_te10_ground_plane.directivity( width, height, frequency) sidelobe_level_eplane, sidelobe_level_hplane = rectangular_te10_ground_plane.side_lobe_level( ) _, et, ep, _, _, _ = rectangular_te10_ground_plane.far_fields( width, height, frequency, r, theta, phi) # The the text boxes on the form to the correct values self.sll_eplane.setText('{:.2f}'.format(sidelobe_level_eplane)) self.sll_hplane.setText('{:.2f}'.format(sidelobe_level_hplane)) self.directivity.setText('{:.2f}'.format(directivity)) # Remove the color bar try: self.cbar.remove() except: # Initial plot pass # Clear the axes for the updated plot self.axes1.clear() # U-V coordinates for plotting the antenna pattern uu = sin(theta) * cos(phi) vv = sin(theta) * sin(phi) # Normalized electric field magnitude for plotting e_mag = sqrt(abs(et * et + ep * ep)) e_mag /= amax(e_mag) if self.plot_type.currentIndex() == 0: # Create the color plot im = self.axes1.pcolor(uu, vv, e_mag, cmap="jet") self.cbar = self.fig.colorbar(im, ax=self.axes1, orientation='vertical') self.cbar.set_label("Normalized Electric Field(V/m)") # Set the x- and y-axis labels self.axes1.set_xlabel("U (sines)", size=12) self.axes1.set_ylabel("V (sines)", size=12) elif self.plot_type.currentIndex() == 1: # Create the contour plot self.axes1.contour(uu, vv, e_mag, 20, cmap="jet", vmin=-0.2, vmax=1.0) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Set the x- and y-axis labels self.axes1.set_xlabel("U (sines)", size=12) self.axes1.set_ylabel("V (sines)", size=12) else: # Create the line plot self.axes1.plot(degrees(theta[0]), 20.0 * log10(e_mag[m]), '', label='E Plane') self.axes1.plot(degrees(theta[0]), 20.0 * log10(e_mag[0]), '--', label='H Plane') # Set the y axis limit self.axes1.set_ylim(-60, 5) # Set the x and y axis labels self.axes1.set_xlabel("Theta (degrees)", size=12) self.axes1.set_ylabel("Normalized |E| (dB)", size=12) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Place the legend self.axes1.legend(loc='upper right', prop={'size': 10}) # Set the plot title and labels self.axes1.set_title('Rectangular Aperture Antenna Pattern', size=14) # Set the tick label size self.axes1.tick_params(labelsize=12) # Update the canvas self.my_canvas.draw()
def nichols_grid(cl_mags=None, cl_phases=None): """Nichols chart grid Plots a Nichols chart grid on the current axis, or creates a new chart if no plot already exists. Parameters ---------- cl_mags : array-like (dB), optional Array of closed-loop magnitudes defining the iso-gain lines on a custom Nichols chart. cl_phases : array-like (degrees), optional Array of closed-loop phases defining the iso-phase lines on a custom Nichols chart. Must be in the range -360 < cl_phases < 0 Returns ------- None """ # Default chart size ol_phase_min = -359.99 ol_phase_max = 0.0 ol_mag_min = -40.0 ol_mag_max = default_ol_mag_max = 50.0 # Find bounds of the current dataset, if there is one. if plt.gcf().gca().has_data(): ol_phase_min, ol_phase_max, ol_mag_min, ol_mag_max = plt.axis() # M-circle magnitudes. if cl_mags is None: # Default chart magnitudes # The key set of magnitudes are always generated, since this # guarantees a recognizable Nichols chart grid. key_cl_mags = np.array([ -40.0, -20.0, -12.0, -6.0, -3.0, -1.0, -0.5, 0.0, 0.25, 0.5, 1.0, 3.0, 6.0, 12.0 ]) # Extend the range of magnitudes if necessary. The extended arange # will end up empty if no extension is required. Assumes that closed-loop # magnitudes are approximately aligned with open-loop magnitudes beyond # the value of np.min(key_cl_mags) cl_mag_step = -20.0 # dB extended_cl_mags = np.arange(np.min(key_cl_mags), ol_mag_min + cl_mag_step, cl_mag_step) cl_mags = np.concatenate((extended_cl_mags, key_cl_mags)) # N-circle phases (should be in the range -360 to 0) if cl_phases is None: # Choose a reasonable set of default phases (denser if the open-loop # data is restricted to a relatively small range of phases). key_cl_phases = np.array( [-0.25, -45.0, -90.0, -180.0, -270.0, -325.0, -359.75]) if np.abs(ol_phase_max - ol_phase_min) < 90.0: other_cl_phases = np.arange(-10.0, -360.0, -10.0) else: other_cl_phases = np.arange(-10.0, -360.0, -20.0) cl_phases = np.concatenate((key_cl_phases, other_cl_phases)) else: assert ((-360.0 < np.min(cl_phases)) and (np.max(cl_phases) < 0.0)) # Find the M-contours m = m_circles(cl_mags, phase_min=np.min(cl_phases), phase_max=np.max(cl_phases)) m_mag = 20 * sp.log10(np.abs(m)) m_phase = sp.mod(sp.degrees(sp.angle(m)), -360.0) # Unwrap # Find the N-contours n = n_circles(cl_phases, mag_min=np.min(cl_mags), mag_max=np.max(cl_mags)) n_mag = 20 * sp.log10(np.abs(n)) n_phase = sp.mod(sp.degrees(sp.angle(n)), -360.0) # Unwrap # Plot the contours behind other plot elements. # The "phase offset" is used to produce copies of the chart that cover # the entire range of the plotted data, starting from a base chart computed # over the range -360 < phase < 0. Given the range # the base chart is computed over, the phase offset should be 0 # for -360 < ol_phase_min < 0. phase_offset_min = 360.0 * np.ceil(ol_phase_min / 360.0) phase_offset_max = 360.0 * np.ceil(ol_phase_max / 360.0) + 360.0 phase_offsets = np.arange(phase_offset_min, phase_offset_max, 360.0) for phase_offset in phase_offsets: # Draw M and N contours plt.plot(m_phase + phase_offset, m_mag, color='gray', linestyle='dotted', zorder=0) plt.plot(n_phase + phase_offset, n_mag, color='gray', linestyle='dotted', zorder=0) # Add magnitude labels for x, y, m in zip(m_phase[:][-1] + phase_offset, m_mag[:][-1], cl_mags): align = 'right' if m < 0.0 else 'left' plt.text(x, y, str(m) + ' dB', size='small', ha=align, color='gray') # Fit axes to generated chart plt.axis([ phase_offset_min - 360.0, phase_offset_max - 360.0, np.min(cl_mags), np.max([ol_mag_max, default_ol_mag_max]) ])
def nichols_plot(sys_list, omega=None, grid=True, figure=None, ax=None, delay=False): """Nichols plot for a system Plots a Nichols plot for the system over a (optional) frequency range. Parameters ---------- sys_list : list of LTI, or LTI List of linear input/output systems (single system is OK) omega : array_like Range of frequencies (list or bounds) in rad/sec grid : boolean, optional True if the plot should include a Nichols-chart grid. Default is True. Returns ------- None """ # If argument was a singleton, turn it into a list if not getattr(sys_list, '__iter__', False): sys_list = (sys_list, ) if omega is None: omega = default_frequency_range(sys_list) for sys in sys_list: omega = np.asarray(omega) if sys.isdtime(strict=True): nyquistfrq = 2. * np.pi * 1. / sys.dt / 2. omega = omega[omega < nyquistfrq] # Get the magnitude and phase of the system mag_tmp, phase_tmp, omega = sys.freqresp(omega) mag = np.squeeze(mag_tmp) phase = np.atleast_1d(np.squeeze(phase_tmp)) phase = unwrap(phase) if np.any((phase * 180.0 / np.pi) >= 180): phase = phase - 2 * np.pi # Convert to Nichols-plot format (phase in degrees, # and magnitude in dB) x = unwrap(sp.degrees(phase), 360) y = 20 * sp.log10(mag) # Generate the plot ax.plot(x, y) ax.xaxis.set_major_formatter(mticker.FormatStrFormatter("%.1f °")) ax.yaxis.set_major_formatter(mticker.FormatStrFormatter("%.1f dB")) ax.set_xlabel('Fase (deg)') ax.set_ylabel('Magnitud (dB)') ax.set_title('Nichols Plot') # Mark the -180 point ax.plot([-180], [0], 'r+') # Add grid if grid: nichols_grid(figure=figure, ax=ax, delay=delay) return x, y, omega
def _update_canvas(self): """ Update the figure when the user changes an input value. :return: """ frequency = float(self.frequency.text()) radius = self.radius.text().split(',') mu_r = self.mu_r.text().split(',') eps_r = self.eps_r.text().split(',') number_of_modes = int(self.number_of_modes.text()) # To put the parameters in order nr = len(radius) mu = ones(nr + 1) eps = ones(nr + 1) ra = ones(nr) # Set up the parameters in the correct order i = 0 for r in radius: ra[nr - 1 - i] = float(r) i += 1 i = 0 for m, e in zip(mu_r, eps_r): mu[nr - i] = float(m) eps[nr - i] = float(e) i += 1 # Flag for PEC core pec = self.pec.currentText() pec_b = False if pec == 'True': pec_b = True # Set the observation angles observation_angle = linspace(0, pi, 721) An, Bn = coefficients(frequency, eps, mu, ra, number_of_modes, pec_b) et = array([radar_cross_section(frequency, oa, 0, An, Bn) for oa in observation_angle]) ep = array([radar_cross_section(frequency, oa, 90, An, Bn) for oa in observation_angle]) # Clear the axes for the updated plot self.axes1.clear() # Display the results self.axes1.plot(degrees(observation_angle), 20.0 * log10(abs(ep[:, 1])), '', label='TE') self.axes1.plot(degrees(observation_angle), 20.0 * log10(abs(et[:, 0])), '--', label='TM') # Set the plot title and labels self.axes1.set_title('RCS vs Bistatic Angle', size=14) self.axes1.set_ylabel('RCS (dBsm)', size=12) self.axes1.set_xlabel('Observation Angle (deg)', size=12) self.axes1.set_ylim(min(20.0 * log10(abs(et[:,0]))) - 3, max(20.0 * log10(abs(et[:,0]))) + 3) # Set the tick label size self.axes1.tick_params(labelsize=12) # Set the legend self.axes1.legend(loc='upper left', prop={'size': 10}) # Turn on the grid self.axes1.grid(linestyle=':', linewidth=0.5) # Update the canvas self.my_canvas.draw()
def __get_theta_deg(self): return scipy.degrees(self.theta)