← All Use Cases
🍳
Central Composite Design

Coffee Brewing Extraction

Central composite design to maximize flavor score and minimize bitterness by tuning grind size, water temperature, brew time, and coffee-to-water ratio

Summary

This experiment investigates coffee brewing extraction. Central composite design to maximize flavor score and minimize bitterness by tuning grind size, water temperature, brew time, and coffee-to-water ratio.

The design varies 4 factors: grind size (um), ranging from 200 to 800, water temp (C), ranging from 85 to 96, brew time (sec), ranging from 180 to 300, and ratio (g/g), ranging from 14 to 18. The goal is to optimize 2 responses: flavor score (pts) (maximize) and bitterness (pts) (minimize). Fixed conditions held constant across all runs include roast level = medium, water tds = 120.

A Central Composite Design (CCD) was selected to fit a full quadratic response surface model, including curvature and interaction effects. With 4 factors this produces 32 runs including center points and axial (star) points that extend beyond the factorial range.

Quadratic response surface models were fitted to capture potential curvature and factor interactions. The RSM contour plots below visualize how pairs of factors jointly affect each response.

Key Findings

For flavor score, the most influential factors were water temp (39.7%), grind size (29.9%), brew time (21.6%). The best observed value was 81.2 (at grind size = 500, water temp = 90.5, brew time = 240).

For bitterness, the most influential factors were brew time (34.5%), grind size (27.7%), water temp (21.4%). The best observed value was 1.7 (at grind size = 500, water temp = 90.5, brew time = 240).

Recommended Next Steps

Experimental Setup

Factors

FactorLowHighUnit
grind_size200800um
water_temp8596C
brew_time180300sec
ratio1418g/g

Fixed: roast_level = medium, water_tds = 120

Responses

ResponseDirectionUnit
flavor_score↑ maximizepts
bitterness↓ minimizepts

Configuration

use_cases/88_coffee_brewing/config.json
{ "metadata": { "name": "Coffee Brewing Extraction", "description": "Central composite design to maximize flavor score and minimize bitterness by tuning grind size, water temperature, brew time, and coffee-to-water ratio" }, "factors": [ { "name": "grind_size", "levels": [ "200", "800" ], "type": "continuous", "unit": "um" }, { "name": "water_temp", "levels": [ "85", "96" ], "type": "continuous", "unit": "C" }, { "name": "brew_time", "levels": [ "180", "300" ], "type": "continuous", "unit": "sec" }, { "name": "ratio", "levels": [ "14", "18" ], "type": "continuous", "unit": "g/g" } ], "fixed_factors": { "roast_level": "medium", "water_tds": "120" }, "responses": [ { "name": "flavor_score", "optimize": "maximize", "unit": "pts" }, { "name": "bitterness", "optimize": "minimize", "unit": "pts" } ], "settings": { "operation": "central_composite", "test_script": "use_cases/88_coffee_brewing/sim.sh" } }

Experimental Matrix

The Central Composite Design produces 32 runs. Each row is one experiment with specific factor settings.

Rungrind_sizewater_tempbrew_timeratio
150090.524011.6182
22009618018
38008530014
48009630018
550090.5371.45316
68008530018
750078.450124016
82009630014
950090.524016
108009618014
1150090.524016
128008518018
1350090.524016
148009630014
1550090.5108.54716
16-157.26790.524016
1750090.524016
182008518018
198009618018
2050090.524016
212008530014
2250090.524016
231157.2790.524016
242008530018
2550090.524016
262009618014
2750090.524020.3818
2850090.524016
298008518014
30500102.5524016
312008518014
322009630018

Step-by-Step Workflow

1

Preview the design

Terminal
$ doe info --config use_cases/88_coffee_brewing/config.json
2

Generate the runner script

Terminal
$ doe generate --config use_cases/88_coffee_brewing/config.json \ --output use_cases/88_coffee_brewing/results/run.sh --seed 42
3

Execute the experiments

Terminal
$ bash use_cases/88_coffee_brewing/results/run.sh
4

Analyze results

Terminal
$ doe analyze --config use_cases/88_coffee_brewing/config.json
5

Get optimization recommendations

Terminal
$ doe optimize --config use_cases/88_coffee_brewing/config.json
6

Multi-objective optimization

With 2 competing responses, use --multi to find the best compromise via Derringer–Suich desirability.

Terminal
$ doe optimize --config use_cases/88_coffee_brewing/config.json --multi
7

Generate the HTML report

Terminal
$ doe report --config use_cases/88_coffee_brewing/config.json \ --output use_cases/88_coffee_brewing/results/report.html

Features Exercised

FeatureValue
Design typecentral_composite
Factor typescontinuous (all 4)
Arg styledouble-dash
Responses2 (flavor_score ↑, bitterness ↓)
Total runs32

Analysis Results

Generated from actual experiment runs using the DOE Helper Tool.

Response: flavor_score

Top factors: water_temp (39.7%), grind_size (29.9%), brew_time (21.6%).

ANOVA

SourceDFSSMSFp-value
SourceDFSSMSFp-value
grind_size4134.622733.65570.6130.6598
water_temp4135.761333.94030.6180.6564
brew_time4154.339138.58480.7030.6021
ratio441.026310.25660.1870.9416
LackofFit8549.925768.7407
PureError7384.3200
Error15934.245754.9029
Total311399.995045.1611

Pareto Chart

Pareto chart for flavor_score

Main Effects Plot

Main effects plot for flavor_score

Normal Probability Plot of Effects

Normal probability plot for flavor_score

Half-Normal Plot of Effects

Half-normal plot for flavor_score

Model Diagnostics

Model diagnostics for flavor_score

Response: bitterness

Top factors: brew_time (34.5%), grind_size (27.7%), water_temp (21.4%).

ANOVA

SourceDFSSMSFp-value
SourceDFSSMSFp-value
grind_size424.17126.04281.0870.3979
water_temp428.14527.03631.2660.3264
brew_time429.83417.45851.3420.3001
ratio417.97164.49290.8090.5388
LackofFit80.00000.0000
PureError738.8987
Error1531.70665.5570
Total31131.82874.2525

Pareto Chart

Pareto chart for bitterness

Main Effects Plot

Main effects plot for bitterness

Normal Probability Plot of Effects

Normal probability plot for bitterness

Half-Normal Plot of Effects

Half-normal plot for bitterness

Model Diagnostics

Model diagnostics for bitterness

Response Surface Plots

3D surfaces fitted with quadratic RSM. Red dots are observed data points.

bitterness brew time vs ratio

RSM surface: bitterness brew time vs ratio

bitterness grind size vs brew time

RSM surface: bitterness grind size vs brew time

bitterness grind size vs ratio

RSM surface: bitterness grind size vs ratio

bitterness grind size vs water temp

RSM surface: bitterness grind size vs water temp

bitterness water temp vs brew time

RSM surface: bitterness water temp vs brew time

bitterness water temp vs ratio

RSM surface: bitterness water temp vs ratio

flavor score brew time vs ratio

RSM surface: flavor score brew time vs ratio

flavor score grind size vs brew time

RSM surface: flavor score grind size vs brew time

flavor score grind size vs ratio

RSM surface: flavor score grind size vs ratio

flavor score grind size vs water temp

RSM surface: flavor score grind size vs water temp

flavor score water temp vs brew time

RSM surface: flavor score water temp vs brew time

flavor score water temp vs ratio

RSM surface: flavor score water temp vs ratio

Multi-Objective Optimization

When responses compete, Derringer–Suich desirability finds the best compromise. Each response is scaled to a 0–1 desirability, then combined via a weighted geometric mean.

Overall Desirability
D = 0.8876

Per-Response Desirability

ResponseWeightDesirabilityPredictedDir
flavor_score 1.5
0.9263
80.50 0.9263 80.50 pts
bitterness 1.0
0.8326
2.80 0.8326 2.80 pts

Recommended Settings

FactorValue
grind_size500 um
water_temp90.5 C
brew_time240 sec
ratio16 g/g

Source: from observed run #6

Trade-off Summary

Sacrifice = how much worse than single-objective best.

ResponsePredictedBest ObservedSacrifice
bitterness2.801.70+1.10

Top 3 Runs by Desirability

RunDFactor Settings
#30.8149grind_size=200, water_temp=96, brew_time=300, ratio=18
#130.7662grind_size=800, water_temp=85, brew_time=180, ratio=14

Model Quality

ResponseType
bitterness0.1331linear

Full Multi-Objective Output

doe optimize --multi
============================================================ MULTI-OBJECTIVE OPTIMIZATION Method: Derringer-Suich Desirability Function ============================================================ Overall desirability: D = 0.8876 Response Weight Desirability Predicted Direction --------------------------------------------------------------------- flavor_score 1.5 0.9263 80.50 pts ↑ bitterness 1.0 0.8326 2.80 pts ↓ Recommended settings: grind_size = 500 um water_temp = 90.5 C brew_time = 240 sec ratio = 16 g/g (from observed run #6) Trade-off summary: flavor_score: 80.50 (best observed: 81.20, sacrifice: +0.70) bitterness: 2.80 (best observed: 1.70, sacrifice: +1.10) Model quality: flavor_score: R² = 0.1923 (linear) bitterness: R² = 0.1331 (linear) Top 3 observed runs by overall desirability: 1. Run #6 (D=0.8876): grind_size=500, water_temp=90.5, brew_time=240, ratio=16 2. Run #3 (D=0.8149): grind_size=200, water_temp=96, brew_time=300, ratio=18 3. Run #13 (D=0.7662): grind_size=800, water_temp=85, brew_time=180, ratio=14

Full Analysis Output

doe analyze
=== Main Effects: flavor_score === Factor Effect Std Error % Contribution -------------------------------------------------------------- water_temp 12.2000 1.1880 39.7% grind_size 9.1786 1.1880 29.9% brew_time 6.6250 1.1880 21.6% ratio 2.7000 1.1880 8.8% === ANOVA Table: flavor_score === Source DF SS MS F p-value ----------------------------------------------------------------------------- grind_size 4 134.6227 33.6557 0.613 0.6598 water_temp 4 135.7613 33.9403 0.618 0.6564 brew_time 4 154.3391 38.5848 0.703 0.6021 ratio 4 41.0263 10.2566 0.187 0.9416 Lack of Fit 8 549.9257 68.7407 1.252 0.3899 Pure Error 7 384.3200 54.9029 Error 15 934.2457 54.9029 Total 31 1399.9950 45.1611 === Summary Statistics: flavor_score === grind_size: Level N Mean Std Min Max ------------------------------------------------------------ -157.267 1 79.4000 0.0000 79.4000 79.4000 1157.27 1 76.2000 0.0000 76.2000 76.2000 200 8 71.9125 8.5359 58.7000 81.2000 500 14 70.2214 6.0354 59.9000 78.1000 800 8 73.5000 6.3449 65.6000 80.9000 water_temp: Level N Mean Std Min Max ------------------------------------------------------------ 102.55 1 63.8000 0.0000 63.8000 63.8000 78.4501 1 76.0000 0.0000 76.0000 76.0000 85 8 74.2625 7.5104 60.1000 80.9000 90.5 14 71.3500 6.2084 59.9000 79.4000 96 8 71.1500 7.2538 58.7000 81.2000 brew_time: Level N Mean Std Min Max ------------------------------------------------------------ 108.547 1 68.9000 0.0000 68.9000 68.9000 180 8 69.8875 7.6665 58.7000 80.9000 240 14 71.4357 6.6267 59.9000 79.4000 300 8 75.5250 6.1337 65.6000 81.2000 371.453 1 69.7000 0.0000 69.7000 69.7000 ratio: Level N Mean Std Min Max ------------------------------------------------------------ 11.6182 1 73.6000 0.0000 73.6000 73.6000 14 8 71.7125 8.7924 58.7000 80.5000 16 14 71.0000 6.6382 59.9000 79.4000 18 8 73.7000 5.9156 65.6000 81.2000 20.3818 1 71.1000 0.0000 71.1000 71.1000 === Main Effects: bitterness === Factor Effect Std Error % Contribution -------------------------------------------------------------- brew_time 4.9625 0.3645 34.5% grind_size 3.9875 0.3645 27.7% water_temp 3.0786 0.3645 21.4% ratio 2.3500 0.3645 16.3% === ANOVA Table: bitterness === Source DF SS MS F p-value ----------------------------------------------------------------------------- grind_size 4 24.1712 6.0428 1.087 0.3979 water_temp 4 28.1452 7.0363 1.266 0.3264 brew_time 4 29.8341 7.4585 1.342 0.3001 ratio 4 17.9716 4.4929 0.809 0.5388 Lack of Fit 8 0.0000 0.0000 0.000 1.0000 Pure Error 7 38.8987 5.5570 Error 15 31.7066 5.5570 Total 31 131.8287 4.2525 === Summary Statistics: bitterness === grind_size: Level N Mean Std Min Max ------------------------------------------------------------ -157.267 1 5.3000 0.0000 5.3000 5.3000 1157.27 1 8.9000 0.0000 8.9000 8.9000 200 8 5.1875 2.1886 1.7000 8.2000 500 14 6.4000 2.1426 3.7000 9.9000 800 8 4.9125 1.4367 2.8000 7.1000 water_temp: Level N Mean Std Min Max ------------------------------------------------------------ 102.55 1 5.2000 0.0000 5.2000 5.2000 78.4501 1 3.7000 0.0000 3.7000 3.7000 85 8 5.3000 1.0392 4.4000 7.5000 90.5 14 6.7786 2.0830 4.2000 9.9000 96 8 4.8000 2.3821 1.7000 8.2000 brew_time: Level N Mean Std Min Max ------------------------------------------------------------ 108.547 1 5.8000 0.0000 5.8000 5.8000 180 8 5.4625 1.9537 2.9000 8.2000 240 14 6.3143 2.0836 3.7000 9.9000 300 8 4.6375 1.6405 1.7000 6.3000 371.453 1 9.6000 0.0000 9.6000 9.6000 ratio: Level N Mean Std Min Max ------------------------------------------------------------ 11.6182 1 5.7000 0.0000 5.7000 5.7000 14 8 4.9500 2.0928 1.7000 8.2000 16 14 6.4857 2.2487 3.7000 9.9000 18 8 5.1500 1.5793 2.9000 7.5000 20.3818 1 7.3000 0.0000 7.3000 7.3000

Optimization Recommendations

doe optimize
=== Optimization: flavor_score === Direction: maximize Best observed run: #4 grind_size = 500 water_temp = 90.5 brew_time = 240 ratio = 16 Value: 81.2 RSM Model (linear, R² = 0.2531, Adj R² = 0.1424): Coefficients: intercept +71.9375 grind_size -0.5837 water_temp +1.4921 brew_time +2.3257 ratio -2.4214 RSM Model (quadratic, R² = 0.4311, Adj R² = -0.0374): Coefficients: intercept +74.3352 grind_size -0.5837 water_temp +1.4922 brew_time +2.3257 ratio -2.4214 grind_size*water_temp +0.5188 grind_size*brew_time +1.4563 grind_size*ratio +1.1437 water_temp*brew_time -0.0187 water_temp*ratio -0.3813 brew_time*ratio -0.1188 grind_size^2 -0.4238 water_temp^2 -1.9758 brew_time^2 -0.8821 ratio^2 +0.2846 Curvature analysis: water_temp coef=-1.9758 concave (has a maximum) brew_time coef=-0.8821 concave (has a maximum) grind_size coef=-0.4238 concave (has a maximum) ratio coef=+0.2846 convex (has a minimum) Notable interactions: grind_size*brew_time coef=+1.4563 (synergistic) grind_size*ratio coef=+1.1437 (synergistic) grind_size*water_temp coef=+0.5188 (synergistic) water_temp*ratio coef=-0.3813 (antagonistic) Predicted optimum (from linear model, at observed points): grind_size = 200 water_temp = 96 brew_time = 300 ratio = 14 Predicted value: 78.7604 Surface optimum (via L-BFGS-B, linear model): grind_size = 200 water_temp = 96 brew_time = 300 ratio = 14 Predicted value: 78.7604 Model quality: Weak fit — consider adding center points or using a different design. Factor importance: 1. brew_time (effect: 22.2, contribution: 38.7%) 2. water_temp (effect: 13.4, contribution: 23.3%) 3. grind_size (effect: 12.8, contribution: 22.3%) 4. ratio (effect: 9.1, contribution: 15.8%) === Optimization: bitterness === Direction: minimize Best observed run: #23 grind_size = 500 water_temp = 90.5 brew_time = 240 ratio = 16 Value: 1.7 RSM Model (linear, R² = 0.0754, Adj R² = -0.0615): Coefficients: intercept +5.7687 grind_size +0.2846 water_temp +0.2567 brew_time -0.2471 ratio +0.4249 RSM Model (quadratic, R² = 0.5010, Adj R² = 0.0900): Coefficients: intercept +5.4960 grind_size +0.2846 water_temp +0.2567 brew_time -0.2471 ratio +0.4249 grind_size*water_temp -0.5375 grind_size*brew_time +0.1125 grind_size*ratio -1.1625 water_temp*brew_time -0.8625 water_temp*ratio +0.7125 brew_time*ratio -0.6375 grind_size^2 +0.0566 water_temp^2 -0.0580 brew_time^2 +0.2545 ratio^2 +0.0878 Curvature analysis: brew_time coef=+0.2545 convex (has a minimum) ratio coef=+0.0878 negligible curvature water_temp coef=-0.0580 negligible curvature grind_size coef=+0.0566 negligible curvature Notable interactions: grind_size*ratio coef=-1.1625 (antagonistic) water_temp*brew_time coef=-0.8625 (antagonistic) water_temp*ratio coef=+0.7125 (synergistic) brew_time*ratio coef=-0.6375 (antagonistic) grind_size*water_temp coef=-0.5375 (antagonistic) Predicted optimum (from quadratic model, at observed points): grind_size = 200 water_temp = 96 brew_time = 180 ratio = 18 Predicted value: 10.5059 Surface optimum (via L-BFGS-B, quadratic model): grind_size = 200 water_temp = 85 brew_time = 180 ratio = 14 Predicted value: 2.7429 Model quality: Moderate fit — use predictions directionally, not precisely. Factor importance: 1. brew_time (effect: 3.8, contribution: 40.4%) 2. water_temp (effect: 2.5, contribution: 26.2%) 3. grind_size (effect: 1.7, contribution: 18.5%) 4. ratio (effect: 1.4, contribution: 15.0%)
← Previous: Bread Baking Optimization Next: Pizza Dough Formulation →