Data Analysis for Engineers/Module 4

Module 4 · Section 4 of 10

Lesson 4.3 - Engineering-Specific Charts

Target: ~10 min read - 20 min hands-on

Overview

Some chart types are specific to engineering practice. We'll build four, one per field: a load-duration curve (electrical / energy), a pump vs system curve (mechanical), a Moody diagram (fluids - chemical / mechanical), and a Sankey energy balance (applies to everyone).

Why This Matters (Engineering Context)

These aren't just "charts" - each is a standard reference tool in its field. Being able to generate one from your own computed data, rather than eyeballing a textbook figure, is a genuine analytical upgrade.

Code-Along

# --- [Electrical] Load-duration curve: every hour's load, sorted high -> low ---
np.random.seed(7)
# np.clip(a, lo, hi) caps values into a range; here just a lower bound of 800 kW
hourly_load = np.clip(np.random.normal(3800, 900, 8760)
                      + 700 * np.sin(np.arange(8760) / 8760 * 4 * np.pi), 800, None)
sorted_load = np.sort(hourly_load)[::-1]          # sort ascending, then [::-1] reverses it
pct_time = np.arange(1, 8761) / 8760 * 100        # x-axis: % of the year

fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(pct_time, sorted_load, color="navy")
ax.fill_between(pct_time, sorted_load, alpha=0.15, color="navy")   # shade under the curve
ax.set_xlabel("Percent of year load is exceeded (%)")
ax.set_ylabel("Load (kW)")
ax.set_title("Load-Duration Curve")
plt.tight_layout(); plt.show()

# --- [Mechanical] Pump curve vs system curve: they cross at the operating point ---
Q = np.linspace(0, 0.03, 200)
pump_H = 45 - 6.0e5 * Q**2
system_H = 12 + 2.5e5 * Q**2
idx = np.argmin(np.abs(pump_H - system_H))        # index where the two curves are closest
fig, ax = plt.subplots(figsize=(7, 5))
ax.plot(Q * 1000, pump_H, label="Pump curve", color="darkred")     # *1000: m^3/s -> L/s
ax.plot(Q * 1000, system_H, label="System curve", color="steelblue")
ax.plot(Q[idx] * 1000, pump_H[idx], "ko")         # "ko" = black circle marker
ax.annotate("operating point", (Q[idx] * 1000, pump_H[idx]),
            textcoords="offset points", xytext=(10, 10))
ax.set_xlabel("Flow (L/s)"); ax.set_ylabel("Head (m)")
ax.set_title("Pump vs System Curve"); ax.legend()
plt.tight_layout(); plt.show()

# --- [Chemical/Mechanical] Moody diagram: friction factor vs Reynolds number ---
def colebrook_f(Re, rel_roughness, f_guess=0.02):
    f = f_guess
    for _ in range(30):                            # fixed-point iteration to solve for f
        f = (-2 * np.log10(rel_roughness / 3.7 + 2.51 / (Re * np.sqrt(f))))**-2
    return f

Re_range = np.logspace(3.7, 8, 100)               # log-spaced points from ~5e3 to 1e8
fig, ax = plt.subplots(figsize=(8, 6))
for rr in [0.05, 0.01, 0.001, 0.0001, 0.000001]:  # one curve per relative roughness
    ax.plot(Re_range, [colebrook_f(Re, rr) for Re in Re_range], label=f"eps/D = {rr}")
ax.set_xscale("log"); ax.set_yscale("log")        # both axes span orders of magnitude
ax.set_xlabel("Reynolds Number"); ax.set_ylabel("Friction Factor")
ax.set_title("Moody Diagram (Colebrook Equation)")
ax.legend(fontsize=8); ax.grid(True, which="both", alpha=0.3)   # which="both": major+minor gridlines
plt.tight_layout(); plt.show()

# --- Sankey energy balance: flow widths must sum to zero (in = out) ---
from matplotlib.sankey import Sankey
fig = plt.figure(figsize=(8, 5))
ax = fig.add_subplot(111, xticks=[], yticks=[])   # blank axes, no ticks
s = Sankey(ax=ax, unit="%", format="%.0f")
# positive flow = in, negative = out; orientations route each arm (0 = horizontal)
s.add(flows=[100, -55, -25, -12, -8],
      labels=["Grid input", "Process loads", "HVAC / cooling", "Lighting & aux", "Losses"],
      orientations=[0, 0, -1, 1, -1])
s.finish()
ax.set_title("Facility Energy Balance")
plt.show()

Run it: four distinct engineering charts should render - a filled load-duration curve, a pump/system-curve intersection marking the operating point, a Moody diagram with 5 relative-roughness curves on log-log axes, and a Sankey balance summing to 100% in and out.

Practice Exercises

  1. On the load-duration curve, read off (approximately) the load exceeded 10% of the year, and the base load (exceeded ~100% of the year).
  2. Change the system curve's static head from 12 m to 20 m and re-plot - which way does the operating point move?
  3. Rebalance the Sankey so process loads are 60%, HVAC 22%, lighting & aux 10%, losses 8% - confirm it still closes to 100%.
# Try the practice exercises here

Knowledge Check

  1. What does a load-duration curve show?
  2. What does the intersection of a pump curve and a system curve represent?
  3. What must the flows into and out of a Sankey diagram sum to?
Answer key
  1. How many hours (or what % of the period) the load is at or above each level, sorted high to low
  2. The operating point - the flow and head at which the pump actually runs on that system
  3. They must balance - total in equals total out (conservation)

37 / 63 sections · Course home · Join the coaching cohort