def test_I_rim_only(): 'Check that wheel inertia returns rim inertia if no spoke density is given' w = BicycleWheel() w.hub = Hub(diameter=0.050, width=0.05) w.rim = Rim(radius=0.3, area=100e-6, I_lat=200. / 69e9, I_rad=100. / 69e9, J_tor=25. / 26e9, I_warp=0.0, young_mod=69e9, shear_mod=26e9, density=1.) w.lace_cross(n_spokes=36, n_cross=3, diameter=1.8e-3, young_mod=210e9, offset=0.) # Should return a warning that some spoke densities are not specified with pytest.warns(UserWarning): I_wheel = w.calc_rot_inertia() assert np.allclose(I_wheel, (2 * np.pi * 0.3 * 100e-6) * 0.3**2)
def test_I_spokes_only(): 'Check that spoke inertias are correctly calculated' w = BicycleWheel() w.hub = Hub(diameter=0.050, width=0.05) w.rim = Rim(radius=0.3, area=100e-6, I_lat=200. / 69e9, I_rad=100. / 69e9, J_tor=25. / 26e9, I_warp=0.0, young_mod=69e9, shear_mod=26e9) w.lace_radial(n_spokes=36, diameter=1.8e-3, young_mod=210e9, offset=0., density=1.0) # Calculate inertia of a single spoke m_spk = np.hypot(0.3 - 0.025, 0.025) * np.pi / 4 * (1.8e-3)**2 * 1.0 I_spk = m_spk * (0.3 - 0.025)**2 / 12. + m_spk * (0.5 * (0.025 + 0.3))**2 # Should return a warning that the rim density is not specified with pytest.warns(UserWarning): I_wheel = w.calc_rot_inertia() assert np.allclose(I_wheel, 36. * I_spk)
def wheel_from_row(self, j): 'Create a BicycleWheel object from a job row' # Try to un-pickle wheel object if 'wheel_pickle' in j: with open(self.out_dir + '/' + j['wheel_pickle'], 'rb') as p: w = pickle.load(p) else: w = BicycleWheel() w.hub = Hub(diam1=j['hub_diam1'], width1=j['hub_width1']) w.rim = Rim(radius=j['rim_radius'], area=j['rim_area'], I11=j['rim_I11'], I22=j['rim_I22'], I33=j['rim_I33'], Iw=j['rim_Iw'], young_mod=j['rim_young_mod'], shear_mod=j['rim_shear_mod']) w.lace_radial(n_spokes=int(j['spk_num']), diameter=j['spk_diameter'], young_mod=j['spk_young_mod']) if 'spk_paired' in j.keys() and j['spk_paired']: w = convert_to_paired(w) return w
def wheel_from_name(name): 'Generate a wheel from a standard template' df = pd.read_csv('../data/wheel_properties.csv', index_col=0) # Find requested wheel if name in df: p = df[name] w = BicycleWheel() w.hub = Hub(diam1=float(p['hub_diameter']) / 1000., width1=float(p['hub_width']) / 2000.) w.rim = Rim( radius=float(p['rim_radius']) / 1000., area=float(p['rim_area']) / 1e6, I11=float(p['rim_GJ']) / (float(p['rim_shear_mod']) * 1e9), I22=float(p['rim_EI2']) / (float(p['rim_young_mod']) * 1e9), I33=float(p['rim_EI1']) / (float(p['rim_young_mod']) * 1e9), Iw=0.0, young_mod=float(p['rim_young_mod']) * 1e9, shear_mod=float(p['rim_shear_mod']) * 1e9) if p['spk_pattern'] == 'radial': w.lace_radial(n_spokes=int(p['spk_num']), diameter=float(p['spk_diameter']) / 1000., young_mod=float(p['spk_young_mod']) * 1e9, offset=float(p['spk_offset']) / 1000.) else: raise KeyError('Spoke pattern {0:s} is not defined.'.format( p['spk_pattern'])) return w else: raise KeyError('Wheel template {0:s} is not defined.'.format(name))
def _build_wheel(): w = BicycleWheel() w.hub = Hub(diameter=0.050, width=0.05) w.rim = Rim(radius=0.3, area=100e-6, I_lat=200. / 69e9, I_rad=100. / 69e9, J_tor=25. / 26e9, I_warp=0.0, young_mod=69e9, shear_mod=26e9) return w
def create_wheel_from_lm(l, mu): """Create a wheel with arbitrary values of lambda and mu. Since the reverse problem of generating a wheel with a specified lambda and mu is not unique, some constraints must be applied: - wheel dimensions are R=300m, d_hub=50mm, w_hub=25mm - radial spokes, E=200 GPa - number and diameter of spokes are chosen to ensure that Pn_lat = 2 """ wheel = BicycleWheel() wheel.hub = Hub(diam1=0.05, width1=0.025) wheel.rim = Rim(radius=0.3, area=100e-6, I11=1000e-12 * (69. / 26.) * mu, I22=1000e-12, I33=1000e-12, Iw=0.0e-12, young_mod=69.0e9, shear_mod=26.0e9) alpha = np.arctan(wheel.hub.width1 / (wheel.rim.radius - wheel.hub.diam1 / 2)) ls = np.sqrt(wheel.hub.width1**2 + (wheel.rim.radius - wheel.hub.diam1 / 2)**2) # Calculate n_s by requiring that Pn_lat = 2.0 and round up to next even n_s = 1.5 * (8 * np.pi / np.power(4, 0.25)) * np.power( l * (mu + 1) / mu, 0.25) n_s = 2 * int(np.ceil(n_s / 2)) # Calculate spoke diameter based on requirement on lambda k_uu = l * wheel.rim.young_mod * wheel.rim.I22 / (wheel.rim.radius**4) A_s = 2 * np.pi * wheel.rim.radius * ls * k_uu / (n_s * 200e9 * np.sin(alpha)**2) d_s = np.sqrt(4 * A_s / np.pi) # Create spokes wheel.lace_radial(n_spokes=n_s, diameter=d_s, young_mod=200e9) return wheel
def _build_wheel(n_cross=0): w = BicycleWheel() w.hub = Hub(diameter=0.050, width=0.05) w.rim = Rim(radius=0.3, area=100e-6, I_lat=200. / 69e9, I_rad=100. / 69e9, J_tor=25. / 26e9, I_warp=0.0, young_mod=69e9, shear_mod=26e9) w.lace_cross(n_spokes=36, n_cross=n_cross, diameter=1.8e-3, young_mod=210e9, offset=0.) return w
def test_I_wheel_less_than_max(): 'Check that rotational inertia is less than theoretical maximum' w = BicycleWheel() w.hub = Hub(diameter=0.050, width=0.05) w.rim = Rim(radius=0.3, area=100e-6, J_tor=25. / 26e9, I_lat=200. / 69e9, I_rad=100. / 69e9, I_warp=0.0, young_mod=69e9, shear_mod=26e9, density=1.0) w.lace_radial(n_spokes=36, diameter=1.8e-3, young_mod=210e9, offset=0., density=1.0) I_wheel = w.calc_rot_inertia() assert I_wheel < w.calc_mass() * w.rim.radius**2
def build_wheel_from_UI(): 'Create a BicycleWheel object from UI inputs' w = BicycleWheel() # Hub w.hub = Hub(diameter=float(hub_diam.value)/1000., width_nds=np.abs(float(hub_width.value[0]))/1000., width_ds=np.abs(float(hub_width.value[1]))/1000.) # Rim r_matl = list(RIM_MATLS)[rim_matl.active] radius = RIM_SIZES[rim_size.value]['radius'] density = RIM_MATLS[r_matl]['density'] mass = float(rim_mass.value) / 1000. area = mass / (2*np.pi*radius*density) rim_young_mod = RIM_MATLS[r_matl]['young_mod'] rim_shear_mod = RIM_MATLS[r_matl]['shear_mod'] w.rim = Rim(radius=radius, area=area, I11=float(rim_GJ.value) / rim_shear_mod, I22=float(rim_EI2.value) / rim_young_mod, I33=float(rim_EI1.value) / rim_young_mod, Iw=0.0, young_mod=rim_young_mod, shear_mod=rim_shear_mod) # Drive-side if spk_pat_ds.value == 'Radial': n_cross_ds = 0 elif spk_pat_ds.value.endswith('-cross'): n_cross_ds = int(spk_pat_ds.value[0]) else: raise ValueError('Undefined drive-side spoke pattern: {:s}'.format(spk_pat_ds.value)) s_matl_ds = list(SPK_MATLS)[spk_matl_ds.active] w.lace_cross_ds(n_spokes=int(spk_num.value)//2, n_cross=n_cross_ds, diameter=float(spk_diam_ds.value)/1000., young_mod=SPK_MATLS[s_matl_ds]['young_mod'], offset=0.) # Implement this later # Non-drive-side if spk_pat_nds.value == 'Radial': n_cross_nds = 0 elif spk_pat_nds.value.endswith('-cross'): n_cross_nds = int(spk_pat_nds.value[0]) else: raise ValueError('Undefined drive-side spoke pattern: {:s}'.format(spk_pat_nds.value)) s_matl_nds = list(SPK_MATLS)[spk_matl_nds.active] w.lace_cross_nds(n_spokes=int(spk_num.value)//2, n_cross=n_cross_nds, diameter=float(spk_diam_nds.value)/1000., young_mod=SPK_MATLS[s_matl_nds]['young_mod'], offset=0.) # Implement this later if (spk_pat_ds.value == 'Radial' and spk_pat_nds.value == 'Radial' and float(spk_T_ds.value) == 0.): # Apply a vanishingly small tension to make stiffness matrix invertable w.apply_tension(T_avg=w.spokes[0].EA*1e-6) else: w.apply_tension(T_right=9.81*float(spk_T_ds.value)) return w
from bikewheelcalc import BicycleWheel, Rim, Hub, ModeMatrix import matplotlib.pyplot as plt import numpy as np # Create an example wheel and rim wheel = BicycleWheel() wheel.hub = Hub(width=0.05, diameter=0.05) wheel.rim = Rim(radius=0.3, area=100e-6, I_lat=200. / 69e9, I_rad=100. / 69e9, J_tor=25. / 26e9, I_warp=0.0, young_mod=69e9, shear_mod=26e9) wheel.lace_cross(n_spokes=36, n_cross=3, diameter=2.0e-3, young_mod=210e9) # Create a ModeMatrix model with 24 modes mm = ModeMatrix(wheel, N=24) # Create a 500 Newton pointing radially inwards at theta=0 F_ext = mm.F_ext(0., np.array([0., 500., 0., 0.])) # Calculate stiffness matrix K = mm.K_rim(tension=False) + mm.K_spk(smeared_spokes=False, tension=False) # Solve for the mode coefficients dm = np.linalg.solve(K, F_ext) # Get radial deflection theta = np.linspace(-np.pi, np.pi, 100)