RasmahRasmah

Drawing a Centrifugal Pump from Scratch

using Rasmah

Overview

A centrifugal pump moves water, coolant, or process fluid by spinning it: a volute casing (the spiral shell) collects the flow a rotating impeller flings outward, and the spiral widens toward the discharge so the fluid slows down and its velocity becomes pressure. Pumps like this one feed boilers, cool machine tools, fill water towers, and push flow through every industrial process loop.

This tutorial draws the two hydraulic parts of a small single-stage pump — the impeller (Ø110, six backward-curved vanes) and its volute casing — using the classic drafting constructions a drawing office would recognize: a circular pattern for the vanes, the four-centre spiral for the volute, booleans for the bore and the tongue, and an extrusion to give each part its width. Then the finished parts are put on the test stand: the impeller’s tip speed at 2900 RPM, the Euler head it can generate, and the masses of the two castings.

Every dimension is in millimetres; the code writes them as metres.

mm(x)  = x * 1e-3
mmv(v) = round(ustrip(uconvert(u"mm", v)); digits = 1)
mm2(v) = round(ustrip(uconvert(u"mm^2", v)); digits = 1)

D2, r1, bore, t, nv = 110.0, 15.0, 7.0, 3.0, 6      # Ø110 impeller, Ø14 shaft bore
Δ = deg2rad(25.0)                                   # vane trailing sweep
0.4363323129985824

The impeller: six backward-curved vanes

The impeller’s vanes are backward-curved: their tips trail the direction of rotation, which is what gives a pump its stable head curve. Each vane is drawn the same way as the gear tooth earlier in this series — a centreline curve offset by half the vane thickness, closed with round caps at both ends:

  • the centreline is a circular arc from the hub radius r = 15 to the tip radius r = 55 − t/2 (so the round tip cap lands exactly on the Ø110 outside diameter), tangent to the radial direction at the hub and sweeping back 25°;
  • the arc’s centre lies on the hub tangent line, at cy = −[(rc cosΔ − r1)² + (rc sinΔ)²] / (2 rc sinΔ) — the circle that passes through both endpoints and leaves the hub tangentially;
  • the vane polygon is the centreline offset by ±t/2 plus two end caps.
rc = D2 / 2 - t / 2                                   # 53.5: centreline tip radius
cy = -((rc * cos(Δ) - r1)^2 + (rc * sin(Δ))^2) / (2 * rc * sin(Δ))
ρ  = abs(cy)
a0 = atan(-cy, 0.0)                                   # centreline angle at the hub
a1 = atan(-rc * sin(Δ) - cy, rc * cos(Δ) - r1)        # ... and at the tip

vane = let m = 20                                    # one vane as a closed sketch
    as   = range(a0, a1; length = m)
    cen  = [[mm(r1 + ρ * cos(a)), mm(cy + ρ * sin(a))] for a in as]
    left  = [cen[i] .+ mm(t / 2) .* [cos(as[i]), sin(as[i])] for i in eachindex(as)]
    right = [cen[i] .- mm(t / 2) .* [cos(as[i]), sin(as[i])] for i in eachindex(as)]
    tipt  = [[cen[end][1] + mm(t / 2) * cos(a), cen[end][2] + mm(t / 2) * sin(a)] for a in range(a1, a1 + π; length = 9)]
    hubt  = [[cen[1][1]  + mm(t / 2) * cos(a), cen[1][2]  + mm(t / 2) * sin(a)] for a in range(a0 + π, a0 + 2π; length = 9)]
    polygon_2d([left..., tipt[2:end-1]..., reverse(right)..., hubt[2:end-1]...])
end

println("one vane area: ", mm2(area(vane)), " mm²")
one vane area: 121.7 mm²
vtk(extrude(vane, mm(15)); n = 24)

Six of them around the hub — the circular pattern — plus the hub and the back shroud, extruded to their widths, and the shaft bore drilled through:

# 1. the vane pattern + hub (15 mm tall), 2. the shroud back plate (5 mm), 3. shaft bore
impeller = difference(
    union(extrude(circle_2d(mm(55)), mm(5)),
          extrude(union(circle_2d(mm(15)), circular_pattern(vane, nv)), mm(15))),
    cylinder(mm(bore), mm(20)))
Difference{FeatureUnion{Extrude{Circle2D{Float64}, Float64}, Extrude{Union2D{Circle2D{Float64}, CircularPattern2D{Polygon2D{Float64}, Int64}}, Float64}}, Cylinder{Float64, Float64}}(FeatureUnion{Extrude{Circle2D{Float64}, Float64}, Extrude{Union2D{Circle2D{Float64}, CircularPattern2D{Polygon2D{Float64}, Int64}}, Float64}}(Extrude{Circle2D{Float64}, Float64}(Circle2D{Float64}(0.055), 0.005), Extrude{Union2D{Circle2D{Float64}, CircularPattern2D{Polygon2D{Float64}, Int64}}, Float64}(Union2D{Circle2D{Float64}, CircularPattern2D{Polygon2D{Float64}, Int64}}(Circle2D{Float64}(0.015), CircularPattern2D{Polygon2D{Float64}, Int64}(Polygon2D{Float64}([[0.015000000000000003, 0.0015], [0.01734920473792254, 0.0014265481598356125], [0.019689232066082113, 0.001206479586505515], [0.022010940427210298, 0.0008406540005103549], [0.024305259828966193, 0.00033050053710184093], [0.02656322727679376, -0.00032198783678099837], [0.028776021788781293, -0.0011142621082419954], [0.030934998855733878, -0.002043227176408739], [0.03303172421183703, -0.0031052539437622173], [0.03505800678398307, -0.004296193493579301]  …  [0.019315130471273874, -0.0017701036891247727], [0.017161787858867936, -0.0015675919359924757], [0.015000000000000003, -0.0015], [0.015574025148547638, -0.00138581929876693], [0.016060660171779824, -0.0010606601717798216], [0.016385819298766934, -0.0005740251485476356], [0.016500000000000004, -3.6739403974420597e-19], [0.016385819298766934, 0.000574025148547635], [0.016060660171779824, 0.001060660171779821], [0.015574025148547638, 0.0013858192987669298]]), 6)), 0.015)), Cylinder{Float64, Float64}(0.007, 0.02))
vtk(impeller; n = 20)

The outside diameter is the first drawing check — it must come out at exactly 110 mm:

lo, hi = bounds(impeller)
println("impeller OD: ", mmv(hi[1] - lo[1]), " mm   (drawing: 110 mm)")
impeller OD: 110.0 mm   (drawing: 110 mm)

The volute casing: the four-centre spiral

The casing’s job is to turn the impeller’s high-speed flow into pressure. Its wall is an Archimedean spiral: the radius grows linearly with angle, so the channel area grows and the fluid decelerates. The classic drafting-room way to draw it — no formula table needed — is the four-centre construction: a square of side p/4 (a quarter of the spiral pitch p), and four quarter-circle arcs centred on successive square corners, each radius p/4 larger than the last. Every junction is tangent because both centres at a junction lie on the same line, and the total radius grows by exactly the pitch over one full turn.

r0, p, H, w = 60.0, 20.0, 60.0, 14.0      # tongue radius, spiral pitch, duct length, casing width
q = p / 4                                 # the quarter-pitch square step

arc(cent, R, θ1, θ2; n = 16) =            # a quarter-turn arc, in millimetres -> metres
    [[mm(cent[1] + R * cos(θ)), mm(cent[2] + R * sin(θ))] for θ in range(deg2rad(θ1), deg2rad(θ2); length = n)]

# the four tangent arcs: centres (0,0) → (0,-q) → (q,-q) → (q,0), radii 60 → 75
spiral = vcat(arc((0.0, 0.0), r0, 0, 90),       arc((0.0, -q), r0 + q, 90, 180)[2:end],
              arc((q, -q), r0 + 2q, 180, 270)[2:end], arc((q, 0.0), r0 + 3q, 270, 360)[2:end])

# the casing outline: the spiral wall, then the tangential discharge duct
loop = vcat(spiral, [[mm(r0 + p), 0.0], [mm(r0 + p), mm(H)], [mm(r0), mm(H)], [mm(r0), 0.0]])
volute = extrude(difference(polygon_2d(loop), circle_2d(mm(r0))), mm(w))
Extrude{Difference2D{Polygon2D{Float64}, Circle2D{Float64}}, Float64}(Difference2D{Polygon2D{Float64}, Circle2D{Float64}}(Polygon2D{Float64}([[0.06, 0.0], [0.0596713137220964, 0.006271707796059207], [0.05868885604402834, 0.01247470144906556], [0.05706339097770921, 0.018541019662496844], [0.05481272745855605, 0.02440419858454801], [0.05196152422706632, 0.029999999999999995], [0.048541019662496854, 0.03526711513754839], [0.04458868952864366, 0.04014783638153149], [0.04014783638153149, 0.04458868952864365], [0.03526711513754839, 0.048541019662496854]  …  [0.06995190528383287, -0.03750000000000003], [0.07351590932319507, -0.03050524823068501], [0.07632923872213651, -0.023176274578121072], [0.07836107005503541, -0.015593376811331992], [0.0795891421526205, -0.007839634745074006], [0.08, -1.8369701987210297e-17], [0.08, 0.0], [0.08, 0.06], [0.06, 0.06], [0.06, 0.0]]), Circle2D{Float64}(0.06)), 0.014)

The last two lines are the geometry of the pump in one gesture: the outer wall is the spiral, closed by the tangential discharge duct (its walls are tangent to both the spiral end and the tongue circle — that is why the duct opens at right angles to the flow), and the tongue circle — the impeller’s chamber, Ø120, 5 mm of running clearance around the Ø110 impeller — is subtracted from the middle.

vtk(volute; n = 24)

The inspector’s checks are two distances: the discharge opening (the duct width, which the pitch p = 20 promises) and the tongue radius (60):

xs  = range(40e-3, 95e-3; length = 2001)
run = [field(volute, [x, mm(30), 0.0]) < 0 for x in xs]          # across the duct
i0  = findfirst(run); i1 = i0 + findfirst(.!run[i0:end]) - 1
println("discharge opening: ", mmv(xs[i1] - xs[i0]), " mm   (drawing: 20 mm)")

run2 = [field(volute, [x, 0.0, 0.0]) < 0 for x in xs]            # along the centreline
println("tongue radius:     ", mmv(xs[findfirst(run2)]), " mm   (drawing: 60 mm)")
discharge opening: 20.0 mm   (drawing: 20 mm)
tongue radius:     60.0 mm   (drawing: 60 mm)

The pump on the test stand

Now the numbers a pump engineer asks. At the synchronous motor speed of 2900 RPM (50 Hz mains), the impeller’s tip speed is

u2 = π * (D2 * 1e-3) * 2900 / 60
println("tip speed: ", round(u2; digits = 1), " m/s")
tip speed: 16.7 m/s

16.7 m/s — right in the 15–25 m/s band small industrial pumps run at. The Euler turbomachinery equation puts an upper bound on the head: with no inlet swirl, the ideal head is u₂²/g:

println("ideal head u₂²/g: ", round(u2^2 / 9.81; digits = 1), " m")
ideal head u₂²/g: 28.4 m

28 m of ideal head. A real pump delivers a fraction of that — slip between the vanes and the fluid plus hydraulic losses typically leave 50–70%, so this impeller belongs to the 15–20 m head class, a typical small single-stage (32-125 class) pump. That is what the drawing was for: the Ø110 impeller and the 20 mm discharge are the two numbers that set the whole machine.

Finally, the masses of the two castings — the impeller in steel, the casing in cast iron:

A_vane = ustrip(uconvert(u"mm^2", area(vane)))
V_imp  = (π * 55.0^2 * 5 + (nv * A_vane + π * 15.0^2) * 15 - π * 7.0^2 * 20) / 1e9   # m³
V_vol  = ustrip(volume(volute))

println("impeller: ", round(V_imp * 1e6; digits = 0), " cm³,  ", round(density(steel) * V_imp; digits = 2), " kg steel")
println("casing:   ", round(V_vol * 1e6; digits = 0), " cm³,  ", round(density(cast_iron) * V_vol; digits = 2), " kg cast iron")
impeller: 66.0 cm³,  0.52 kg steel
casing:   61.0 cm³,  0.44 kg cast iron

About a kilogram of metal for the hydraulic parts — believable for a small pump whose motor and bearing housing weigh ten times more. The two parts, assembled on their common axis:

vtk(union(impeller, volute); n = 16)

The impeller rides inside the tongue circle with its 5 mm of clearance, and the discharge duct opens straight into the outlet flange — where the flange drawings of the earlier tutorial bolt on.

Next steps