Skip to content
Open
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
22 changes: 18 additions & 4 deletions bladex/blade.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ class Blade(object):
radial section of the blade.
:param array_like skew_angles: 1D array, contains the skew angles
(in degrees) for each radial section of the blade.
:param array_like thickness: 1D array, contains the value of the
thickness of each section, specified if sections have not the desired thickness.
:param array_like camber: 1D array, contains the value of the
camber of each section, specified if sections have note the desired camber.

Note that, each of the previous array_like parameters must be consistent
with the other parameters in terms of the radial ordering of the blade
Expand Down Expand Up @@ -149,7 +153,7 @@ class Blade(object):
"""

def __init__(self, sections, radii, chord_lengths, pitch, rake,
skew_angles):
skew_angles, thickness=None, camber=None):
# Data are given in absolute values
self.sections = sections
self.n_sections = len(sections)
Expand All @@ -158,6 +162,8 @@ def __init__(self, sections, radii, chord_lengths, pitch, rake,
self.pitch = pitch
self.rake = rake
self.skew_angles = skew_angles
self.thickness = thickness
self.camber = camber
self._check_params()

self.conversion_factor = 1000 # to convert units if necessary
Expand Down Expand Up @@ -328,12 +334,20 @@ def apply_transformations(self, reflect=True):
# Translate reference point into origin
self.sections[i].translate(-self.sections[i].reference_point)

if reflect:
self.sections[i].reflect()

# Scale the unit chord to actual length.
self.sections[i].scale(self.chord_lengths[i])

# Setting thickness max is required
if self.thickness is not None:
self.sections[i].set_thickness_max(self.thickness[i])

# Setting camber max is required
if self.camber is not None and i < self.n_sections-1:
self.sections[i].set_camber_line_max(self.camber[i])

if reflect:
self.sections[i].reflect()

# Rotate according to the pitch angle.
# Since the current orientation system is not standard (It is
# left-handed Cartesian orientation system, where Y-axis points
Expand Down
47 changes: 44 additions & 3 deletions bladex/profile/baseprofile.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,9 +379,6 @@ def deform_camber_line(self, percent_change, n_interpolated_points=None):

:param float percent_change: percentage of change of the
maximum camber. Default value is None
:param bool interpolate: if True, the interpolated coordinates are
used to compute the camber line and foil's thickness, otherwise
the original discrete coordinates are used. Default value is False.
:param int n_interpolated_points: number of points to be used for the
equally-spaced sample computations. If None then there is no
interpolation, unless the arrays x_up != x_down elementwise which
Expand Down Expand Up @@ -415,6 +412,50 @@ def deform_camber_line(self, percent_change, n_interpolated_points=None):
self.yup_coordinates = self.camber_line[1] + half_thickness
self.ydown_coordinates = self.camber_line[1] - half_thickness

def set_camber_line_max(self, camber_max):
"""
Deform camber line according to a given maximum value.
The percentage of camber wrt to the x/c coordinate does not change, i.e.,
we rescale the camber value by a scalar
Also reconstructs the deformed airfoil's coordinates.

Thus, the percentage of change is defined as follows:

.. math::
\\frac{\\text{new magnitude of max camber - old magnitude of
maximum \
camber}}{\\text{old magnitude of maximum camber}} * 100

A positive percentage means the new camber is larger than the max
camber value, while a negative percentage indicates the new value
is smaller.

We note that the method works only for airfoils in the reference
position, i.e. chord line lies on the X-axis and the foil is not
rotated, since the measurements are based on the Y-values of the
airfoil coordinates, hence any measurements or scalings will be
inaccurate for the foils not in their reference position.

:param float camber_max: maximum camber to be set.
"""
old_camber_max = self.max_camber()
percent_scaling_factor = 100*(camber_max - old_camber_max) / (old_camber_max)
# print(percent_scaling_factor)
self.deform_camber_line(percent_scaling_factor)


def set_thickness_max(self, thickness_max):
"""
Deform y_up and y_down coordinates to have the desired thickness max value.
To do so, we compute the ratio between olt thickness and new one

:param float thickness_max: maximum thickness to be set.
"""
old_thickness = self.max_thickness()
ratio_thickness = thickness_max / old_thickness if old_thickness != 0. else 0.
self.yup_coordinates *= ratio_thickness
self.ydown_coordinates *= ratio_thickness

@property
def yup_curve(self):
"""
Expand Down
4 changes: 2 additions & 2 deletions bladex/profile/customprofile.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ def __init__(self, **kwargs):
raise RuntimeError(
"""Input arguments should be the section coordinates
(xup, yup, xdown, ydown) or the section parameters
(camber_perc, thickness_perc,
camber_max, thickness_max, chord_perc).""")
(camber_perc, thickness_perc, camber_max,
thickness_max, chord_perc, chord_len).""")

def generate_parameters(self, convention='british'):
return super().generate_parameters(convention)
Expand Down
19 changes: 19 additions & 0 deletions tests/test_profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,25 @@ def create_custom_profile():
return CustomProfile(xup=xup, yup=yup, xdown=xdown, ydown=ydown)


class TestBaseProfileMethods(TestCase):
def test_max_thickness(self):
profile = NacaProfile(digits='2412')
self.assertAlmostEqual(profile.max_thickness(), .12, delta=1e-4)

def test_set_thickness_max(self):
profile = NacaProfile(digits='2412')
profile.set_thickness_max(.24)
self.assertAlmostEqual(profile.max_thickness(), .24, delta=1e-4)

def test_max_camber(self):
profile = NacaProfile(digits='3412')
self.assertAlmostEqual(profile.max_camber(), .03, delta=1e-4)

def test_set_camber_max(self):
profile = NacaProfile(digits='3412')
profile.set_camber_line_max(.05)
self.assertAlmostEqual(profile.max_camber(), .05, delta=1e-4)

class TestCustomProfile(TestCase):
def test_inheritance_custom(self):
self.assertTrue(issubclass(CustomProfile, ProfileInterface))
Expand Down
Loading