Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Individual Fin #686

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
311 changes: 197 additions & 114 deletions docs/notebooks/coeff_testing.ipynb

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions rocketpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,19 @@
AeroSurface,
AirBrakes,
Components,
EllipticalFin,
EllipticalFins,
Fin,
Fins,
GenericSurface,
LinearGenericSurface,
NoseCone,
Parachute,
RailButtons,
Rocket,
Tail,
TrapezoidalFin,
TrapezoidalFins,
GenericSurface,
LinearGenericSurface,
)
from .simulation import Flight, MonteCarlo
from .stochastic import (
Expand Down
253 changes: 253 additions & 0 deletions rocketpy/plots/aero_surface_plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,67 @@ def all(self):
self.lift()


class _FinPlots(_AeroSurfacePlots):
"""Abstract class that contains all fin plots. This class inherits from the
_AeroSurfacePlots class."""

@abstractmethod
def draw(self):
pass

def airfoil(self):
"""Plots the airfoil information when the fin has an airfoil shape. If
the fin does not have an airfoil shape, this method does nothing.

Returns
-------
None
"""

if self.aero_surface.airfoil:
print("Airfoil lift curve:")
self.aero_surface.airfoil_cl.plot_1d(force_data=True)

def roll(self):
"""Plots the roll parameters of the fin set.

Returns
-------
None
"""
print("Roll parameters:")
# TODO: lacks a title in the plots
self.aero_surface.roll_parameters[0]()
self.aero_surface.roll_parameters[1]()

def lift(self):
"""Plots the lift coefficient of the aero surface as a function of Mach
and the angle of attack. A 3D plot is expected. See the rocketpy.Function
class for more information on how this plot is made. Also, this method
plots the lift coefficient considering a single fin and the lift
coefficient considering all fins.

Returns
-------
None
"""
print("Lift coefficient:")
self.aero_surface.cl()
self.aero_surface.clalpha_single_fin()

def all(self):
"""Plots all available fin plots.

Returns
-------
None
"""
self.draw()
self.airfoil()
self.roll()
self.lift()


class _TrapezoidalFinsPlots(_FinsPlots):
"""Class that contains all trapezoidal fin plots."""

Expand Down Expand Up @@ -309,6 +370,127 @@ def draw(self):
plt.show()


class _TrapezoidalFinPlots(_FinPlots):
"""Class that contains all trapezoidal fin plots."""

# pylint: disable=too-many-statements
def draw(self):
"""Draw the fin shape along with some important information, including
the center line, the quarter line and the center of pressure position.

Returns
-------
None
"""
# Color cycle [#348ABD, #A60628, #7A68A6, #467821, #D55E00, #CC79A7,
# #56B4E9, #009E73, #F0E442, #0072B2]
# Fin
leading_edge = plt.Line2D(
(0, self.aero_surface.sweep_length),
(0, self.aero_surface.span),
color="#A60628",
)
tip = plt.Line2D(
(
self.aero_surface.sweep_length,
self.aero_surface.sweep_length + self.aero_surface.tip_chord,
),
(self.aero_surface.span, self.aero_surface.span),
color="#A60628",
)
back_edge = plt.Line2D(
(
self.aero_surface.sweep_length + self.aero_surface.tip_chord,
self.aero_surface.root_chord,
),
(self.aero_surface.span, 0),
color="#A60628",
)
root = plt.Line2D((self.aero_surface.root_chord, 0), (0, 0), color="#A60628")

# Center and Quarter line
center_line = plt.Line2D(
(
self.aero_surface.root_chord / 2,
self.aero_surface.sweep_length + self.aero_surface.tip_chord / 2,
),
(0, self.aero_surface.span),
color="#7A68A6",
alpha=0.35,
linestyle="--",
label="Center Line",
)
quarter_line = plt.Line2D(
(
self.aero_surface.root_chord / 4,
self.aero_surface.sweep_length + self.aero_surface.tip_chord / 4,
),
(0, self.aero_surface.span),
color="#7A68A6",
alpha=1,
linestyle="--",
label="Quarter Line",
)

# Center of pressure
cp_point = [self.aero_surface.cpz, self.aero_surface.Yma]

# Mean Aerodynamic Chord
yma_start = (
self.aero_surface.sweep_length
* (self.aero_surface.root_chord + 2 * self.aero_surface.tip_chord)
/ (3 * (self.aero_surface.root_chord + self.aero_surface.tip_chord))
)
yma_end = (
2 * self.aero_surface.root_chord**2
+ self.aero_surface.root_chord * self.aero_surface.sweep_length
+ 2 * self.aero_surface.root_chord * self.aero_surface.tip_chord
+ 2 * self.aero_surface.sweep_length * self.aero_surface.tip_chord
+ 2 * self.aero_surface.tip_chord**2
) / (3 * (self.aero_surface.root_chord + self.aero_surface.tip_chord))
yma_line = plt.Line2D(
(yma_start, yma_end),
(self.aero_surface.Yma, self.aero_surface.Yma),
color="#467821",
linestyle="--",
label="Mean Aerodynamic Chord",
)

# Plotting
fig = plt.figure(figsize=(7, 4))
with plt.style.context("bmh"):
ax = fig.add_subplot(111)

# Fin
ax.add_line(leading_edge)
ax.add_line(tip)
ax.add_line(back_edge)
ax.add_line(root)

ax.add_line(center_line)
ax.add_line(quarter_line)
ax.add_line(yma_line)
ax.scatter(*cp_point, label="Center of Pressure", color="red", s=100, zorder=10)
ax.scatter(*cp_point, facecolors="none", edgecolors="red", s=500, zorder=10)

# Plot settings
xlim = (
self.aero_surface.root_chord
if self.aero_surface.sweep_length + self.aero_surface.tip_chord
< self.aero_surface.root_chord
else self.aero_surface.sweep_length + self.aero_surface.tip_chord
)
ax.set_xlim(0, xlim * 1.1)
ax.set_ylim(0, self.aero_surface.span * 1.1)
ax.set_xlabel("Root chord (m)")
ax.set_ylabel("Span (m)")
ax.set_title("Trapezoidal Fin Cross Section")
ax.legend(bbox_to_anchor=(1.05, 1.0), loc="upper left")

plt.tight_layout()
plt.show()


class _EllipticalFinsPlots(_FinsPlots):
"""Class that contains all elliptical fin plots."""

Expand Down Expand Up @@ -380,6 +562,77 @@ def draw(self):
plt.show()


class _EllipticalFinPlots(_FinPlots):
"""Class that contains all elliptical fin plots."""

# pylint: disable=too-many-statements
def draw(self):
"""Draw the fin shape along with some important information.
These being: the center line and the center of pressure position.

Returns
-------
None
"""
# Ellipse
ellipse = Ellipse(
(self.aero_surface.root_chord / 2, 0),
self.aero_surface.root_chord,
self.aero_surface.span * 2,
fill=False,
edgecolor="#A60628",
linewidth=2,
)

# Mean Aerodynamic Chord # From Barrowman's theory
yma_length = 8 * self.aero_surface.root_chord / (3 * np.pi)
yma_start = (self.aero_surface.root_chord - yma_length) / 2
yma_end = (
self.aero_surface.root_chord
- (self.aero_surface.root_chord - yma_length) / 2
)
yma_line = plt.Line2D(
(yma_start, yma_end),
(self.aero_surface.Yma, self.aero_surface.Yma),
label="Mean Aerodynamic Chord",
color="#467821",
)

# Center Line
center_line = plt.Line2D(
(self.aero_surface.root_chord / 2, self.aero_surface.root_chord / 2),
(0, self.aero_surface.span),
color="#7A68A6",
alpha=0.35,
linestyle="--",
label="Center Line",
)

# Center of pressure
cp_point = [self.aero_surface.cpz, self.aero_surface.Yma]

# Plotting
fig = plt.figure(figsize=(7, 4))
with plt.style.context("bmh"):
ax = fig.add_subplot(111)
ax.add_patch(ellipse)
ax.add_line(yma_line)
ax.add_line(center_line)
ax.scatter(*cp_point, label="Center of Pressure", color="red", s=100, zorder=10)
ax.scatter(*cp_point, facecolors="none", edgecolors="red", s=500, zorder=10)

# Plot settings
ax.set_xlim(0, self.aero_surface.root_chord)
ax.set_ylim(0, self.aero_surface.span * 1.1)
ax.set_xlabel("Root chord (m)")
ax.set_ylabel("Span (m)")
ax.set_title("Elliptical Fin Cross Section")
ax.legend(bbox_to_anchor=(1.05, 1.0), loc="upper left")

plt.tight_layout()
plt.show()


class _TailPlots(_AeroSurfacePlots):
"""Class that contains all tail plots."""

Expand Down
33 changes: 32 additions & 1 deletion rocketpy/plots/rocket_plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import numpy as np

from rocketpy.motors import EmptyMotor, HybridMotor, LiquidMotor, SolidMotor
from rocketpy.rocket.aero_surface import Fins, NoseCone, Tail
from rocketpy.rocket.aero_surface import Fin, Fins, NoseCone, Tail


class _RocketPlots:
Expand Down Expand Up @@ -242,6 +242,8 @@ def _draw_aerodynamic_surfaces(self, ax, vis_args):
self._draw_tail(ax, surface, position.z, drawn_surfaces, vis_args)
elif isinstance(surface, Fins):
self._draw_fins(ax, surface, position.z, drawn_surfaces, vis_args)
elif isinstance(surface, Fin):
self._draw_fin(ax, surface, position.z, drawn_surfaces, vis_args)
return drawn_surfaces

def _draw_nose_cone(self, ax, surface, position, drawn_surfaces, vis_args):
Expand Down Expand Up @@ -334,6 +336,35 @@ def _draw_fins(self, ax, surface, position, drawn_surfaces, vis_args):

drawn_surfaces.append((surface, position, surface.rocket_radius, x_rotated[-1]))

def _draw_fin(self, ax, surface, position, drawn_surfaces, vis_args):
"""Draws the fins and saves the position of the points of interest
for the tubes."""

x_fin = -self.rocket._csys * surface.shape_vec[0] + position
y_fin = surface.shape_vec[1] + surface.rocket_radius
angle = surface.angular_position

# Create a rotation matrix for the angle around the x-axis
rotation_matrix = np.array([[1, 0], [0, np.cos(angle)]])

# Apply the rotation to the original fin points
rotated_points_2d = np.dot(rotation_matrix, np.vstack((x_fin, y_fin)))

# Extract x and y coordinates of the rotated points
x_rotated, y_rotated = rotated_points_2d

# Project points above the XY plane back into the XY plane (set z-coordinate to 0)
x_rotated = np.where(rotated_points_2d[1] > 0, rotated_points_2d[0], x_rotated)
y_rotated = np.where(rotated_points_2d[1] > 0, rotated_points_2d[1], y_rotated)
ax.plot(
x_rotated,
y_rotated,
color=vis_args["fins"],
linewidth=vis_args["line_width"],
)

drawn_surfaces.append((surface, position, surface.rocket_radius, x_rotated[-1]))

def _draw_tubes(self, ax, drawn_surfaces, vis_args):
"""Draws the tubes between the aerodynamic surfaces."""
for i, d_surface in enumerate(drawn_surfaces):
Expand Down
Loading