Source code for rocketpy.rocket.aero_surface.fins.trapezoidal_fins

import numpy as np

from rocketpy.plots.aero_surface_plots import _TrapezoidalFinsPlots
from rocketpy.prints.aero_surface_prints import _TrapezoidalFinsPrints

from .fins import Fins


[docs] class TrapezoidalFins(Fins): """Class that defines and holds information for a trapezoidal fin set. This class inherits from the Fins class. Note ---- Local coordinate system: - Origin located at the top of the root chord. - Z axis along the longitudinal axis of symmetry, positive downwards (top -> bottom). - Y axis perpendicular to the Z axis, in the span direction, positive upwards. - X axis completes the right-handed coordinate system. See Also -------- Fins Attributes ---------- TrapezoidalFins.n : int Number of fins in fin set. TrapezoidalFins.rocket_radius : float The reference rocket radius used for lift coefficient normalization, in meters. TrapezoidalFins.airfoil : tuple Tuple of two items. First is the airfoil lift curve. Second is the unit of the curve (radians or degrees). TrapezoidalFins.cant_angle : float Fins cant angle with respect to the rocket centerline, in degrees. TrapezoidalFins.changing_attribute_dict : dict Dictionary that stores the name and the values of the attributes that may be changed during a simulation. Useful for control systems. TrapezoidalFins.cant_angle_rad : float Fins cant angle with respect to the rocket centerline, in radians. TrapezoidalFins.root_chord : float Fin root chord in meters. TrapezoidalFins.tip_chord : float Fin tip chord in meters. TrapezoidalFins.span : float Fin span in meters. TrapezoidalFins.name : string Name of fin set. TrapezoidalFins.sweep_length : float Fins sweep length in meters. By sweep length, understand the axial distance between the fin root leading edge and the fin tip leading edge measured parallel to the rocket centerline. TrapezoidalFins.sweep_angle : float Fins sweep angle with respect to the rocket centerline. Must be given in degrees. TrapezoidalFins.d : float Reference diameter of the rocket, in meters. TrapezoidalFins.ref_area : float Reference area of the rocket, in m². TrapezoidalFins.Af : float Area of the longitudinal section of each fin in the set. TrapezoidalFins.AR : float Aspect ratio of each fin in the set TrapezoidalFins.gamma_c : float Fin mid-chord sweep angle. TrapezoidalFins.Yma : float Span wise position of the mean aerodynamic chord. TrapezoidalFins.roll_geometrical_constant : float Geometrical constant used in roll calculations. TrapezoidalFins.tau : float Geometrical relation used to simplify lift and roll calculations. TrapezoidalFins.lift_interference_factor : float Factor of Fin-Body interference in the lift coefficient. TrapezoidalFins.cp : tuple Tuple with the x, y and z local coordinates of the fin set center of pressure. Has units of length and is given in meters. TrapezoidalFins.cpx : float Fin set local center of pressure x coordinate. Has units of length and is given in meters. TrapezoidalFins.cpy : float Fin set local center of pressure y coordinate. Has units of length and is given in meters. TrapezoidalFins.cpz : float Fin set local center of pressure z coordinate. Has units of length and is given in meters. TrapezoidalFins.cl : Function Function which defines the lift coefficient as a function of the angle of attack and the Mach number. Takes as input the angle of attack in radians and the Mach number. Returns the lift coefficient. TrapezoidalFins.clalpha : float Lift coefficient slope. Has units of 1/rad. """
[docs] def __init__( self, n, root_chord, tip_chord, span, rocket_radius, cant_angle=0, sweep_length=None, sweep_angle=None, airfoil=None, name="Fins", ): """Initialize TrapezoidalFins class. Parameters ---------- n : int Number of fins, must be larger than 2. root_chord : int, float Fin root chord in meters. tip_chord : int, float Fin tip chord in meters. span : int, float Fin span in meters. rocket_radius : int, float Reference radius to calculate lift coefficient, in meters. cant_angle : int, float, optional Fins cant angle with respect to the rocket centerline. Must be given in degrees. sweep_length : int, float, optional Fins sweep length in meters. By sweep length, understand the axial distance between the fin root leading edge and the fin tip leading edge measured parallel to the rocket centerline. If not given, the sweep length is assumed to be equal the root chord minus the tip chord, in which case the fin is a right trapezoid with its base perpendicular to the rocket's axis. Cannot be used in conjunction with sweep_angle. sweep_angle : int, float, optional Fins sweep angle with respect to the rocket centerline. Must be given in degrees. If not given, the sweep angle is automatically calculated, in which case the fin is assumed to be a right trapezoid with its base perpendicular to the rocket's axis. Cannot be used in conjunction with sweep_length. airfoil : tuple, optional Default is null, in which case fins will be treated as flat plates. Otherwise, if tuple, fins will be considered as airfoils. The tuple's first item specifies the airfoil's lift coefficient by angle of attack and must be either a .csv, .txt, ndarray or callable. The .csv and .txt files can contain a single line header and the first column must specify the angle of attack, while the second column must specify the lift coefficient. The ndarray should be as [(x0, y0), (x1, y1), (x2, y2), ...] where x0 is the angle of attack and y0 is the lift coefficient. If callable, it should take an angle of attack as input and return the lift coefficient at that angle of attack. The tuple's second item is the unit of the angle of attack, accepting either "radians" or "degrees". name : str Name of fin set. Returns ------- None """ super().__init__( n, root_chord, span, rocket_radius, cant_angle, airfoil, name, ) # Check if sweep angle or sweep length is given if sweep_length is not None and sweep_angle is not None: raise ValueError("Cannot use sweep_length and sweep_angle together") elif sweep_angle is not None: sweep_length = np.tan(sweep_angle * np.pi / 180) * span elif sweep_length is None: sweep_length = root_chord - tip_chord else: # Sweep length is given pass self._tip_chord = tip_chord self._sweep_length = sweep_length self._sweep_angle = sweep_angle self.evaluate_geometrical_parameters() self.evaluate_center_of_pressure() self.evaluate_lift_coefficient() self.evaluate_roll_parameters() self.prints = _TrapezoidalFinsPrints(self) self.plots = _TrapezoidalFinsPlots(self)
@property def tip_chord(self): return self._tip_chord @tip_chord.setter def tip_chord(self, value): self._tip_chord = value self.evaluate_geometrical_parameters() self.evaluate_center_of_pressure() self.evaluate_lift_coefficient() self.evaluate_roll_parameters() @property def sweep_angle(self): return self._sweep_angle @sweep_angle.setter def sweep_angle(self, value): self._sweep_angle = value self._sweep_length = np.tan(value * np.pi / 180) * self.span self.evaluate_geometrical_parameters() self.evaluate_center_of_pressure() self.evaluate_lift_coefficient() self.evaluate_roll_parameters() @property def sweep_length(self): return self._sweep_length @sweep_length.setter def sweep_length(self, value): self._sweep_length = value self.evaluate_geometrical_parameters() self.evaluate_center_of_pressure() self.evaluate_lift_coefficient() self.evaluate_roll_parameters()
[docs] def evaluate_center_of_pressure(self): """Calculates and returns the center of pressure of the fin set in local coordinates. The center of pressure position is saved and stored as a tuple. Returns ------- None """ # Center of pressure position in local coordinates cpz = (self.sweep_length / 3) * ( (self.root_chord + 2 * self.tip_chord) / (self.root_chord + self.tip_chord) ) + (1 / 6) * ( self.root_chord + self.tip_chord - self.root_chord * self.tip_chord / (self.root_chord + self.tip_chord) ) self.cpx = 0 self.cpy = 0 self.cpz = cpz self.cp = (self.cpx, self.cpy, self.cpz)
[docs] def evaluate_geometrical_parameters(self): # pylint: disable=too-many-statements """Calculates and saves fin set's geometrical parameters such as the fins' area, aspect ratio and parameters for roll movement. Returns ------- None """ # pylint: disable=invalid-name Yr = self.root_chord + self.tip_chord Af = Yr * self.span / 2 # Fin area AR = 2 * self.span**2 / Af # Fin aspect ratio gamma_c = np.arctan( (self.sweep_length + 0.5 * self.tip_chord - 0.5 * self.root_chord) / (self.span) ) Yma = ( (self.span / 3) * (self.root_chord + 2 * self.tip_chord) / Yr ) # Span wise coord of mean aero chord # Fin–body interference correction parameters tau = (self.span + self.rocket_radius) / self.rocket_radius lift_interference_factor = 1 + 1 / tau lambda_ = self.tip_chord / self.root_chord # Parameters for Roll Moment. # Documented at: https://docs.rocketpy.org/en/latest/technical/ roll_geometrical_constant = ( (self.root_chord + 3 * self.tip_chord) * self.span**3 + 4 * (self.root_chord + 2 * self.tip_chord) * self.rocket_radius * self.span**2 + 6 * (self.root_chord + self.tip_chord) * self.span * self.rocket_radius**2 ) / 12 roll_damping_interference_factor = 1 + ( ((tau - lambda_) / (tau)) - ((1 - lambda_) / (tau - 1)) * np.log(tau) ) / ( ((tau + 1) * (tau - lambda_)) / (2) - ((1 - lambda_) * (tau**3 - 1)) / (3 * (tau - 1)) ) roll_forcing_interference_factor = (1 / np.pi**2) * ( (np.pi**2 / 4) * ((tau + 1) ** 2 / tau**2) + ((np.pi * (tau**2 + 1) ** 2) / (tau**2 * (tau - 1) ** 2)) * np.arcsin((tau**2 - 1) / (tau**2 + 1)) - (2 * np.pi * (tau + 1)) / (tau * (tau - 1)) + ((tau**2 + 1) ** 2) / (tau**2 * (tau - 1) ** 2) * (np.arcsin((tau**2 - 1) / (tau**2 + 1))) ** 2 - (4 * (tau + 1)) / (tau * (tau - 1)) * np.arcsin((tau**2 - 1) / (tau**2 + 1)) + (8 / (tau - 1) ** 2) * np.log((tau**2 + 1) / (2 * tau)) ) # Store values self.Yr = Yr self.Af = Af # Fin area self.AR = AR # Aspect Ratio self.gamma_c = gamma_c # Mid chord angle self.Yma = Yma # Span wise coord of mean aero chord self.roll_geometrical_constant = roll_geometrical_constant self.tau = tau self.lift_interference_factor = lift_interference_factor self.λ = lambda_ # pylint: disable=non-ascii-name self.roll_damping_interference_factor = roll_damping_interference_factor self.roll_forcing_interference_factor = roll_forcing_interference_factor self.evaluate_shape()
def evaluate_shape(self): if self.sweep_length: points = [ (0, 0), (self.sweep_length, self.span), (self.sweep_length + self.tip_chord, self.span), (self.root_chord, 0), ] else: points = [ (0, 0), (self.root_chord - self.tip_chord, self.span), (self.root_chord, self.span), (self.root_chord, 0), ] x_array, y_array = zip(*points) self.shape_vec = [np.array(x_array), np.array(y_array)]
[docs] def info(self): self.prints.geometry() self.prints.lift()
[docs] def all_info(self): self.prints.all() self.plots.all()
def to_dict(self, include_outputs=False): data = super().to_dict(include_outputs) data["tip_chord"] = self.tip_chord if include_outputs: data.update( { "sweep_length": self.sweep_length, "sweep_angle": self.sweep_angle, "shape_vec": self.shape_vec, "Af": self.Af, "AR": self.AR, "gamma_c": self.gamma_c, "Yma": self.Yma, "roll_geometrical_constant": self.roll_geometrical_constant, "tau": self.tau, "lift_interference_factor": self.lift_interference_factor, "roll_damping_interference_factor": self.roll_damping_interference_factor, "roll_forcing_interference_factor": self.roll_forcing_interference_factor, } ) return data @classmethod def from_dict(cls, data): return cls( n=data["n"], root_chord=data["root_chord"], tip_chord=data["tip_chord"], span=data["span"], rocket_radius=data["rocket_radius"], cant_angle=data["cant_angle"], airfoil=data["airfoil"], name=data["name"], )