Index of State Variables & Constants
- $T$: Water Temp (K)
- $d_p$: Grind Size ($m$)
- $\Delta P$: Pressure Drop ($Pa$)
- $A$: Puck Area ($m^2$)
- $L$: Puck Depth ($m$)
- $\rho_{solid}$: Coffee Density ($1200\ kg/m^3$)
- $\rho$: Water Density ($1000\ kg/m^3$)
- $Y$: Young's Modulus ($5 \times 10^6\ Pa$)
- $\Phi$: Initial Porosity ($0.45$)
- $k_m$: Max Yield ($0.22 \times M_{puck}$)
- $\ell_m$: Peak Extraction Delay ($10\ s$)
- $m_m$: Dissolution Spread ($4\ s$)
Sigmoidal Mass Dissolution
Mass physically erodes from the puck forming a "J-Curve" over time. Fines extract rapidly at first,
tapering off as the grounds are fully depleted:
$$ m_d(t) = \frac{k_m}{2} \left[ 1 + \tanh\left(\frac{t - 10}{4}\right) \right]
$$
Dynamic Porosity Expansion
As solid mass leaves the portafilter into your cup, the internal void fraction ($\epsilon$)
dynamically opens up mid-shot, accelerating flow:
$$ \epsilon = \left( \Phi - \frac{\Delta P}{Y} \right) +
\frac{m_d(t)}{\rho_{solid} V_{bed}} $$
Variable Viscosity Feedback
The local concentration of solids ($C_{TDS}$) spikes when dissolution rates are highest. This causes
a massive early-shot viscosity drag, resulting in a thick, syrupy start:
$$ \mu_t = \mu_{water} \times \left[ 1 + 0.02 \left( \frac{\frac{d
m_d}{dt}}{Q_{t-1}} \right) \right] $$
Permeability & Calibrated Shape Factor
Permeability ($k$) establishes how readily fluid permeates the medium. A discrete scalar correction
($5 \times 10^{-5}$) scales the standard theoretical geometry to match real-world, irregular coffee
extraction flows:
$$ k = \left[ \left( \frac{d_p^2}{150} \right) \left( \frac{\epsilon^3}{(\Phi -
1)^2 (1 - \epsilon_{strain})} \right) \right] \times 5 \times 10^{-5} $$
Darcy-Forchheimer Solutions
At every timestep, the instantaneous fluid velocity ($v$) is localized by deriving the roots of this
robust quadratic formulation:
$$ (\beta \rho) v^2 + \left( \frac{\mu_t}{k} \right) v - \frac{\Delta P}{L} = 0
$$
Reverse Grind Estimation
A binary search isolates the optimal grind diameter ($d_p^*$) for a Target Flow ($Q_{target}$). Let
$f(d_p)$ represent the simulation's average flow. Because $f(d_p)$ is monotonically increasing
(coarser = faster flow), we solve $f(d_p^*) \approx Q_{target}$ iteratively:
Bounds & Constraints: $d_{min} = 50 \mu m$, $d_{max} = 1500 \mu m$, Tolerance: $\pm
0.05$ ml/s.
Execution Flow: For each iteration (up to 25):
$$ d_{mid} = \frac{d_{min} + d_{max}}{2} $$
$$ Q_{sim} = f(d_{mid}) $$
• If $|Q_{sim} - Q_{target}| \le 0.05$,
Return $d_{mid}$
• If $Q_{sim} < Q_{target}$ (Too slow):
$d_{min}=d_{mid}$
• If $Q_{sim} > Q_{target}$ (Too fast):
$d_{max} = d_{mid}$
Example ($Q_{target} = 2.0$ ml/s): Iter 1 tests $775\mu m
\rightarrow 6.4$ ml/s (Too fast, $d_{max} = 775$). Iter 2 tests $412.5\mu m \rightarrow 2.1$
ml/s (Too fast, $d_{max} = 412.5$). Bounds rapidly converge to $\approx 401\mu m$.