Skip to content

Commit

Permalink
Merge pull request #276 from CeuAzul/add_new_components_and_extras
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaellehmkuhl authored Sep 15, 2020
2 parents 7350187 + ce23234 commit 789e1a3
Show file tree
Hide file tree
Showing 21 changed files with 360 additions and 0 deletions.
72 changes: 72 additions & 0 deletions adr/Components/Aerodynamic/AerodynamicSurface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import attr
import math
from vec import Vector2

from adr.Components import AttachedComponent
from adr.Methods.Aerodynamic.aerodynamic_fundamental_equations import get_lift, get_drag, get_moment
from adr.World.Aerodynamic.coefficients_data import get_CL, get_CD, get_CM, get_CL_inv, get_CD_inv, get_CM_inv


@attr.s(auto_attribs=True)
class AerodynamicSurface(AttachedComponent):
type: str = 'aerodynamic_surface'
inverted: bool = False
span: float = None
chord: float = None

def __attrs_post_init__(self):
self.add_external_force_function('lift', self.get_lift)
self.add_external_force_function('drag', self.get_drag)
self.add_external_moment_function('moment', self.get_moment)

@property
def area(self):
return -1

@property
def mean_aerodynamic_chord(self):
return -1

@property
def aerodynamic_center(self):
return -1

def get_lift(self):
if self.inverted:
CL = get_CL_inv(self.angle_of_attack)
else:
CL = get_CL(self.angle_of_attack)
lift_mag = get_lift(
self.ambient.air_density,
self.velocity.r,
self.area,
CL)
lift_angle = math.radians(90) - self.angle_of_attack
lift = Vector2(r=lift_mag, theta=lift_angle)
return lift, self.aerodynamic_center

def get_drag(self):
if self.inverted:
CD = get_CD_inv(self.angle_of_attack)
else:
CD = get_CD(self.angle_of_attack)
drag_mag = get_drag(
self.ambient.air_density,
self.velocity.r,
self.area,
CD)
drag_angle = math.radians(180) - self.angle_of_attack
drag = Vector2(r=drag_mag, theta=drag_angle)
return drag, self.aerodynamic_center

def get_moment(self):
if self.inverted:
CM = get_CM_inv(self.angle_of_attack)
else:
CM = get_CM(self.angle_of_attack)
moment_mag = get_moment(self.ambient.air_density,
self.velocity.r,
self.area,
CM,
self.mean_aerodynamic_chord)
return moment_mag
10 changes: 10 additions & 0 deletions adr/Components/Aerodynamic/Flap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import attr

from adr.Components import AttachedComponent


@attr.s(auto_attribs=True)
class Flap(AttachedComponent):
type: str = 'flap'
width: float = None
height: float = None
23 changes: 23 additions & 0 deletions adr/Components/Aerodynamic/RectangularAerodynamicSurface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import attr
from vec import Vector2

from adr.Components.Aerodynamic import AerodynamicSurface


@attr.s(auto_attribs=True)
class RectangularAerodynamicSurface(AerodynamicSurface):
type: str = 'rectangular_aerodynamic_surface'
span: float = None
chord: float = None

@property
def area(self):
return self.span*self.chord

@property
def mean_aerodynamic_chord(self):
return self.chord

@property
def aerodynamic_center(self):
return Vector2(-0.25 * self.mean_aerodynamic_chord, 0)
11 changes: 11 additions & 0 deletions adr/Components/Aerodynamic/RectangularHorizontalStabilizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import attr
import math
from vec import Vector2

from adr.Components.Aerodynamic import RectangularAerodynamicSurface


@attr.s(auto_attribs=True)
class RectangularHorizontalStabilizer(RectangularAerodynamicSurface):
type: str = 'horizontal_stabilizer'
inverted: bool = True
10 changes: 10 additions & 0 deletions adr/Components/Aerodynamic/RectangularWing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import attr
import math
from vec import Vector2

from adr.Components.Aerodynamic import RectangularAerodynamicSurface


@attr.s(auto_attribs=True)
class RectangularWing(RectangularAerodynamicSurface):
type: str = 'wing'
5 changes: 5 additions & 0 deletions adr/Components/Aerodynamic/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .AerodynamicSurface import AerodynamicSurface
from .RectangularAerodynamicSurface import RectangularAerodynamicSurface
from .RectangularHorizontalStabilizer import RectangularHorizontalStabilizer
from .RectangularWing import RectangularWing
from .Flap import Flap
53 changes: 53 additions & 0 deletions adr/Components/Auxiliary/LandingGear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import attr
import math
from vec import Vector2

from adr.World.constants import gravitational_acceleration
from adr.Components import AttachedComponent
from adr.Methods.Powertrain.thrust_equations import get_axial_thrust_from_linear_model


@attr.s(auto_attribs=True)
class LandingGear(AttachedComponent):
type: str = 'landing_gear'
height: float = None
spring_coeff: float = None
dump_coeff: float = None
friction_coeff: float = None

def __attrs_post_init__(self):
self.add_external_force_function(
'gear_reaction', self.gear_reaction)
self.add_external_force_function(
'gear_friction', self.gear_friction)

@property
def floor_contact_point(self):
return Vector2(0, -self.height)

@property
def gui_repr_vector(self) -> Vector2:
return Vector2(r=self.length, theta=math.radians(-90))

def gear_reaction(self):
displacement = self.height-self.position.y
axial_velocity = self.velocity.y
if displacement > 0:
reaction_mag = self.spring_coeff*displacement - self.dump_coeff*axial_velocity
else:
reaction_mag = 0
reaction = Vector2(0, reaction_mag)
return reaction, self.floor_contact_point

def gear_friction(self):
normal_force, contact_point = self.gear_reaction()

if self.velocity.x > 0:
velocity_direction = 1
else:
velocity_direction = -1

friction_mag = self.friction_coeff * normal_force.r * velocity_direction

friction = Vector2(-friction_mag, 0)
return friction, self.floor_contact_point
8 changes: 8 additions & 0 deletions adr/Components/Auxiliary/Payload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import attr

from adr.Components import AttachedComponent


@attr.s(auto_attribs=True)
class Payload(AttachedComponent):
type: str = 'payload'
2 changes: 2 additions & 0 deletions adr/Components/Auxiliary/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .LandingGear import LandingGear
from .Payload import Payload
22 changes: 22 additions & 0 deletions adr/Components/Powertrain/Motor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import attr
import math
from vec import Vector2

from adr.Components import AttachedComponent
from adr.Methods.Powertrain.thrust_equations import get_axial_thrust_from_linear_model


@attr.s(auto_attribs=True)
class Motor(AttachedComponent):
type: str = 'motor'

def __attrs_post_init__(self):
self.add_external_force_function('thrust', self.get_thrust)

@property
def thrust_center(self):
return Vector2(0, 0)

def get_thrust(self):
thrust = Vector2(0, 0)
return thrust, self.thrust_center
30 changes: 30 additions & 0 deletions adr/Components/Powertrain/SimpleMotor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import attr
from vec import Vector2

from adr.Components.Powertrain import Motor
from adr.Methods.Powertrain.thrust_equations import get_axial_thrust_from_linear_model


@attr.s(auto_attribs=True)
class SimpleMotor(Motor):
static_thrust: float = None
linear_coefficient: float = None
distance_origin_to_propeller: float = None

@property
def thrust_center(self):
return Vector2(self.distance_origin_to_propeller, 0)

def get_thrust(self):
angle_of_attack = self.angle_of_attack
axial_velocity = self.velocity.rotated(angle_of_attack).x

thrust_mag = get_axial_thrust_from_linear_model(
self.ambient.air_density,
axial_velocity,
self.static_thrust,
self.linear_coefficient
)

thrust = Vector2(thrust_mag, 0)
return thrust, self.thrust_center
2 changes: 2 additions & 0 deletions adr/Components/Powertrain/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .Motor import Motor
from .SimpleMotor import SimpleMotor
3 changes: 3 additions & 0 deletions adr/Components/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from .BaseComponent import BaseComponent
from .FreeBody import FreeBody
from .AttachedComponent import AttachedComponent
from .Auxiliary import LandingGear, Payload
from .Powertrain import Motor, SimpleMotor
from .Aerodynamic import AerodynamicSurface, RectangularAerodynamicSurface, RectangularHorizontalStabilizer, RectangularWing, Flap
1 change: 1 addition & 0 deletions adr/Methods/Aerodynamic/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .aerodynamic_fundamental_equations import get_lift, get_drag, get_moment
42 changes: 42 additions & 0 deletions adr/Methods/Aerodynamic/aerodynamic_fundamental_equations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
def get_lift(air_density, velocity, area, lift_coefficient):
cond1 = air_density > 0
cond2 = area > 0
cond3 = velocity >= 0

if cond1 and cond2 and cond3:
return 0.5 * air_density * velocity ** 2 * area * lift_coefficient
else:
raise ValueError(
f'Air density and area must be positive. \
Velocity must be equal or greater than zero. \
Found density={air_density}, area={area} and velocity = {velocity}.')


def get_drag(air_density, velocity, area, drag_coefficient):
cond1 = air_density > 0
cond2 = area > 0
cond3 = velocity >= 0
cond4 = drag_coefficient >= 0

if cond1 and cond2 and cond3 and cond4:
return 0.5 * air_density * velocity ** 2 * area * drag_coefficient
else:
raise ValueError(
f'Air density and area must be positive. \
Velocity and drag coefficient must be equal or greater than zero. \
Found density={air_density}, area={area}, velocity = {velocity} and CD = {drag_coefficient}.')


def get_moment(air_density, velocity, area, moment_coefficient, chord):
cond1 = air_density > 0
cond2 = area > 0
cond3 = velocity >= 0
cond4 = chord > 0

if cond1 and cond2 and cond3 and cond4:
return 0.5 * air_density * velocity ** 2 * area * moment_coefficient * chord
else:
raise ValueError(
f'Air density, area and chord must be positive. \
Velocity must be equal or greater than zero. \
Found density={air_density}, area={area}, velocity = {velocity} and chord = {chord}.')
1 change: 1 addition & 0 deletions adr/Methods/Powertrain/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .thrust_equations import get_axial_thrust_from_linear_model
12 changes: 12 additions & 0 deletions adr/Methods/Powertrain/thrust_equations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
def get_axial_thrust_from_linear_model(air_density, velocity, static_thrust, linear_coefficient):
cond1 = air_density > 0
cond2 = velocity >= 0

if cond1 and cond2:
air_density_factor = air_density/1.225
return (static_thrust + linear_coefficient * velocity) * air_density_factor
else:
raise ValueError(
f'Air density must be positive. \
Velocity must be equal or greater than zero. \
Found density={air_density} and velocity = {velocity}.')
2 changes: 2 additions & 0 deletions adr/Methods/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .Aerodynamic import aerodynamic_fundamental_equations
from .Powertrain import thrust_equations
1 change: 1 addition & 0 deletions adr/World/Aerodynamic/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .coefficients_data import get_CL, get_CD, get_CM, get_CL_inv, get_CD_inv, get_CM_inv
49 changes: 49 additions & 0 deletions adr/World/Aerodynamic/coefficients_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
def get_CL(angle_of_attack):
if angle_of_attack > 15 or angle_of_attack < -5:
return 0
else:
return 0.6 + 0.1 * angle_of_attack


def get_CD(angle_of_attack):
if angle_of_attack > 15 or angle_of_attack < -5:
return 10 * (0.06 + 0.01 * 15)
else:
return 0.06 + 0.01 * angle_of_attack


def get_CM(angle_of_attack):
a = 0.0012365
b = -0.016365
c = -0.2327
if angle_of_attack > 15 or angle_of_attack < -5:
return 0
else:
return a * angle_of_attack**2 + b * angle_of_attack + c


def get_CL_inv(angle_of_attack):
angle_of_attack = -angle_of_attack
if angle_of_attack > 15 or angle_of_attack < -5:
return 0
else:
return -1 * (0.6 + 0.1 * angle_of_attack)


def get_CD_inv(angle_of_attack):
angle_of_attack = -angle_of_attack
if angle_of_attack > 15 or angle_of_attack < -5:
return 10 * (0.06 + 0.01 * 15)
else:
return 0.06 + 0.01 * angle_of_attack


def get_CM_inv(angle_of_attack):
angle_of_attack = -angle_of_attack
a = 0.0012365
b = -0.016365
c = -0.2327
if angle_of_attack > 15 or angle_of_attack < -5:
return 0
else:
return -1 * (a * angle_of_attack**2 + b * angle_of_attack + c)
1 change: 1 addition & 0 deletions adr/World/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .constants import gravitational_acceleration, air_gas_constant
from .Ambient import Ambient
from .Aerodynamic import coefficients_data

0 comments on commit 789e1a3

Please sign in to comment.