SoCal Lift Station — Excel Template +
Submittal Report (Stormwater & Sanitary)
v2.0
Deliverable: Microsoft Excel workbook template (no add-ins required)
+ printable technical report Author: Code Copilot • Date: 2025-09-10
0) Build Plan (pseudocode)
1. Sheets: Inputs, K_Minors, LeD_Minors (optional), Hydraulics,
SystemCurve, PumpLibrary, Selection, NPSH, Charts, QAQC.
2. Named ranges on Inputs for all scalar inputs (units in labels). Provide
drop-downs for Design_Service and Minor_Method.
3. Hydraulics: Hazen-Williams friction; optional minors from K_Minors or
LeD_Minors; compute TDH and velocity checks.
4. SystemCurve: dynamic Q grid; compute head vs. Q using Inputs +
Hydraulics; expose as table.
5. PumpLibrary: per-pump 3-point Q-H; compute quadratic coefficients
(a,b,c), efficiency model, NPSHr interpolation.
6. Selection: for each pump, intersect H_pump(Q) with H_sys(Q) via grid +
interpolation; compute BEP proximity (POR), efficiency, HP, NPSH
margin, rank, and auto-authorize top picks.
7. NPSH: compute NPSHa (barometric by elevation, vapor pressure by
temp, suction losses). Feed Selection checks.
8. Charts: XY scatter of System Curve vs. each candidate pump; markers
at operating points; efficiency bubble overlay.
9. QAQC: flags for units/inputs, velocity, POR, NPSH, redundancy,
retention time; traffic-light formatting.
1) Workbook Setup (Excel 365 recommended)
1.1 Named ranges (on Inputs)
Create a two-column table (A:B) and define these Names (column A) with
values in column B. Use Data Validation lists where indicated.
Project (text)
Design_Service (list: Sanitary,Stormwater)
Q_input (accept gpm or cfs as label; store in gpm): enter gpm; if you
only have cfs, multiply by 448.831
Z_suction_ft
Z_discharge_ft
Static_Head_ft := formula =Z_discharge_ft - Z_suction_ft
ID_in (inside diameter, inches)
Length_straight_ft
C_HW
Minor_Method (list: K,LeD)
Use_EntranceExit (TRUE/FALSE)
Entrance_K
Exit_K
Downstream_Pressure_psi
Safety_Factor_Head (default 1.10)
Velocity_Target_min_fps (default 3)
Velocity_Target_max_fps (default 8)
Min_BEP_fraction (0.8)
Max_BEP_fraction (1.2)
Specific_Gravity (1.0)
Water_Temp_F (e.g., 68)
Num_Duty_Pumps (1)
Num_Standby_Pumps (1)
Helper Names (define via Formulas ▸ Name Manager):
ID_ft := =ID_in/12
Q_gpm := =Q_input
Q_cfs := =Q_gpm/448.831
Area_ft2 := =PI()*ID_ft^2/4
Velocity_fps := =Q_cfs/Area_ft2
Pressure_head_downstream_ft := =Downstream_Pressure_psi*2.31
1.2 K-method minors (K_Minors sheet)
Make an Excel Table tblK with columns: Item, K_default, Qty, K_use,
K_total. Prefill typical values (editable):
Entrance (sharp) 0.5, Exit (free) 1.0, 90° elbow 0.9, 45° elbow 0.4, Tee
run 0.6, Tee branch 1.8, Gate valve 0.17, Swing check 2.0, Butterfly
0.7, Reducer 0.5, Expander 1.0, User A, User B. Formulas in Table:
K_use = =IF([@K_default]="",0,[@K_default])
K_total = =[@Qty]*[@K_use] Define Name K_sum :=
=SUM(tblK[K_total]) Define Name g_fps2 := =32.174 Define Name
h_minor_K_ft := =K_sum*(Velocity_fps^2/(2*g_fps2))
1.3 Equivalent length (optional LeD_Minors)
Table tblLeD with columns: Fitting, Le_over_D, Qty, Le_each_ft,
Le_total_ft. Example Le/D: elbow 30, 45° 16, tee run 20, tee branch 60,
gate 8, swing check 100.
Le_each_ft = =[@Le_over_D]*ID_ft
Le_total_ft = =[@Qty]*[@Le_each_ft] Define Length_equiv_ft :=
=SUM(tblLeD[Le_total_ft])
2) Hydraulics sheet (Hazen–Williams + TDH)
Enter these formulas (cells shown as Name := formula):
hf_100ft_ftper100 :=
=0.2083*(100/C_HW)^1.852*(Q_gpm^1.852)/(ID_in^4.8655)
hf_pipe_ft := =hf_100ft_ftper100*( (Length_straight_ft +
IF(Minor_Method="LeD", Length_equiv_ft, 0))/100 )
h_entrance_ft := =IF(Use_EntranceExit,
Entrance_K*Velocity_fps^2/(2*g_fps2), 0)
h_exit_ft := =IF(Use_EntranceExit,
Exit_K*Velocity_fps^2/(2*g_fps2), 0)
h_minor_total_ft := =IF(Minor_Method="K", h_minor_K_ft,
0)+h_entrance_ft+h_exit_ft
H_static_ft := =Static_Head_ft + Pressure_head_downstream_ft
H_friction_ft := =hf_pipe_ft
TDH_raw_ft := =H_static_ft + H_friction_ft + h_minor_total_ft
TDH_select_ft := =TDH_raw_ft*Safety_Factor_Head
Velocity_OK := =AND(Velocity_fps>=Velocity_Target_min_fps,
Velocity_fps<=Velocity_Target_max_fps)
System curve function (grid) on SystemCurve:
In A2: header Q_gpm
In A3: =SEQUENCE(121,1,0,ROUNDUP(Q_gpm*1.8/120,0)) ➜ produces
~0→1.8×Q in ~121 points. If older Excel, fill series 0..1.8×Q.
In B2: header H_sys_ft
In B3 (copy down): =H_static_ft +
(0.2083*(100/C_HW)^1.852*(A3^1.852)/(ID_in^4.8655))*((Length_stra
ight_ft + IF(Minor_Method="LeD", Length_equiv_ft, 0))/100) +
IF(Minor_Method="K",K_sum*(( (A3/448.831)/Area_ft2
)^2/(2*g_fps2)),0) +
IF(Use_EntranceExit,Entrance_K*((A3/448.831)/Area_ft2)^2/(2*g_fps
2),0)+IF(Use_EntranceExit,Exit_K*((A3/448.831)/Area_ft2)^2/
(2*g_fps2),0) Make the range A2:B123 an Excel Table tblSystem.
3) Pump Library (PumpLibrary sheet)
Create Table tblPumps with these columns (one row per pump):
Pump_ID, Pump_Type, Speed_rpm, Min_Q_gpm, Max_Q_gpm, Q1_gpm, H1_ft,
Q2_gpm, H2_ft, Q3_gpm, H3_ft, BEP_Q_gpm, BEP_Eff, Motor_HP_rated,
N1_Q_gpm, N1_ft, N2_Q_gpm, N2_ft, N3_Q_gpm, N3_ft
3.1 Quadratic fit coefficients (three-point closed form)
Add columns a_ft, b_ftpergpm, c_ftpergpm2 with formulas in the first data
row, then fill down:
=LET(
Q1,[@Q1_gpm],Q2,[
@Q2_gpm],Q3,[@Q3_gpm],H1,[@H1_ft],H2,[@H2_ft],H3,[@H3_ft],
D,(Q1-Q2)*(Q1-Q3)*(Q2-Q3),
a,(H1*Q2*Q3*(Q2-Q3)+H2*Q3*Q1*(Q3-Q1)+H3*Q1*Q2*(Q1-Q2))/D,
a)
=LET(Q1,[@Q1_gpm],Q2,[@Q2_gpm],Q3,[@Q3_gpm],H1,[@H1_ft],H2,
[@H2_ft],H3,[@H3_ft],
D,(Q1-Q2)*(Q1-Q3)*(Q2-Q3),
b,(H1*(Q3^2-Q2^2)+H2*(Q1^2-Q3^2)+H3*(Q2^2-Q1^2))/D,
b)
=LET(Q1,[@Q1_gpm],Q2,[@Q2_gpm],Q3,[@Q3_gpm],H1,[@H1_ft],H2,
[@H2_ft],H3,[@H3_ft],
D,(Q1-Q2)*(Q1-Q3)*(Q2-Q3),
c,(H1*(Q2-Q3)+H2*(Q3-Q1)+H3*(Q1-Q2))/D,
c)
3.2 Efficiency model (approx)
Add column Eff_at_Q later (Selection) via: =MAX(0, [@BEP_Eff] -
([k_eff]*((Q/BEP_Q_gpm)^2 - 2*(Q/BEP_Q_gpm) + 1))) where k_eff is Name
=BEP_Eff/0.36 when evaluating (see Selection).
3.3 NPSHr interpolation
Define a Name NPSHr(Q,Row) using LAMBDA on PumpLibrary:
=LAMBDA(Q,Row,
LET(Q1,INDEX(tblPumps[N1_Q_gpm],Row), N1,INDEX(tblPumps[N1_ft],Row),
Q2,INDEX(tblPumps[N2_Q_gpm],Row), N2,INDEX(tblPumps[N2_ft],Row),
Q3,INDEX(tblPumps[N3_Q_gpm],Row), N3,INDEX(tblPumps[N3_ft],Row),
IF(Q<=Q1, N1,
IF(Q>=Q3, N3,
IF(Q<=Q2, N1 + (N2-N1)*(Q-Q1)/(Q2-Q1), N2 + (N3-N2)*(Q-
Q2)/(Q3-Q2))))) )
(Or compute directly in Selection per pump.)
3.4 Starter pumps (sample data)
Prefill three rows (edit freely in projects):
GEN-NC12-1750 (Non-clog submersible): (0,112) (1600,78)
(2800,38), BEP 1600 gpm @ 0.78, NPSHr pts (800,10) (1600,16)
(2400,21), Motor 75 hp.
GEN-NC10-1750 (Non-clog dry-pit): (0,128) (1200,92) (2200,50),
BEP 1200 gpm @ 0.76, NPSHr (600,9) (1200,14) (1800,18), Motor 60
hp.
GEN-AX18-885 (Axial/mixed-flow): (0,24) (8000,16) (12000,10), BEP
8000 gpm @ 0.85, NPSHr (6000,8) (8000,10) (10000,12), Motor 150
hp.
Add column Service_OK:
=IF(Design_Service="Sanitary", ISNUMBER(SEARCH("non-clog",
[@Pump_Type])),
OR(ISNUMBER(SEARCH("axial",[@Pump_Type])),
ISNUMBER(SEARCH("mixed",[@Pump_Type]))))
4) Selection sheet (auto-sizing & ranking; no macros)
4.1 Duty-point via grid+interpolation (per pump)
For each row r in tblPumps:
Compute series on SystemCurve: we already have Q and H_sys.
Compute pump head at grid: create a 2-col spill beside SystemCurve
(or on Selection) using MAP/BYROW:
PumpHead_r := a_r + b_r*Q + c_r*Q^2
Diff_r := PumpHead_r - H_sys
In classic formulas (no MAP): add two helper columns on SystemCurve per
pump or reuse one helper area on Selection with named cell refs to current
pump’s coefficients.
Find index where Diff_r changes sign or minimizes ABS(Diff_r):
i := XMATCH(TRUE, Diff_r>=0, 1) (next larger)
Q1 := INDEX(Q,i-1) ; Q2 := INDEX(Q,i)
F1 := INDEX(Diff_r,i-1) ; F2 := INDEX(Diff_r,i)
Interpolated Q_op := Q1 + (0 - F1)*(Q2-Q1)/(F2-F1)
H_op := H_sys(Q_op) via the same Hazen–Williams expression
replacing A3 with Q_op.
Clamp to pump min/max: Q_op := MIN(MAX(Q_op, Min_Q_gpm), Max_Q_gpm)
4.2 Performance, checks, scoring
Eff_op := MAX(0, BEP_Eff - (BEP_Eff/0.36)*((Q_op/BEP_Q_gpm -
1)^2))
HP_shaft := (Specific_Gravity*Q_op*H_op)/(3960*Eff_op) (hp)
HP_motor_required := HP_shaft/0.95
POR_OK := AND(Q_op>=Min_BEP_fraction*BEP_Q_gpm,
Q_op<=Max_BEP_fraction*BEP_Q_gpm)
TDH_margin_OK := (TDH_select_ft <= (a_r + b_r*Q_op + c_r*Q_op^2)
+ 3)
NPSHr_op := NPSHr(Q_op, r) or inline interpolation
NPSH_OK := NPSHa_ft >= 1.1*NPSHr_op
Velocity_OK from Hydraulics
Score (higher is better):
=100*Eff_op + 5*POR_OK + 2*Velocity_OK + 3*TDH_margin_OK -
0.1*ABS(Q_op-Q_gpm)
Sort tblSelection by Score desc. Top 3 flagged as Recommended; top 1
flagged Authorized.
tblSelection columns: Rank, Authorized, Pump_ID, Service, Q_op_gpm,
H_op_ft, Eff_op, Motor_HP, POR_OK, NPSH_OK, Velocity_OK, Score, Notes.
5) NPSH (NPSH sheet)
Inputs (cells with Names): Site_Elevation_ft, Wetwell_Level_ft,
Pump_CL_Elev_ft, Suction_Pipe_Length_ft, Suction_ID_in, Suction_C_HW,
Suction_K_sum
Helper Names:
Submergence_ft := Wetwell_Level_ft - Pump_CL_Elev_ft
P_atm_psi := IF(P_atm_mode="Direct", P_atm_psi_in, 14.696*EXP(-
Site_Elevation_ft/145366.45))
P_atm_head_ft := P_atm_psi*2.31
Vapor pressure table (tblPvap: Temp_F, Pvap_psi). Pvap_psi :=
FORECAST.LINEAR(Water_Temp_F, tblPvap[Pvap_psi], tblPvap[Temp_F])
Pvap_head_ft := Pvap_psi*2.31
Suction_ID_ft := Suction_ID_in/12
Area_suction_ft2 := PI()*Suction_ID_ft^2/4
V_suction_fps := Q_cfs/Area_suction_ft2
hf_suction_ft :=
0.2083*(100/Suction_C_HW)^1.852*(Q_gpm^1.852)/(Suction_ID_in^4.86
55)*(Suction_Pipe_Length_ft/100)
h_minor_suction_ft := Suction_K_sum*V_suction_fps^2/(2*g_fps2)
``
Expose NPSHa_ft to Selection for NPSH_OK check.
6) Charts (Charts sheet)
1. XY Scatter (smooth lines): X = tblSystem[Q_gpm], Y =
tblSystem[H_sys_ft].
2. Add series for each pump: X = tblSystem[Q_gpm], Y = computed
PumpHead_r spill range (or create per-pump computed column on
SystemCurve). Dim non-filtered pumps (Service_OK=FALSE) via
color/format.
3. Add single-point series for each operating point (Q_op_gpm, H_op_ft)
with markers.
4. Optional: Size markers by Eff_op using a bubble chart; or add data
labels showing Eff_op.
7) QA/QC (QAQC sheet)
Boolean checks with conditional formatting (red/amber/green):
Inputs present; no blank required cells
Velocity_OK
POR_OK (for chosen pump)
NPSH_OK
Redundancy_OK := Num_Standby_Pumps>=1
Retention_Time_hr := ( (Length_straight_ft +
IF(Minor_Method="LeD",Length_equiv_ft,0))*Area_ft2 / (Q_cfs*3600)
); flag if sanitary and > 2 hr (odor risk)
8) Optional VBA (root-finding alternative; not required)
Open Alt+F11 ▸ Insert ▸ Module and paste:
' Module: PumpDuty
Option Explicit
' Returns duty flow (gpm) where pump head equals system head using
bisection on [Qlo,Qhi]
Public Function DutyQ(ByVal a As Double, ByVal b As Double, ByVal c As
Double, _
ByVal Qlo As Double, ByVal Qhi As Double, _
ByVal Hstatic As Double, ByVal LenTotal As
Double, _
ByVal C As Double, ByVal Din As Double, _
ByVal Ksum As Double, ByVal UseK As Boolean, _
ByVal UseEntEx As Boolean, ByVal Kentr As
Double, ByVal Kexit As Double) As Double
Dim i As Long, mid As Double, fmid As Double, flo As Double, fhi
As Double
flo = PumpHead(a, b, c, Qlo) - SysHead(Qlo, Hstatic, LenTotal, C,
Din, Ksum, UseK, UseEntEx, Kentr, Kexit)
fhi = PumpHead(a, b, c, Qhi) - SysHead(Qhi, Hstatic, LenTotal, C,
Din, Ksum, UseK, UseEntEx, Kentr, Kexit)
If flo * fhi > 0 Then
DutyQ = Qlo ' fallback
Exit Function
End If
For i = 1 To 50
mid = 0.5 * (Qlo + Qhi)
fmid = PumpHead(a, b, c, mid) - SysHead(mid, Hstatic,
LenTotal, C, Din, Ksum, UseK, UseEntEx, Kentr, Kexit)
If fmid = 0# Then Exit For
If flo * fmid < 0 Then
Qhi = mid: fhi = fmid
Else
Qlo = mid: flo = fmid
End If
If Abs(Qhi - Qlo) < 0.01 Then Exit For
Next i
DutyQ = mid
End Function
Private Function PumpHead(a As Double, b As Double, c As Double, Q As
Double) As Double
PumpHead = a + b * Q + c * Q * Q
End Function
Private Function SysHead(Qgpm As Double, Hstatic As Double, LenTotal
As Double, _
C As Double, Din As Double, Ksum As Double, _
UseK As Boolean, UseEntEx As Boolean, Kentr
As Double, Kexit As Double) As Double
Dim hf100 As Double, v As Double, A As Double, Dft As Double,
hminor As Double
Dft = Din / 12#
A = 3.14159265358979 * Dft * Dft / 4#
v = (Qgpm / 448.831) / A
hf100 = 0.2083 * (100# / C) ^ 1.852 * (Qgpm ^ 1.852) / (Din ^
4.8655)
hminor = 0#
If UseK Then hminor = hminor + Ksum * v * v / (2# * 32.174)
If UseEntEx Then hminor = hminor + Kentr * v * v / (2# * 32.174) +
Kexit * v * v / (2# * 32.174)
SysHead = Hstatic + hf100 * (LenTotal / 100#) + hminor
End Function
Use in Selection per pump: =DutyQ(a,b,c, MAX(Min_Q_gpm,0.2*Q_gpm),
MIN(Max_Q_gpm,1.8*Q_gpm), H_static_ft,
Length_straight_ft+IF(Minor_Method="LeD",Length_equiv_ft,0), C_HW,
ID_in, K_sum, Minor_Method="K", Use_EntranceExit, Entrance_K, Exit_K)
Keep the non-macro grid method as default for transparency; use
VBA only if required by reviewer.
9) Submittal Report (printable from Excel)
Create a worksheet Report with the following sections (convert to PDF):
9.1 Executive Summary
Project description and service (Sanitary/Stormwater).
Duty flow, static head, pipe, TDH, selected pump, motor HP, efficiency,
NPSH margin.
9.2 Methodology
Hazen–Williams: (h_{100} = 0.2083 (100/C)^{1.852}, Q^{1.852} /
d^{4.8655}) with Q in gpm, d in inches.
Pipe headloss: (h_f = h_{100} (L/100))
Minors: K-method (h_m = K V^2/(2g)) or equivalent length (L_e =
(Le/D) d).
System curve: (H_{sys}(Q) = H_{static} + h_f(Q) + h_m(Q)).
Pump curves: 3-point quadratic fit ( H(Q) = a + bQ + cQ^2 ) from
manufacturer points; efficiency modeled about BEP when not provided.
Duty point: intersection of pump and system curves (grid +
interpolation).
Power: (HP = ).
9.3 Design Checks
POR: operate within ([, ]Q_{BEP}).
Velocity: 3–8 ft/s target for force mains.
NPSH: ensure (NPSHa , NPSHr).
Redundancy: duty + standby.
Retention time: note if excessive (odor risk for sanitary).
9.4 Results Tables
Inputs, Fittings, Hydraulics (Show steps), NPSH, Selection summary
with ranking and authorization.
9.5 Code & Standards Conformance Narrative (Southwest
California)
Conformance to California Plumbing Code (latest adopted edition by
AHJ at time of permit).
NPDES/State Water Board SSS General Order considerations for
sanitary conveyance reliability.
City manuals (e.g., LA BOE Sewer Design Manual Part F; City of San
Diego Stormwater Pump Station Guidelines) for pump station criteria,
redundancy, and submittal content.
Hydraulic Institute guidance for operating near BEP and POR/AOR.
9.6 Attachments
Manufacturer pump sheets for recommended models.
Charts: System vs Pump Curves; operating point markers; efficiency.
QA/QC checklist printout.
10) Demo Scenario (pre-filled)
Design_Service = Sanitary, Q_input = 1500, Z_suction_ft=102.5,
Z_discharge_ft=145.0, ID_in=11.9, Length_straight_ft=1450, C_HW=150,
Minor_Method=K with defaults in tblK, Safety_Factor_Head=1.10,
Water_Temp_F=68.
NPSH: Site_Elevation_ft=200, Wetwell_Level_ft=102.5,
Pump_CL_Elev_ft=95.0, suction length 0.
Use tblPumps starter rows. Selection will rank and authorize a top
pump.
11) Notes & Good Practice
Keep all formulas unit-consistent (US customary). Input units are
clearly labeled; constants embedded are dimensionalized accordingly.
When real manufacturer efficiency curves are available, replace the
symmetric model with tabular efficiency vs Q and interpolate.
For stormwater, consider seasonal/peak scenarios; for sanitary, check
diurnal firm capacity and redundancy.
Always replace sample pump data with actual submittals before final
approval.
End of Excel Template & Report Specification