Exemplo n.º 1
0
    def test_has_gyroscopic_forces_when_spinning(self):
        # When the body is spinning, a torque should cause a
        # perpendicular acceleration

        # Set up rigid body spinning about x axis, and precessing about z axis
        precession = 0.1
        spin = 27.3
        A = 2.4  # perpendicular inertia
        C = 5.7  # polar inertia

        b = RigidBody("body", mass=7.04, inertia=diag([A, A, C]))
        b.Rp[:, :] = rotmat_y(pi / 2)
        b.vp[3:] = [spin, 0, precession]
        update_skewmat(b.wps, b.vp[3:])
        b.calc_mass()

        # Expect moment of momentum to be [C*spin, 0, A*precession] in global
        Jp = dot(b.Rp, dot(b.inertia, b.Rp.T))
        hp = dot(Jp, b.vp[3:])
        assert_array_almost_equal(hp, [C * spin, 0, A * precession])

        # Expect the torque to be (precession * spin_speed) * (C - A)
        # about the y axis
        expected_Q2 = spin * precession * (C - A)
        assert_array_almost_equal(b.quad_forces, [0, 0, 0, 0, expected_Q2, 0])
    def test_accounts_for_offset_centre_of_mass_in_mass_matrix(self):
        # check mass matrix calculation when centre of mass is offset
        # from proximal node.
        b = RigidBody('body', mass=5.6, Xc=[1.2, 3.4, 5.4])
        b.calc_mass()

        # F = ma: a Z acceleration should produce a Z-force and X- and
        # Y-moments.
        F = -dot(b.mass_vv, [0, 0, 1, 0, 0, 0])
        assert_array_equal(F, b.mass * array([0, 0, -1, -3.4, 1.2, 0]))
Exemplo n.º 3
0
    def test_accounts_for_offset_centre_of_mass_in_applied_force(self):
        # check applied force due to gravity is correct
        b = RigidBody("body", mass=5.6, Xc=[1.2, 3.4, 5.4])
        s = System(gravity=9.81)  # need a System to define gravity
        s.add_leaf(b)
        s.setup()

        b.calc_mass()
        b.calc_external_loading()
        assert_array_equal(b.applied_forces, b.mass * 9.81 * array([0, 0, -1, -3.4, 1.2, 0]))
Exemplo n.º 4
0
    def test_accounts_for_offset_centre_of_mass_in_mass_matrix(self):
        # check mass matrix calculation when centre of mass is offset
        # from proximal node.
        b = RigidBody("body", mass=5.6, Xc=[1.2, 3.4, 5.4])
        b.calc_mass()

        # F = ma: a Z acceleration should produce a Z-force and X- and
        # Y-moments.
        F = -dot(b.mass_vv, [0, 0, 1, 0, 0, 0])
        assert_array_equal(F, b.mass * array([0, 0, -1, -3.4, 1.2, 0]))
    def test_has_gyroscopic_forces_when_spinning(self):
        # When the body is spinning, a torque should cause a
        # perpendicular acceleration

        # Set up rigid body spinning about x axis, and precessing about z axis
        precession = 0.1
        spin = 27.3
        A = 2.4  # perpendicular inertia
        C = 5.7  # polar inertia

        b = RigidBody('body', mass=7.04, inertia=diag([A, A, C]))
        b.Rp[:, :] = rotmat_y(pi / 2)
        b.vp[3:] = [spin, 0, precession]
        update_skewmat(b.wps, b.vp[3:])
        b.calc_mass()

        # Expect moment of momentum to be [C*spin, 0, A*precession] in global
        Jp = dot(b.Rp, dot(b.inertia, b.Rp.T))
        hp = dot(Jp, b.vp[3:])
        assert_array_almost_equal(hp, [C * spin, 0, A * precession])

        # Expect the torque to be (precession * spin_speed) * (C - A)
        # about the y axis
        expected_Q2 = spin * precession * (C - A)
        assert_array_almost_equal(b.quad_forces, [0, 0, 0, 0, expected_Q2, 0])
    def test_interal_forces(self):
        # NB minus sign because convention for applied_stress is that
        # stiffness loads are positive.
        b = RigidBody('body', 1)

        # Constant loading
        b.nodal_load = np.array([2, 3.1, 2.1])
        b.calc_external_loading()
        assert_array_equal(b.applied_forces, [2, 3.1, 2.1, 0, 0, 0])
        assert_array_equal(b.applied_stress, [])

        # Loading function
        b.nodal_load = lambda element, t: np.ones(3)
        b.calc_external_loading()
        assert_array_equal(b.applied_forces, [1, 1, 1, 0, 0, 0])
        assert_array_equal(b.applied_stress, [])
Exemplo n.º 7
0
def build_structure(rigid_body_configs):
    # Free joint represents the rigid-body motion of the platform
    free_joint = FreeJoint('base')

    for i, conf in enumerate(rigid_body_configs):
        name = conf.get('name', 'body{}'.format(i))
        conn = RigidConnection('conn-' + name, offset=conf['CoM'])
        body = RigidBody(name,
                         mass=conf['mass'],
                         inertia=np.diag(conf['inertia']))
        free_joint.add_leaf(conn)
        conn.add_leaf(body)

    system = System(free_joint)
    return system
    def test_accounts_for_offset_centre_of_mass_in_applied_force(self):
        # check applied force due to gravity is correct
        b = RigidBody('body', mass=5.6, Xc=[1.2, 3.4, 5.4])
        s = System(gravity=9.81)  # need a System to define gravity
        s.add_leaf(b)
        s.setup()

        b.calc_mass()
        b.calc_external_loading()
        assert_array_equal(b.applied_forces,
                           b.mass * 9.81 * array([0, 0, -1, -3.4, 1.2, 0]))
Exemplo n.º 9
0
    def test_interal_forces(self):
        # NB minus sign because convention for applied_stress is that
        # stiffness loads are positive.
        b = RigidBody("body", 1)

        # Constant loading
        b.nodal_load = np.array([2, 3.1, 2.1])
        b.calc_external_loading()
        assert_array_equal(b.applied_forces, [2, 3.1, 2.1, 0, 0, 0])
        assert_array_equal(b.applied_stress, [])

        # Loading function
        b.nodal_load = lambda element, t: np.ones(3)
        b.calc_external_loading()
        assert_array_equal(b.applied_forces, [1, 1, 1, 0, 0, 0])
        assert_array_equal(b.applied_stress, [])
Exemplo n.º 10
0
    def test_calculates_mass_and_inertia_in_global_coordinates(self):
        # simple rigid body at origin: this just checks the mass and
        # inertia carry directly through to element mass matrix
        II = diag([4.2, 6.7, 11.7])
        b = RigidBody('body', mass=4.3, inertia=II)
        b.calc_mass()
        assert_array_equal(b.mass_vv[:3, :3], 4.3 * eye(3))
        assert_array_equal(b.mass_vv[:3, 3:], 0)
        assert_array_equal(b.mass_vv[3:, :3], 0)
        assert_array_equal(b.mass_vv[3:, 3:], II)
        assert_array_equal(b.quad_forces, 0)

        # now rotate node by 90 deg about z axis, swapping x & y. This
        # confirms that the mass part doesn't change, but the inertia
        # matrix is updated.
        b.Rp = rotmat_z(pi / 2)
        b.calc_mass()
        assert_array_equal(b.mass_vv[:3, :3], 4.3 * eye(3))
        assert_array_equal(b.mass_vv[:3, 3:], 0)
        assert_array_equal(b.mass_vv[3:, :3], 0)
        assert_array_almost_equal(b.mass_vv[3:, 3:], diag([6.7, 4.2, 11.7]))
        assert_array_equal(b.quad_forces, 0)
Exemplo n.º 11
0
    def test_calculates_mass_and_inertia_in_global_coordinates(self):
        # simple rigid body at origin: this just checks the mass and
        # inertia carry directly through to element mass matrix
        II = diag([4.2, 6.7, 11.7])
        b = RigidBody("body", mass=4.3, inertia=II)
        b.calc_mass()
        assert_array_equal(b.mass_vv[:3, :3], 4.3 * eye(3))
        assert_array_equal(b.mass_vv[:3, 3:], 0)
        assert_array_equal(b.mass_vv[3:, :3], 0)
        assert_array_equal(b.mass_vv[3:, 3:], II)
        assert_array_equal(b.quad_forces, 0)

        # now rotate node by 90 deg about z axis, swapping x & y. This
        # confirms that the mass part doesn't change, but the inertia
        # matrix is updated.
        b.Rp = rotmat_z(pi / 2)
        b.calc_mass()
        assert_array_equal(b.mass_vv[:3, :3], 4.3 * eye(3))
        assert_array_equal(b.mass_vv[:3, 3:], 0)
        assert_array_equal(b.mass_vv[3:, :3], 0)
        assert_array_almost_equal(b.mass_vv[3:, 3:], diag([6.7, 4.2, 11.7]))
        assert_array_equal(b.quad_forces, 0)
Exemplo n.º 12
0
    def __init__(self, structure_config):
        s = structure_config

        #### Load details of flexible elements ####
        if 'definition' in s['tower']:
            if 'mass' in s['tower']:
                raise ValueError("Both tower definition and explicit mass!")
            self.tower_definition = Tower(s['tower']['definition'])
            assert np.all(self.tower_definition.stn_pos[:, :2] == 0)  # vert.
            z_tower = self.tower_definition.stn_pos[:, 2]
            self.tower_modes = ModesFromScratch(
                z_tower - z_tower[0],
                self.tower_definition.density, 1,
                self.tower_definition.EIy, self.tower_definition.EIz)
        else:
            self.tower_definition = None
            self.tower_modes = None

        if 'blade' in s:
            self.blade_modes = load_modes_from_Bladed(s['blade']['definition'])
        else:
            self.blade_modes = None

        #### Create the elements ####

        # Free joint represents the rigid-body motion of the platform
        free_joint = FreeJoint('base')

        # This is the rigid-body mass of the platform structure
        conn_platform = RigidConnection('conn-platform',
                                        offset=s['platform']['CoM'])
        platform = RigidBody('platform',
                             mass=s['platform']['mass'],
                             inertia=np.diag(s['platform']['inertia']))
        free_joint.add_leaf(conn_platform)
        conn_platform.add_leaf(platform)

        # Make a rigid body to represent the added mass
        # (approximate to zero frequency)
        #  XXX this is skipping the coupling matrix
        #A = whales_model.A(0)
        # added_mass = RigidBody('added-mass', mass=np.diag(A[:3, :3]),
        #                           inertia=A[3:, 3:])

        # Flexible tower or equivalent rigid body
        if self.tower_modes:
            # move base of tower 10m up, and rotate so tower x-axis is vertical
            conn_tower = RigidConnection(
                'conn-tower', offset=[0, 0, z_tower[0]],
                rotation=rotmat_y(-pi/2))
            tower = DistalModalElementFromScratch(
                'tower', self.tower_modes,
                s['tower']['number of normal modes'])
        else:
            # move tower to COG
            conn_tower = RigidConnection(
                'conn-tower', offset=s['tower']['CoM'])
            tower = RigidBody('tower', s['tower']['mass'],
                              np.diag(s['tower']['inertia']))
        free_joint.add_leaf(conn_tower)
        conn_tower.add_leaf(tower)

        # The nacelle -- rigid body
        # rotate back so nacelle inertia is aligned with global coordinates
        if self.tower_modes:
            nacoff = s['nacelle']['offset from tower top']
            conn_nacelle = RigidConnection('conn-nacelle',
                                           offset=dot(rotmat_y(pi/2), nacoff),
                                           rotation=rotmat_y(pi/2))
            tower.add_leaf(conn_nacelle)
        else:
            conn_nacelle = RigidConnection(
                'conn-nacelle',
                offset=np.array([0, 0, s['nacelle']['height']]))
            free_joint.add_leaf(conn_nacelle)
        nacelle = RigidBody(
            'nacelle',
            mass=s['nacelle']['mass'],
            inertia=np.diag(s['nacelle'].get('inertia', np.zeros(3))))
        conn_nacelle.add_leaf(nacelle)

        # The rotor hub -- currently just connections (no mass)
        # rotate so rotor centre is aligned with global coordinates
        if self.tower_modes:
            rotoff = s['rotor']['offset from tower top']
            conn_rotor = RigidConnection('conn-rotor',
                                         offset=dot(rotmat_y(pi/2), rotoff),
                                         rotation=rotmat_y(pi/2))
            tower.add_leaf(conn_rotor)
        else:
            conn_rotor = RigidConnection(
                'conn-rotor',
                offset=np.array([0, 0, s['nacelle']['height']]))
            free_joint.add_leaf(conn_rotor)

        # The drive shaft rotation (rotation about x)
        shaft = Hinge('shaft', [1, 0, 0])
        conn_rotor.add_leaf(shaft)

        # The blades
        if self.blade_modes:
            rtlen = s['rotor']['root length']
            Ryx = dot(rotmat_y(-pi/2), rotmat_x(-pi/2))  # align blade modes
            for i in range(3):
                R = rotmat_x(i*2*pi/3)
                root = RigidConnection('root%d' % (i+1),
                                       offset=dot(R, [0, 0, rtlen]),
                                       rotation=dot(R, Ryx))
                blade = ModalElement('blade%d' % (i+1), self.blade_modes)
                shaft.add_leaf(root)
                root.add_leaf(blade)
        else:
            rotor = RigidBody('rotor', s['rotor']['mass'],
                              np.diag(s['rotor']['inertia']))
            shaft.add_leaf(rotor)

        # Build system
        self.system = System(free_joint)

        # Constrain missing DOFs -- tower torsion & extension not complete
        if self.tower_modes:
            self.system.prescribe(tower, vel=0, part=[0, 3])