Note
Go to the end to download the full example code or to run this example in your browser via JupyterLite.
Dalby’s balancing of rotating masses (1902)#
Faster engines and turbines made unbalance a practical danger: a mass
\(m\) at radius \(r\) pulls on the bearings with
\(mr\omega^2\), a force that grows with the square of speed. William
Dalby’s The Balancing of Engines (1902) taught designers to balance any
set of rotating masses with two correction masses in chosen planes. Taking
moments about one correction plane, the reference plane, removes the
unknown correction there and gives the other directly; the force balance
then gives the first. A single correction can only make the shaft balance
statically, resting in any position, and leaves a rocking couple.
balance_rotating_masses() finds
the corrections and unbalance()
measures what remains. The example simulates the bearing reactions of a
rigid rotor before and after balancing.
import matplotlib.pyplot as plt
import numpy as np
from engineeringkit.mechanical_engineering import balance_rotating_masses, unbalance
Four masses on a shaft#
masses = np.array([0.20, 0.30, 0.25, 0.15])
radii = np.array([0.08, 0.06, 0.07, 0.09])
angles = np.radians([0.0, 75.0, 160.0, 270.0])
z = np.array([0.15, 0.30, 0.45, 0.60])
planes = np.array([0.0, 0.75])
force, couple = unbalance(masses, radii, angles, z)
print(f"before: force unbalance {force * 1e3:.2f} g m, couple unbalance {couple * 1e3:.2f} g m^2")
static = balance_rotating_masses(masses, radii, angles)
dynamic = balance_rotating_masses(masses, radii, angles, z, planes)
print("static correction:", static.summary())
print("two-plane corrections:", dynamic.summary())
before: force unbalance 10.73 g m, couple unbalance 3.61 g m^2
static correction: {'mass_radius_kg_m': [0.01073385070569282], 'angle_deg': [-113.11644661423342]}
two-plane corrections: {'mass_radius_kg_m': [0.01355920958764438, 0.004809993011868052], 'angle_deg': [-131.6852843733348, 3.028472457886462]}
Bearing reactions#
Bearings at the two correction planes carry the rotating forces of a rigid rotor. Static balance removes the net force but the two bearings still push in opposite directions; two-plane balance removes both.
def bearing_forces(m_list, r_list, a_list, z_list, omega):
u = np.asarray(m_list) * r_list * np.exp(1j * np.asarray(a_list))
right = (u * (np.asarray(z_list) - planes[0])).sum() / (planes[1] - planes[0]) * omega**2
left = u.sum() * omega**2 - right
return abs(left), abs(right)
omega = 2 * np.pi * 3000 / 60
before = bearing_forces(masses, radii, angles, z, omega)
once = bearing_forces([*masses, 1.0], [*radii, static.mass_radius[0]], [*angles, static.angle[0]], [*z, planes[0]], omega)
twice = bearing_forces([*masses, 1.0, 1.0], [*radii, *dynamic.mass_radius], [*angles, *dynamic.angle], [*z, *planes], omega)
for label, f in (("unbalanced", before), ("static balance", once), ("two-plane balance", twice)):
print(f"{label:>17}: bearing forces {f[0]:8.2f} N and {f[1]:8.2f} N at 3000 rpm")
assert np.isclose(once[0], once[1]) and once[0] > 1
assert max(twice) < 1e-10
f_after, c_after = unbalance([*masses, 1.0, 1.0], [*radii, *dynamic.mass_radius], [*angles, *dynamic.angle], [*z, *planes])
assert f_after < 1e-15 and c_after < 1e-15
fig, ax = dynamic.plot()
for m_i, r_i, a_i in zip(masses, radii, angles):
ax.plot([a_i, a_i], [0, m_i * r_i], "k-", lw=1)
ax.set_title("Masses (black) and two-plane corrections [kg m]")
plt.show()
![Masses (black) and two-plane corrections [kg m]](../../../../_images/sphx_glr_plot_02_dalby_balancing_001.png)
unbalanced: bearing forces 1338.24 N and 474.73 N at 3000 rpm
static balance: bearing forces 474.73 N and 474.73 N at 3000 rpm
two-plane balance: bearing forces 0.00 N and 0.00 N at 3000 rpm
Total running time of the script: (0 minutes 0.069 seconds)