Skip to content

Commit ee49409

Browse files
Merge pull request #558 from RocketPy-Team/hotfix/issue-557
BUG: Add reference area factor correction to aero surfaces (solves #557)
2 parents 43b486a + 643ea6e commit ee49409

File tree

5 files changed

+122
-13
lines changed

5 files changed

+122
-13
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
3939
### Fixed
4040

4141

42+
## [v1.2.1] - 2024-02-22
43+
44+
You can install this version by running `pip install rocketpy==1.2.1`
45+
46+
### Fixed
47+
48+
- BUG: Add reference area factor correction to aero surfaces (solves #557) [#558](https://github.com/RocketPy-Team/RocketPy/pull/558)
49+
4250
## [v1.2.0] - 2024-02-12
4351

4452
You can install this version by running `pip install rocketpy==1.2.0`

rocketpy/prints/rocket_prints.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,13 @@ def rocket_aerodynamics_quantities(self):
114114
print("\nAerodynamics Lift Coefficient Derivatives\n")
115115
for surface, position in self.rocket.aerodynamic_surfaces:
116116
name = surface.name
117+
# ref_factor corrects lift for different reference areas
118+
ref_factor = (surface.rocket_radius / self.rocket.radius) ** 2
117119
print(
118120
name
119-
+ " Lift Coefficient Derivative: {:.3f}".format(surface.clalpha(0))
121+
+ " Lift Coefficient Derivative: {:.3f}".format(
122+
ref_factor * surface.clalpha(0)
123+
)
120124
+ "/rad"
121125
)
122126

@@ -135,6 +139,9 @@ def rocket_aerodynamics_quantities(self):
135139
print(
136140
f"Center of Mass position (time=0): {self.rocket.center_of_mass(0):.3f} m"
137141
)
142+
print(
143+
f"Center of Pressure position (time=0): {self.rocket.cp_position(0):.3f} m"
144+
)
138145
print(
139146
"Initial Static Margin (mach=0, time=0): "
140147
+ "{:.3f}".format(self.rocket.static_margin(0))

rocketpy/rocket/aero_surface.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,12 +349,20 @@ def evaluate_geometrical_parameters(self):
349349
# If base radius is not given, the ratio between base radius and
350350
# rocket radius is assumed as 1, meaning that the nose cone has the
351351
# same radius as the rocket
352-
if self.base_radius is None or self.rocket_radius is None:
352+
if self.base_radius is None and self.rocket_radius is not None:
353353
self.radius_ratio = 1
354+
self.base_radius = self.rocket_radius
355+
elif self.base_radius is not None and self.rocket_radius is None:
356+
self.radius_ratio = 1
357+
self.rocket_radius = self.base_radius
354358
# If base radius is given, the ratio between base radius and rocket
355359
# radius is calculated
356-
else:
360+
elif self.base_radius is not None and self.rocket_radius is not None:
357361
self.radius_ratio = self.base_radius / self.rocket_radius
362+
else:
363+
raise ValueError(
364+
"Either base radius or rocket radius must be given to calculate the nose cone radius ratio."
365+
)
358366

359367
self.fineness_ratio = self.length / (2 * self.base_radius)
360368
return None

rocketpy/rocket/rocket.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -517,9 +517,13 @@ def evaluate_center_of_pressure(self):
517517
# Calculate total lift coefficient derivative and center of pressure
518518
if len(self.aerodynamic_surfaces) > 0:
519519
for aero_surface, position in self.aerodynamic_surfaces:
520-
self.total_lift_coeff_der += aero_surface.clalpha
521-
self.cp_position += aero_surface.clalpha * (
522-
position - self._csys * aero_surface.cpz
520+
# ref_factor corrects lift for different reference areas
521+
ref_factor = (aero_surface.rocket_radius / self.radius) ** 2
522+
self.total_lift_coeff_der += ref_factor * aero_surface.clalpha
523+
self.cp_position += (
524+
ref_factor
525+
* aero_surface.clalpha
526+
* (position - self._csys * aero_surface.cpz)
523527
)
524528
self.cp_position /= self.total_lift_coeff_der
525529

@@ -871,7 +875,9 @@ def add_tail(
871875
self.add_surfaces(tail, position)
872876
return tail
873877

874-
def add_nose(self, length, kind, position, bluffness=0, name="Nose Cone"):
878+
def add_nose(
879+
self, length, kind, position, bluffness=0, name="Nose Cone", base_radius=None
880+
):
875881
"""Creates a nose cone, storing its parameters as part of the
876882
aerodynamic_surfaces list. Its parameters are the axial position
877883
along the rocket and its derivative of the coefficient of lift
@@ -894,6 +900,9 @@ def add_nose(self, length, kind, position, bluffness=0, name="Nose Cone"):
894900
the radius of the base of the ogive.
895901
name : string
896902
Nose cone name. Default is "Nose Cone".
903+
base_radius : int, float, optional
904+
Nose cone base radius in meters. If not given, the rocket radius
905+
will be used.
897906
898907
See Also
899908
--------
@@ -907,8 +916,8 @@ def add_nose(self, length, kind, position, bluffness=0, name="Nose Cone"):
907916
nose = NoseCone(
908917
length=length,
909918
kind=kind,
910-
base_radius=self.radius,
911-
rocket_radius=self.radius,
919+
base_radius=base_radius or self.radius,
920+
rocket_radius=base_radius or self.radius,
912921
bluffness=bluffness,
913922
name=name,
914923
)
@@ -983,8 +992,9 @@ def add_trapezoidal_fins(
983992
with its base perpendicular to the rocket's axis. Cannot be used in
984993
conjunction with sweep_length.
985994
radius : int, float, optional
986-
Reference radius to calculate lift coefficient. If None, which is
987-
default, use rocket radius.
995+
Reference fuselage radius where the fins are located. This is used
996+
to calculate lift coefficient and to draw the rocket. If None,
997+
which is default, the rocket radius will be used.
988998
airfoil : tuple, optional
989999
Default is null, in which case fins will be treated as flat plates.
9901000
Otherwise, if tuple, fins will be considered as airfoils. The
@@ -1064,8 +1074,9 @@ def add_elliptical_fins(
10641074
Fins cant angle with respect to the rocket centerline. Must be given
10651075
in degrees.
10661076
radius : int, float, optional
1067-
Reference radius to calculate lift coefficient. If None, which
1068-
is default, use rocket radius.
1077+
Reference fuselage radius where the fins are located. This is used
1078+
to calculate lift coefficient and to draw the rocket. If None,
1079+
which is default, the rocket radius will be used.
10691080
airfoil : tuple, optional
10701081
Default is null, in which case fins will be treated as flat plates.
10711082
Otherwise, if tuple, fins will be considered as airfoils. The

tests/test_rocket.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from unittest.mock import patch
22

33
import numpy as np
4+
import pytest
45

56
from rocketpy import Rocket, SolidMotor
7+
from rocketpy.rocket import NoseCone
68

79

810
@patch("matplotlib.pyplot.show")
@@ -205,3 +207,76 @@ def test_air_brakes_clamp_off(mock_show, calisto_air_brakes_clamp_off):
205207
assert air_brakes_clamp_off.deployment_level == 0
206208

207209
assert air_brakes_clamp_off.all_info() == None
210+
211+
212+
def test_add_surfaces_different_noses(calisto):
213+
"""Test the add_surfaces method with different nose cone configurations.
214+
More specifically, this will check the static margin of the rocket with
215+
different nose cone configurations.
216+
217+
Parameters
218+
----------
219+
calisto : Rocket
220+
Pytest fixture for the calisto rocket.
221+
"""
222+
length = 0.55829
223+
kind = "vonkarman"
224+
position = 1.16
225+
bluffness = 0
226+
base_radius = 0.0635
227+
rocket_radius = 0.0635
228+
229+
# Case 1: base_radius == rocket_radius
230+
nose1 = NoseCone(
231+
length,
232+
kind,
233+
base_radius=base_radius,
234+
bluffness=bluffness,
235+
rocket_radius=rocket_radius,
236+
name="Nose Cone 1",
237+
)
238+
calisto.add_surfaces(nose1, position)
239+
assert nose1.radius_ratio == pytest.approx(1, 1e-8)
240+
assert calisto.static_margin(0) == pytest.approx(-8.9053, 0.01)
241+
242+
# Case 2: base_radius == rocket_radius / 2
243+
calisto.aerodynamic_surfaces.remove(nose1)
244+
nose2 = NoseCone(
245+
length,
246+
kind,
247+
base_radius=base_radius / 2,
248+
bluffness=bluffness,
249+
rocket_radius=rocket_radius,
250+
name="Nose Cone 2",
251+
)
252+
calisto.add_surfaces(nose2, position)
253+
assert nose2.radius_ratio == pytest.approx(0.5, 1e-8)
254+
assert calisto.static_margin(0) == pytest.approx(-8.9053, 0.01)
255+
256+
# Case 3: base_radius == None
257+
calisto.aerodynamic_surfaces.remove(nose2)
258+
nose3 = NoseCone(
259+
length,
260+
kind,
261+
base_radius=None,
262+
bluffness=bluffness,
263+
rocket_radius=rocket_radius * 2,
264+
name="Nose Cone 3",
265+
)
266+
calisto.add_surfaces(nose3, position)
267+
assert nose3.radius_ratio == pytest.approx(1, 1e-8)
268+
assert calisto.static_margin(0) == pytest.approx(-8.9053, 0.01)
269+
270+
# Case 4: rocket_radius == None
271+
calisto.aerodynamic_surfaces.remove(nose3)
272+
nose4 = NoseCone(
273+
length,
274+
kind,
275+
base_radius=base_radius,
276+
bluffness=bluffness,
277+
rocket_radius=None,
278+
name="Nose Cone 4",
279+
)
280+
calisto.add_surfaces(nose4, position)
281+
assert nose4.radius_ratio == pytest.approx(1, 1e-8)
282+
assert calisto.static_margin(0) == pytest.approx(-8.9053, 0.01)

0 commit comments

Comments
 (0)