Пример #1
0
    def test_rotation_about_axis(self):
        """
        Tests the rotations about the cartesian axes
        """
        i = np.array([1, 0, 0])
        j = np.array([0, 1, 0])
        k = np.array([0, 0, 1])

        angle = 90 * np.pi / 180

        # Testing rotations about the x axis - rotation3d_x
        out = algebra.rotation3d_x(angle).dot(j)
        for ax in range(3):
            self.assertAlmostEqual(out[ax], k[ax])

        out = algebra.rotation3d_x(angle).dot(k)
        for ax in range(3):
            self.assertAlmostEqual(out[ax], -j[ax])

        # Testing rotations about the y axis - rotation3d_y
        out = algebra.rotation3d_y(angle).dot(i)
        for ax in range(3):
            self.assertAlmostEqual(out[ax], -k[ax])

        out = algebra.rotation3d_y(angle).dot(k)
        for ax in range(3):
            self.assertAlmostEqual(out[ax], i[ax])

        # Testing rotations about the z axis - rotation3d_z
        out = algebra.rotation3d_z(angle).dot(i)
        for ax in range(3):
            self.assertAlmostEqual(out[ax], j[ax])

        out = algebra.rotation3d_z(angle).dot(j)
        for ax in range(3):
            self.assertAlmostEqual(out[ax], -i[ax])
Пример #2
0
def generate_strip(node_info,
                   airfoil_db,
                   aligned_grid,
                   orientation_in=np.array([1, 0, 0]),
                   calculate_zeta_dot=False):
    """
    Returns a strip of panels in ``A`` frame of reference, it has to be then rotated to
    simulate angles of attack, etc
    """
    strip_coordinates_a_frame = np.zeros((3, node_info['M'] + 1),
                                         dtype=ct.c_double)
    strip_coordinates_b_frame = np.zeros((3, node_info['M'] + 1),
                                         dtype=ct.c_double)
    zeta_dot_a_frame = np.zeros((3, node_info['M'] + 1), dtype=ct.c_double)

    # airfoil coordinates
    # we are going to store everything in the x-z plane of the b
    # FoR, so that the transformation Cab rotates everything in place.
    if node_info['M_distribution'] == 'uniform':
        strip_coordinates_b_frame[1, :] = np.linspace(0.0, 1.0,
                                                      node_info['M'] + 1)
    elif node_info['M_distribution'] == '1-cos':
        domain = np.linspace(0, 1.0, node_info['M'] + 1)
        strip_coordinates_b_frame[1, :] = 0.5 * (1.0 - np.cos(domain * np.pi))
    elif node_info['M_distribution'].lower() == 'user_defined':
        # strip_coordinates_b_frame[1, :-1] = np.linspace(0.0, 1.0 - node_info['last_panel_length'], node_info['M'])
        # strip_coordinates_b_frame[1,-1] = 1.
        strip_coordinates_b_frame[
            1, :] = node_info['user_defined_m_distribution']
    else:
        raise NotImplemented('M_distribution is ' +
                             node_info['M_distribution'] +
                             ' and it is not yet supported')
    strip_coordinates_b_frame[2, :] = airfoil_db[node_info['airfoil']](
        strip_coordinates_b_frame[1, :])

    # elastic axis correction
    for i_M in range(node_info['M'] + 1):
        strip_coordinates_b_frame[1, i_M] -= node_info['eaxis']

    # chord_line_b_frame = strip_coordinates_b_frame[:, -1] - strip_coordinates_b_frame[:, 0]
    cs_velocity = np.zeros_like(strip_coordinates_b_frame)

    # control surface deflection
    if node_info['control_surface'] is not None:
        b_frame_hinge_coords = strip_coordinates_b_frame[:, node_info[
            'M'] - node_info['control_surface']['chord']]
        # support for different hinge location for fully articulated control surfaces
        if node_info['control_surface']['hinge_coords'] is not None:
            # make sure the hinge coordinates are only applied when M == cs_chord
            if not node_info['M'] - node_info['control_surface']['chord'] == 0:
                node_info['control_surface']['hinge_coords'] = None
            else:
                b_frame_hinge_coords = node_info['control_surface'][
                    'hinge_coords']

        for i_M in range(
                node_info['M'] - node_info['control_surface']['chord'],
                node_info['M'] + 1):
            relative_coords = strip_coordinates_b_frame[:,
                                                        i_M] - b_frame_hinge_coords
            # rotate the control surface
            relative_coords = np.dot(
                algebra.rotation3d_x(
                    -node_info['control_surface']['deflection']),
                relative_coords)
            # deflection velocity
            try:
                cs_velocity[:, i_M] += np.cross(
                    np.array([
                        -node_info['control_surface']['deflection_dot'], 0.0,
                        0.0
                    ]), relative_coords)
            except KeyError:
                pass

            # restore coordinates
            relative_coords += b_frame_hinge_coords

            # substitute with new coordinates
            strip_coordinates_b_frame[:, i_M] = relative_coords

    # chord scaling
    strip_coordinates_b_frame *= node_info['chord']

    # twist transformation (rotation around x_b axis)
    if np.abs(node_info['twist']) > 1e-6:
        Ctwist = algebra.rotation3d_x(node_info['twist'])
    else:
        Ctwist = np.eye(3)

    # Cab transformation
    Cab = algebra.crv2rotation(node_info['beam_psi'])

    rot_angle = algebra.angle_between_vectors_sign(orientation_in, Cab[:, 1],
                                                   Cab[:, 2])
    if np.sign(np.dot(orientation_in, Cab[:, 1])) >= 0:
        rot_angle += 0.0
    else:
        rot_angle += -2 * np.pi
    Crot = algebra.rotation3d_z(-rot_angle)

    c_sweep = np.eye(3)
    if np.abs(node_info['sweep']) > 1e-6:
        c_sweep = algebra.rotation3d_z(node_info['sweep'])

    # transformation from beam to beam prime (with sweep and twist)
    for i_M in range(node_info['M'] + 1):
        strip_coordinates_b_frame[:, i_M] = np.dot(
            c_sweep,
            np.dot(Crot, np.dot(Ctwist, strip_coordinates_b_frame[:, i_M])))
        strip_coordinates_a_frame[:, i_M] = np.dot(
            Cab, strip_coordinates_b_frame[:, i_M])

        cs_velocity[:, i_M] = np.dot(Cab, cs_velocity[:, i_M])

    # zeta_dot
    if calculate_zeta_dot:
        # velocity due to pos_dot
        for i_M in range(node_info['M'] + 1):
            zeta_dot_a_frame[:, i_M] += node_info['pos_dot']

        # velocity due to psi_dot
        omega_a = algebra.crv_dot2omega(node_info['beam_psi'],
                                        node_info['psi_dot'])
        for i_M in range(node_info['M'] + 1):
            zeta_dot_a_frame[:,
                             i_M] += (np.dot(algebra.skew(omega_a),
                                             strip_coordinates_a_frame[:,
                                                                       i_M]))

        # control surface deflection velocity contribution
        try:
            if node_info['control_surface'] is not None:
                node_info['control_surface']['deflection_dot']
                for i_M in range(node_info['M'] + 1):
                    zeta_dot_a_frame[:, i_M] += cs_velocity[:, i_M]
        except KeyError:
            pass

    else:
        zeta_dot_a_frame = np.zeros((3, node_info['M'] + 1), dtype=ct.c_double)

    # add node coords
    for i_M in range(node_info['M'] + 1):
        strip_coordinates_a_frame[:, i_M] += node_info['beam_coord']

    # add quarter-chord disp
    delta_c = (strip_coordinates_a_frame[:, -1] -
               strip_coordinates_a_frame[:, 0]) / node_info['M']
    if node_info['M_distribution'] == 'uniform':
        for i_M in range(node_info['M'] + 1):
            strip_coordinates_a_frame[:, i_M] += 0.25 * delta_c
    else:
        warnings.warn(
            "No quarter chord disp of grid for non-uniform grid distributions implemented",
            UserWarning)

    # rotation from a to g
    for i_M in range(node_info['M'] + 1):
        strip_coordinates_a_frame[:, i_M] = np.dot(
            node_info['cga'], strip_coordinates_a_frame[:, i_M])
        zeta_dot_a_frame[:, i_M] = np.dot(node_info['cga'],
                                          zeta_dot_a_frame[:, i_M])

    return strip_coordinates_a_frame, zeta_dot_a_frame
Пример #3
0
def alpha_beta_to_direction(alpha, beta):
    direction = np.array([1, 0, 0])
    alpha_rot = algebra.rotation3d_y(alpha)
    beta_rot = algebra.rotation3d_z(beta)
    direction = np.dot(beta_rot, np.dot(alpha_rot, direction))
    return direction
Пример #4
0
def generate_strip(node_info,
                   airfoil_db,
                   aligned_grid,
                   orientation_in=np.array([1, 0, 0])):
    """
    Returns a strip in "a" frame of reference, it has to be then rotated to
    simulate angles of attack, etc
    :param node_info:
    :param airfoil_db:
    :param aligned_grid:
    :param orientation_in:
    :return:
    """
    strip_coordinates_a_frame = np.zeros((3, node_info['M'] + 1),
                                         dtype=ct.c_double)
    strip_coordinates_b_frame = np.zeros((3, node_info['M'] + 1),
                                         dtype=ct.c_double)

    # airfoil coordinates
    # we are going to store everything in the x-z plane of the b
    # FoR, so that the transformation Cab rotates everything in place.
    if node_info['M_distribution'] == 'uniform':
        strip_coordinates_b_frame[1, :] = np.linspace(0.0, 1.0,
                                                      node_info['M'] + 1)
    elif node_info['M_distribution'] == '1-cos':
        domain = np.linspace(0, 1.0, node_info['M'] + 1)
        strip_coordinates_b_frame[1, :] = 0.5 * (1.0 - np.cos(domain * np.pi))
    else:
        raise NotImplemented('M_distribution is ' +
                             node_info['M_distribution'] +
                             ' and it is not yet supported')
    strip_coordinates_b_frame[2, :] = airfoil_db[node_info['airfoil']](
        strip_coordinates_b_frame[1, :])

    # elastic axis correction
    for i_M in range(node_info['M'] + 1):
        strip_coordinates_b_frame[1, i_M] -= node_info['eaxis']

    # chord scaling
    strip_coordinates_b_frame *= node_info['chord']

    # twist transformation (rotation around x_b axis)
    if np.abs(node_info['twist']) > 1e-6:
        Ctwist = algebra.rotation3d_x(node_info['twist'])
    else:
        Ctwist = np.eye(3)

    # Cab transformation
    Cab = algebra.crv2rot(node_info['beam_psi'])

    # sweep angle correction
    # angle between orientation_in and chord line
    chord_line_b_frame = strip_coordinates_b_frame[:,
                                                   -1] - strip_coordinates_b_frame[:,
                                                                                   0]
    chord_line_a_frame = np.dot(Cab, chord_line_b_frame)
    sweep_angle = algebra.angle_between_vectors_sign(orientation_in,
                                                     chord_line_a_frame,
                                                     np.array([0, 0, 1]))
    # rotation matrix
    Csweep = algebra.rotation3d_z(-sweep_angle)

    # transformation from beam to aero
    for i_M in range(node_info['M'] + 1):
        strip_coordinates_a_frame[:, i_M] = np.dot(
            Cab,
            np.dot(Csweep, np.dot(Ctwist, strip_coordinates_b_frame[:, i_M])))

    # add node coords
    for i_M in range(node_info['M'] + 1):
        strip_coordinates_a_frame[:, i_M] += node_info['beam_coord']

    return strip_coordinates_a_frame
Пример #5
0
def generate_strip(node_info, airfoil_db, aligned_grid, orientation_in=np.array([1, 0, 0]), calculate_zeta_dot = False):
    """
    Returns a strip in "a" frame of reference, it has to be then rotated to
    simulate angles of attack, etc
    :param node_info:
    :param airfoil_db:
    :param aligned_grid:
    :param orientation_in:
    :return:
    """
    strip_coordinates_a_frame = np.zeros((3, node_info['M'] + 1), dtype=ct.c_double)
    strip_coordinates_b_frame = np.zeros((3, node_info['M'] + 1), dtype=ct.c_double)

    # airfoil coordinates
    # we are going to store everything in the x-z plane of the b
    # FoR, so that the transformation Cab rotates everything in place.
    if node_info['M_distribution'] == 'uniform':
        strip_coordinates_b_frame[1, :] = np.linspace(0.0, 1.0, node_info['M'] + 1)
    elif node_info['M_distribution'] == '1-cos':
        domain = np.linspace(0, 1.0, node_info['M'] + 1)
        strip_coordinates_b_frame[1, :] = 0.5*(1.0 - np.cos(domain*np.pi))
    else:
        raise NotImplemented('M_distribution is ' + node_info['M_distribution'] +
                             ' and it is not yet supported')
    strip_coordinates_b_frame[2, :] = airfoil_db[node_info['airfoil']](
                                            strip_coordinates_b_frame[1, :])

    # elastic axis correction
    for i_M in range(node_info['M'] + 1):
        strip_coordinates_b_frame[1, i_M] -= node_info['eaxis']

    chord_line_b_frame = strip_coordinates_b_frame[:, -1] - strip_coordinates_b_frame[:, 0]

    # control surface deflection
    if node_info['control_surface'] is not None:
        b_frame_hinge_coords = strip_coordinates_b_frame[:, node_info['M'] - node_info['control_surface']['chord']]
        # support for different hinge location for fully articulated control surfaces
        if node_info['control_surface']['hinge_coords'] is not None:
            # make sure the hinge coordinates are only applied when M == cs_chord
            if not node_info['M'] - node_info['control_surface']['chord'] == 0:
                cout.cout_wrap('The hinge coordinates parameter is only supported when M == cs_chord')
                node_info['control_surface']['hinge_coords'] = None
            else:
                b_frame_hinge_coords =  node_info['control_surface']['hinge_coords']

        for i_M in range(node_info['M'] - node_info['control_surface']['chord'], node_info['M'] + 1):
            relative_coords = strip_coordinates_b_frame[:, i_M] - b_frame_hinge_coords
            # rotate the control surface
            relative_coords = np.dot(algebra.rotation3d_x(-node_info['control_surface']['deflection']),
                                     relative_coords)
            # restore coordinates
            relative_coords += b_frame_hinge_coords

            # substitute with new coordinates
            strip_coordinates_b_frame[:, i_M] = relative_coords

    # chord scaling
    strip_coordinates_b_frame *= node_info['chord']

    # twist transformation (rotation around x_b axis)
    if np.abs(node_info['twist']) > 1e-6:
        Ctwist = algebra.rotation3d_x(node_info['twist'])
    else:
        Ctwist = np.eye(3)

    # Cab transformation
    Cab = algebra.crv2rot(node_info['beam_psi'])

    rot_angle = algebra.angle_between_vectors_sign(orientation_in, Cab[:, 1], Cab[:, 2])
    Crot = algebra.rotation3d_z(-rot_angle)

    c_sweep = np.eye(3)
    if np.abs(node_info['sweep']) > 1e-6:
        c_sweep = algebra.rotation3d_z(node_info['sweep'])

    # transformation from beam to beam prime (with sweep and twist)
    for i_M in range(node_info['M'] + 1):
        strip_coordinates_b_frame[:, i_M] = np.dot(c_sweep, np.dot(Crot,
                                                   np.dot(Ctwist, strip_coordinates_b_frame[:, i_M])))
        strip_coordinates_a_frame[:, i_M] = np.dot(Cab, strip_coordinates_b_frame[:, i_M])

    # zeta_dot
    if calculate_zeta_dot:
        zeta_dot_a_frame = np.zeros((3, node_info['M'] + 1), dtype=ct.c_double)

        # velocity due to pos_dot
        for i_M in range(node_info['M'] + 1):
            zeta_dot_a_frame[:, i_M] += node_info['pos_dot']

        # velocity due to psi_dot
        Omega_b = algebra.crv_dot2Omega(node_info['beam_psi'], node_info['psi_dot'])
        for i_M in range(node_info['M'] + 1):
            zeta_dot_a_frame[:, i_M] += (
                np.dot(algebra.skew(Omega_b), strip_coordinates_a_frame[:, i_M]))

    else:
        zeta_dot_a_frame = np.zeros((3, node_info['M'] + 1), dtype=ct.c_double)

    # add node coords
    for i_M in range(node_info['M'] + 1):
        strip_coordinates_a_frame[:, i_M] += node_info['beam_coord']

    # rotation from a to g
    for i_M in range(node_info['M'] + 1):
        strip_coordinates_a_frame[:, i_M] = np.dot(node_info['cga'],
                                                   strip_coordinates_a_frame[:, i_M])
        zeta_dot_a_frame[:, i_M] = np.dot(node_info['cga'],
                                          zeta_dot_a_frame[:, i_M])

    return strip_coordinates_a_frame, zeta_dot_a_frame