def calc_rel_properties(self): """Calculates the mass, relative/local center of mass, and relative/local inertia tensor (about the segment's center of mass). Also computes the center of mass of each constituent solid with respect to the segment's base in the segment's reference frame. """ # mass self._mass = 0.0 for s in self.solids: self._mass += s.mass # relative position of each solid w.r.t. segment orientation and # segment's origin solidpos = [] # center of mass of each solid w.r.t. segment orientation and # segment's origin solidCOM = [] z_unit_vector = np.array([[0, 0, 1]]).T if self._build_toward_positive_z: solidpos.append(np.zeros((3, 1))) for i in np.arange(self.nSolids): if i != 0: solidpos.append( solidpos[i-1] + self.solids[i-1].height * z_unit_vector) solidCOM.append(self.solids[0].rel_center_of_mass) for i in np.arange(self.nSolids): if i != 0: solidCOM.append( solidpos[i] + self.solids[i].rel_center_of_mass) else: # not self._build_toward_positive_z # solidpos last_pos = np.zeros((3, 1)) for solid in self.solids: solidpos.append(last_pos - solid.height * z_unit_vector) last_pos = solidpos[-1] # solidCOM for i in np.arange(self.nSolids): solidCOM.append(solidpos[i] + self.solids[i].rel_center_of_mass) # TODO above code could be substantially cleaned up. # relative center of mass relmoment = np.zeros((3, 1)) for i in np.arange(self.nSolids): relmoment += self.solids[i].mass * solidCOM[i] self._rel_center_of_mass = relmoment / self.mass # relative Inertia self._rel_inertia = np.mat(np.zeros((3, 3))) for i in np.arange(self.nSolids): dist = solidCOM[i] - self.rel_center_of_mass self._rel_inertia += np.mat(inertia.parallel_axis( self.solids[i].rel_inertia, self.solids[i].mass, [dist[0, 0], dist[1, 0], dist[2, 0]]))
def calc_properties(self): '''Calculates the segment's center of mass with respect to the fixed human frame origin (in the fixed human reference frame) and the segment's inertia in the fixed human frame but about the segment's center of mass. ''' # center of mass self.COM = self.pos + self.RotMat * self.relCOM # inertia in frame f w.r.t. segment's COM self.Inertia = inertia.rotate3_inertia(self.RotMat, self.relInertia) # an alternative way of calculating absolute inertia tensor, # implemented for validation purposes. # inertia in frame f w.r.t. segment's COM self.Inertia2 = np.mat(np.zeros((3, 3))) for s in self.solids: dist = s.COM - self.COM self.Inertia2 += np.mat(inertia.parallel_axis( s.Inertia, s.Mass, [dist[0, 0], dist[1, 0], dist[2, 0]]))
def calc_rel_properties(self): '''Calculates the mass, relative/local center of mass, and relative/local inertia tensor (about the segment's center of mass). Also computes the center of mass of each constituent solid with respect to the segment's base in the segment's reference frame. ''' # mass self.Mass = 0.0 for s in self.solids: self.Mass += s.Mass # relative position of each solid w.r.t. segment orientation and # segment's origin self.solidpos = [] self.solidpos.append(np.zeros((3, 1))) for i in np.arange(self.nSolids): if i != 0: self.solidpos.append( self.solidpos[i-1] + self.solids[i-1].height * np.array([[0, 0, 1]]).T) # center of mass of each solid w.r.t. segment orientation and # segment's origin self.solidCOM = [] self.solidCOM.append(self.solids[0].relCOM) for i in np.arange(self.nSolids): if i != 0: self.solidCOM.append( self.solidpos[i] + self.solids[i].relCOM) # relative center of mass relmoment = np.zeros((3, 1)) for i in np.arange(self.nSolids): relmoment += self.solids[i].Mass * self.solidCOM[i] self.relCOM = relmoment / self.Mass # relative Inertia self.relInertia = np.mat(np.zeros((3, 3))) for i in np.arange(self.nSolids): dist = self.solidCOM[i] - self.relCOM self.relInertia += np.mat(inertia.parallel_axis( self.solids[i].relInertia, self.solids[i].Mass, [dist[0, 0], dist[1, 0], dist[2, 0]]))
def steer_assembly_moment_of_inertia(self, handlebar=True, fork=True, wheel=True, aboutSteerAxis=False, nominal=False): """ Returns the inertia tensor of the steer assembly with respect to a reference frame aligned with the steer axis. Parameters ---------- handlebar : boolean, optional If true the handlebar will be included in the calculation. fork : boolean, optional If true the fork will be included in the calculation. wheel : boolean, optional If true then the wheel will be included in the calculation. aboutSteerAxis : boolean, optional If true the inertia tensor will be with respect to a point made from the projection of the center of mass onto the steer axis. nominal : boolean, optional If true the nominal values will be returned instead of a uarray. Returns ------- iAss : float Inertia tensor of the specified steer assembly parts with respect to a reference frame aligned with the steer axis. Notes ----- The 3 component is aligned with the steer axis (pointing downward), the 1 component is perpendicular to the steer axis (pointing forward) and the 2 component is perpendicular to the steer axis (pointing to the right). This function does not currently take into account the flywheel, D, if it is defined, beware. """ # load in the Benchmark parameter set par = self.parameters['Benchmark'] if 'mD' in par.keys(): print( "You have a flywheel defined. Beware that it is ignored in " + "the calculations and the results do not reflect that it is " + "there.") # there should always be either an H (handlebar/fork) and sometimes # there is a G (handlebar) and S (fork) if the fork and handlebar were # measured separately try: if fork and handlebar: # handlebar/fork I = inertia.part_inertia_tensor(par, 'H') m = par['mH'] x = par['xH'] z = par['zH'] elif fork and not handlebar: # fork alone I = inertia.part_inertia_tensor(par, 'S') m = par['mS'] x = par['xS'] z = par['zS'] elif handlebar and not fork: # handlebar alone I = inertia.part_inertia_tensor(par, 'G') m = par['mG'] x = par['xG'] z = par['zG'] else: # if neither set to zero I = np.zeros((3, 3)) m = 0. x = 0. z = 0. except KeyError: raise ValueError("The fork and handlebar were not measured " + "separately for this bicycle." + " Try making both the fork and handlebar either" + " both True or both False.") if wheel: # list the mass and com of the handlebar/assembly and the front # wheel masses = np.array([m, par['mF']]) coords = np.array([[x, par['w']], [0., 0.], [z, -par['rF']]]) # mass and com of the entire assembly mAss, cAss = com.total_com(coords, masses) # front wheel inertia in the benchmark reference frame about the # com IF = inertia.part_inertia_tensor(par, 'F') # distance from the fork/handlebar assembly (without wheel) to the # new center of mass for the assembly with the wheel d = np.array([x - cAss[0], 0., z - cAss[2]]) # distance from the front wheel center to the new center of mass # for the assembly with the wheel dF = np.array([par['w'] - cAss[0], 0., -par['rF'] - cAss[2]]) # this is the inertia of the assembly about the com with reference # to the benchmark bicycle reference frame iAss = (inertia.parallel_axis(I, m, d) + inertia.parallel_axis(IF, par['mF'], dF)) # this is the inertia of the assembly about a reference frame aligned with # the steer axis and through the center of mass iAssRot = inertia.rotate_inertia_tensor(iAss, par['lam']) else: # don't add the wheel mAss = m cAss = np.array([x, 0., z]) iAssRot = inertia.rotate_inertia_tensor(I, par['lam']) if aboutSteerAxis: # this is the distance from the assembly com to the steer axis distance = geometry.distance_to_steer_axis(par['w'], par['c'], par['lam'], cAss) print "handlebar cg distance", distance # now calculate the inertia about the steer axis of the rotated frame iAss = inertia.parallel_axis(iAssRot, mAss, np.array([distance, 0., 0.])) else: iAss = iAssRot if nominal: return unumpy.nominal_values(iAss) else: return iAss
def calculate_benchmark_from_measured(mp): '''Returns the benchmark (Meijaard 2007) parameter set based on the measured data. Parameters ---------- mp : dictionary Complete set of measured data. Returns ------- par : dictionary Benchmark bicycle parameter set. ''' forkIsSplit = is_fork_split(mp) par = {} # calculate the wheelbase, steer axis tilt and trail par = geometry.calculate_benchmark_geometry(mp, par) # masses par['mB'] = mp['mB'] par['mF'] = mp['mF'] par['mR'] = mp['mR'] try: # we measured the mass of the flywheel plus the mass of the front # wheel, mp['mD'], so to get the actual mass of the flywheel, subtract # the mass of the front wheel par['mD'] = mp['mD'] - mp['mF'] except KeyError: pass if forkIsSplit: par['mS'] = mp['mS'] par['mG'] = mp['mG'] else: par['mH'] = mp['mH'] # get the slopes, intercepts and betas for each part slopes, intercepts, betas = com.part_com_lines(mp, par, forkIsSplit) # calculate the centers of mass for part in slopes.keys(): par['x' + part], par['z' + part] = com.center_of_mass( slopes[part], intercepts[part]) # find the center of mass of the handlebar/fork assembly if the fork was # split if forkIsSplit: coordinates = np.array([[par['xS'], par['xG']], [0., 0.], [par['zS'], par['zG']]]) masses = np.array([par['mS'], par['mG']]) mH, cH = inertia.total_com(coordinates, masses) par['mH'] = mH par['xH'] = cH[0] par['zH'] = cH[2] # local accelation due to gravity par['g'] = mp['g'] # calculate the wheel y inertias par['IFyy'] = inertia.compound_pendulum_inertia(mp['mF'], mp['g'], mp['lF'], mp['TcF1']) par['IRyy'] = inertia.compound_pendulum_inertia(mp['mR'], mp['g'], mp['lR'], mp['TcR1']) try: # we measured the inertia of the front wheel with the flywheel inside iFlywheelPlusFwheel = inertia.compound_pendulum_inertia( mp['mD'], mp['g'], mp['lF'], mp['TcD1']) par['IDyy'] = iFlywheelPlusFwheel - par['IFyy'] except KeyError: pass # calculate the y inertias for the frame and fork lB = (par['xB']**2 + (par['zB'] + par['rR'])**2)**(0.5) par['IByy'] = inertia.compound_pendulum_inertia(mp['mB'], mp['g'], lB, mp['TcB1']) if forkIsSplit: # fork lS = ((par['xS'] - par['w'])**2 + (par['zS'] + par['rF'])**2)**(0.5) par['ISyy'] = inertia.compound_pendulum_inertia( mp['mS'], mp['g'], lS, mp['TcS1']) # handlebar l1, l2 = geometry.calculate_l1_l2(mp['h6'], mp['h7'], mp['d5'], mp['d6'], mp['l']) u1, u2 = geometry.fwheel_to_handlebar_ref(par['lam'], l1, l2) lG = ((par['xG'] - par['w'] + u1)**2 + (par['zG'] + par['rF'] + u2)**2)**(.5) par['IGyy'] = inertia.compound_pendulum_inertia( mp['mG'], mp['g'], lG, mp['TcG1']) else: lH = ((par['xH'] - par['w'])**2 + (par['zH'] + par['rF'])**2)**(0.5) par['IHyy'] = inertia.compound_pendulum_inertia( mp['mH'], mp['g'], lH, mp['TcH1']) # calculate the stiffness of the torsional pendulum IPxx, IPyy, IPzz = inertia.tube_inertia(mp['lP'], mp['mP'], mp['dP'] / 2., 0.) torStiff = inertia.torsional_pendulum_stiffness(IPyy, mp['TtP1']) #print "Torsional pendulum stiffness:", torStiff # calculate the wheel x/z inertias par['IFxx'] = inertia.tor_inertia(torStiff, mp['TtF1']) par['IRxx'] = inertia.tor_inertia(torStiff, mp['TtR1']) try: par['IDxx'] = inertia.tor_inertia(torStiff, mp['TtD1']) - par['IFxx'] except KeyError: pass pendulumInertias = {} # calculate the in plane moments of inertia for part, slopeSet in slopes.items(): # the number of orientations for this part numOrien = len(slopeSet) # intialize arrays to store the inertia values and orientation angles penInertia = np.zeros(numOrien, dtype=object) beta = np.array(betas[part]) # fill arrays of the inertias for i in range(numOrien): penInertia[i] = inertia.tor_inertia(torStiff, mp['Tt' + part + str(i + 1)]) # store these inertias pendulumInertias[part] = list(penInertia) inert = inertia.inertia_components(penInertia, beta) for i, axis in enumerate(['xx', 'xz', 'zz']): par['I' + part + axis] = inert[i] if forkIsSplit: # combine the moments of inertia to find the total handlebar/fork MoI IG = inertia.part_inertia_tensor(par, 'G') IS = inertia.part_inertia_tensor(par, 'S') # columns are parts, rows = x, y, z coordinates = np.array([[par['xG'], par['xS']], [0., 0.], [par['zG'], par['zS']]]) masses = np.array([par['mG'], par['mS']]) par['mH'], cH = com.total_com(coordinates, masses) par['xH'] = cH[0] par['zH'] = cH[2] dG = np.array([par['xG'] - par['xH'], 0., par['zG'] - par['zH']]) dS = np.array([par['xS'] - par['xH'], 0., par['zS'] - par['zH']]) IH = (inertia.parallel_axis(IG, par['mG'], dG) + inertia.parallel_axis(IS, par['mS'], dS)) par['IHxx'] = IH[0, 0] par['IHxz'] = IH[0, 2] par['IHyy'] = IH[1, 1] par['IHzz'] = IH[2, 2] # package the extra information that is useful outside this function extras = { 'slopes': slopes, 'intercepts': intercepts, 'betas': betas, 'pendulumInertias': pendulumInertias } return par, extras
def steer_assembly_moment_of_inertia(self, handlebar=True, fork=True, wheel=True, aboutSteerAxis=False, nominal=False): """ Returns the inertia tensor of the steer assembly with respect to a reference frame aligned with the steer axis. Parameters ---------- handlebar : boolean, optional If true the handlebar will be included in the calculation. fork : boolean, optional If true the fork will be included in the calculation. wheel : boolean, optional If true then the wheel will be included in the calculation. aboutSteerAxis : boolean, optional If true the inertia tensor will be with respect to a point made from the projection of the center of mass onto the steer axis. nominal : boolean, optional If true the nominal values will be returned instead of a uarray. Returns ------- iAss : float Inertia tensor of the specified steer assembly parts with respect to a reference frame aligned with the steer axis. Notes ----- The 3 component is aligned with the steer axis (pointing downward), the 1 component is perpendicular to the steer axis (pointing forward) and the 2 component is perpendicular to the steer axis (pointing to the right). This function does not currently take into account the flywheel, D, if it is defined, beware. """ # load in the Benchmark parameter set par = self.parameters['Benchmark'] if 'mD' in par.keys(): print("You have a flywheel defined. Beware that it is ignored in " + "the calculations and the results do not reflect that it is " + "there.") # there should always be either an H (handlebar/fork) and sometimes # there is a G (handlebar) and S (fork) if the fork and handlebar were # measured separately try: if fork and handlebar: # handlebar/fork I = inertia.part_inertia_tensor(par, 'H') m = par['mH'] x = par['xH'] z = par['zH'] elif fork and not handlebar: # fork alone I = inertia.part_inertia_tensor(par, 'S') m = par['mS'] x = par['xS'] z = par['zS'] elif handlebar and not fork: # handlebar alone I = inertia.part_inertia_tensor(par, 'G') m = par['mG'] x = par['xG'] z = par['zG'] else: # if neither set to zero I = np.zeros((3, 3)) m = 0. x = 0. z = 0. except KeyError: raise ValueError("The fork and handlebar were not measured " + "separately for this bicycle." + " Try making both the fork and handlebar either" + " both True or both False.") if wheel: # list the mass and com of the handlebar/assembly and the front # wheel masses = np.array([m, par['mF']]) coords = np.array([[x, par['w']], [0., 0.], [z, -par['rF']]]) # mass and com of the entire assembly mAss, cAss = com.total_com(coords, masses) # front wheel inertia in the benchmark reference frame about the # com IF = inertia.part_inertia_tensor(par, 'F') # distance from the fork/handlebar assembly (without wheel) to the # new center of mass for the assembly with the wheel d = np.array([x - cAss[0], 0., z - cAss[2]]) # distance from the front wheel center to the new center of mass # for the assembly with the wheel dF = np.array([par['w'] - cAss[0], 0., -par['rF'] - cAss[2]]) # this is the inertia of the assembly about the com with reference # to the benchmark bicycle reference frame iAss = (inertia.parallel_axis(I, m, d) + inertia.parallel_axis(IF, par['mF'], dF)) # this is the inertia of the assembly about a reference frame aligned with # the steer axis and through the center of mass iAssRot = inertia.rotate_inertia_tensor(iAss, par['lam']) else: # don't add the wheel mAss = m cAss = np.array([x, 0., z]) iAssRot = inertia.rotate_inertia_tensor(I, par['lam']) if aboutSteerAxis: # this is the distance from the assembly com to the steer axis distance = geometry.distance_to_steer_axis(par['w'], par['c'], par['lam'], cAss) print "handlebar cg distance", distance # now calculate the inertia about the steer axis of the rotated frame iAss = inertia.parallel_axis(iAssRot, mAss, np.array([distance, 0., 0.])) else: iAss = iAssRot if nominal: return unumpy.nominal_values(iAss) else: return iAss
def calculate_benchmark_from_measured(mp): '''Returns the benchmark (Meijaard 2007) parameter set based on the measured data. Parameters ---------- mp : dictionary Complete set of measured data. Returns ------- par : dictionary Benchmark bicycle parameter set. ''' forkIsSplit = is_fork_split(mp) par = {} # calculate the wheelbase, steer axis tilt and trail par = geometry.calculate_benchmark_geometry(mp, par) # masses par['mB'] = mp['mB'] par['mF'] = mp['mF'] par['mR'] = mp['mR'] try: # we measured the mass of the flywheel plus the mass of the front # wheel, mp['mD'], so to get the actual mass of the flywheel, subtract # the mass of the front wheel par['mD'] = mp['mD'] - mp['mF'] except KeyError: pass if forkIsSplit: par['mS'] = mp['mS'] par['mG'] = mp['mG'] else: par['mH'] = mp['mH'] # get the slopes, intercepts and betas for each part slopes, intercepts, betas = com.part_com_lines(mp, par, forkIsSplit) # calculate the centers of mass for part in slopes.keys(): par['x' + part], par['z' + part] = com.center_of_mass(slopes[part], intercepts[part]) # find the center of mass of the handlebar/fork assembly if the fork was # split if forkIsSplit: coordinates = np.array([[par['xS'], par['xG']], [0., 0.], [par['zS'], par['zG']]]) masses = np.array([par['mS'], par['mG']]) mH, cH = inertia.total_com(coordinates, masses) par['mH'] = mH par['xH'] = cH[0] par['zH'] = cH[2] # local accelation due to gravity par['g'] = mp['g'] # calculate the wheel y inertias par['IFyy'] = inertia.compound_pendulum_inertia(mp['mF'], mp['g'], mp['lF'], mp['TcF1']) par['IRyy'] = inertia.compound_pendulum_inertia(mp['mR'], mp['g'], mp['lR'], mp['TcR1']) try: # we measured the inertia of the front wheel with the flywheel inside iFlywheelPlusFwheel = inertia.compound_pendulum_inertia(mp['mD'], mp['g'], mp['lF'], mp['TcD1']) par['IDyy'] = iFlywheelPlusFwheel - par['IFyy'] except KeyError: pass # calculate the y inertias for the frame and fork lB = (par['xB']**2 + (par['zB'] + par['rR'])**2)**(0.5) par['IByy'] = inertia.compound_pendulum_inertia(mp['mB'], mp['g'], lB, mp['TcB1']) if forkIsSplit: # fork lS = ((par['xS'] - par['w'])**2 + (par['zS'] + par['rF'])**2)**(0.5) par['ISyy'] = inertia.compound_pendulum_inertia(mp['mS'], mp['g'], lS, mp['TcS1']) # handlebar l1, l2 = geometry.calculate_l1_l2(mp['h6'], mp['h7'], mp['d5'], mp['d6'], mp['l']) u1, u2 = geometry.fwheel_to_handlebar_ref(par['lam'], l1, l2) lG = ((par['xG'] - par['w'] + u1)**2 + (par['zG'] + par['rF'] + u2)**2)**(.5) par['IGyy'] = inertia.compound_pendulum_inertia(mp['mG'], mp['g'], lG, mp['TcG1']) else: lH = ((par['xH'] - par['w'])**2 + (par['zH'] + par['rF'])**2)**(0.5) par['IHyy'] = inertia.compound_pendulum_inertia(mp['mH'], mp['g'], lH, mp['TcH1']) # calculate the stiffness of the torsional pendulum IPxx, IPyy, IPzz = inertia.tube_inertia(mp['lP'], mp['mP'], mp['dP'] / 2., 0.) torStiff = inertia.torsional_pendulum_stiffness(IPyy, mp['TtP1']) #print "Torsional pendulum stiffness:", torStiff # calculate the wheel x/z inertias par['IFxx'] = inertia.tor_inertia(torStiff, mp['TtF1']) par['IRxx'] = inertia.tor_inertia(torStiff, mp['TtR1']) try: par['IDxx'] = inertia.tor_inertia(torStiff, mp['TtD1']) - par['IFxx'] except KeyError: pass pendulumInertias = {} # calculate the in plane moments of inertia for part, slopeSet in slopes.items(): # the number of orientations for this part numOrien = len(slopeSet) # intialize arrays to store the inertia values and orientation angles penInertia = np.zeros(numOrien, dtype=object) beta = np.array(betas[part]) # fill arrays of the inertias for i in range(numOrien): penInertia[i] = inertia.tor_inertia(torStiff, mp['Tt' + part + str(i + 1)]) # store these inertias pendulumInertias[part] = list(penInertia) inert = inertia.inertia_components(penInertia, beta) for i, axis in enumerate(['xx', 'xz', 'zz']): par['I' + part + axis] = inert[i] if forkIsSplit: # combine the moments of inertia to find the total handlebar/fork MoI IG = inertia.part_inertia_tensor(par, 'G') IS = inertia.part_inertia_tensor(par, 'S') # columns are parts, rows = x, y, z coordinates = np.array([[par['xG'], par['xS']], [0., 0.], [par['zG'], par['zS']]]) masses = np.array([par['mG'], par['mS']]) par['mH'], cH = com.total_com(coordinates, masses) par['xH'] = cH[0] par['zH'] = cH[2] dG = np.array([par['xG'] - par['xH'], 0., par['zG'] - par['zH']]) dS = np.array([par['xS'] - par['xH'], 0., par['zS'] - par['zH']]) IH = (inertia.parallel_axis(IG, par['mG'], dG) + inertia.parallel_axis(IS, par['mS'], dS)) par['IHxx'] = IH[0, 0] par['IHxz'] = IH[0, 2] par['IHyy'] = IH[1, 1] par['IHzz'] = IH[2, 2] # package the extra information that is useful outside this function extras = {'slopes' : slopes, 'intercepts' : intercepts, 'betas' : betas, 'pendulumInertias' : pendulumInertias} return par, extras