Summary
This experiment investigates wine tasting panel. Box-Behnken design with 3 tasting panel blocks to optimize wine blending parameters for aroma and balance.
The design varies 3 factors: oak aging (months), ranging from 3 to 18, sugar residual (g/L), ranging from 1 to 8, and sulfite level (mg/L), ranging from 20 to 60. The goal is to optimize 2 responses: aroma score (pts) (maximize) and balance score (pts) (maximize). Fixed conditions held constant across all runs include grape variety = cabernet_sauvignon, vintage = 2024.
A Box-Behnken design was chosen because it efficiently fits quadratic models with 3 continuous factors while avoiding extreme corner combinations — requiring only 45 runs instead of the 8 needed for a full factorial at two levels.
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 aroma score, the most influential factors were oak aging (43.6%), sugar residual (43.0%), sulfite level (13.4%). The best observed value was 8.4 (at oak aging = 10.5, sugar residual = 1, sulfite level = 60).
For balance score, the most influential factors were sugar residual (60.2%), sulfite level (25.0%), oak aging (14.8%). The best observed value was 7.9 (at oak aging = 3, sugar residual = 4.5, sulfite level = 60).
Recommended Next Steps
- Run confirmation experiments at the predicted optimal settings to validate the model.
- Consider whether any fixed factors should be varied in a future study.
Experimental Setup
Factors
| Factor | Low | High | Unit |
oak_aging | 3 | 18 | months |
sugar_residual | 1 | 8 | g/L |
sulfite_level | 20 | 60 | mg/L |
Fixed: grape_variety = cabernet_sauvignon, vintage = 2024
Responses
| Response | Direction | Unit |
aroma_score | ↑ maximize | pts |
balance_score | ↑ maximize | pts |
Configuration
{
"metadata": {
"name": "Wine Tasting Panel",
"description": "Box-Behnken design with 3 tasting panel blocks to optimize wine blending parameters for aroma and balance"
},
"factors": [
{
"name": "oak_aging",
"levels": [
"3",
"18"
],
"type": "continuous",
"unit": "months"
},
{
"name": "sugar_residual",
"levels": [
"1",
"8"
],
"type": "continuous",
"unit": "g/L"
},
{
"name": "sulfite_level",
"levels": [
"20",
"60"
],
"type": "continuous",
"unit": "mg/L"
}
],
"fixed_factors": {
"grape_variety": "cabernet_sauvignon",
"vintage": "2024"
},
"responses": [
{
"name": "aroma_score",
"optimize": "maximize",
"unit": "pts"
},
{
"name": "balance_score",
"optimize": "maximize",
"unit": "pts"
}
],
"settings": {
"operation": "box_behnken",
"test_script": "use_cases/307_wine_tasting_panel/sim.sh"
}
}
Experimental Matrix
The Box-Behnken Design produces 45 runs. Each row is one experiment with specific factor settings.
| Run | Block | oak_aging | sugar_residual | sulfite_level |
| 1 | 1 | 10.5 | 1 | 20 |
| 2 | 1 | 10.5 | 4.5 | 40 |
| 3 | 1 | 18 | 4.5 | 60 |
| 4 | 1 | 18 | 4.5 | 20 |
| 5 | 1 | 10.5 | 4.5 | 40 |
| 6 | 1 | 10.5 | 4.5 | 40 |
| 7 | 1 | 3 | 4.5 | 60 |
| 8 | 1 | 18 | 1 | 40 |
| 9 | 1 | 10.5 | 1 | 60 |
| 10 | 1 | 18 | 8 | 40 |
| 11 | 1 | 3 | 4.5 | 20 |
| 12 | 1 | 10.5 | 8 | 60 |
| 13 | 1 | 3 | 1 | 40 |
| 14 | 1 | 3 | 8 | 40 |
| 15 | 1 | 10.5 | 8 | 20 |
| 16 | 2 | 18 | 1 | 40 |
| 17 | 2 | 10.5 | 4.5 | 40 |
| 18 | 2 | 10.5 | 1 | 60 |
| 19 | 2 | 18 | 4.5 | 60 |
| 20 | 2 | 3 | 4.5 | 20 |
| 21 | 2 | 18 | 4.5 | 20 |
| 22 | 2 | 3 | 4.5 | 60 |
| 23 | 2 | 10.5 | 8 | 20 |
| 24 | 2 | 10.5 | 4.5 | 40 |
| 25 | 2 | 10.5 | 1 | 20 |
| 26 | 2 | 10.5 | 8 | 60 |
| 27 | 2 | 18 | 8 | 40 |
| 28 | 2 | 3 | 8 | 40 |
| 29 | 2 | 10.5 | 4.5 | 40 |
| 30 | 2 | 3 | 1 | 40 |
| 31 | 3 | 18 | 4.5 | 60 |
| 32 | 3 | 10.5 | 1 | 20 |
| 33 | 3 | 18 | 8 | 40 |
| 34 | 3 | 10.5 | 8 | 60 |
| 35 | 3 | 10.5 | 8 | 20 |
| 36 | 3 | 10.5 | 4.5 | 40 |
| 37 | 3 | 3 | 8 | 40 |
| 38 | 3 | 10.5 | 4.5 | 40 |
| 39 | 3 | 3 | 4.5 | 60 |
| 40 | 3 | 18 | 4.5 | 20 |
| 41 | 3 | 18 | 1 | 40 |
| 42 | 3 | 3 | 1 | 40 |
| 43 | 3 | 10.5 | 4.5 | 40 |
| 44 | 3 | 3 | 4.5 | 20 |
| 45 | 3 | 10.5 | 1 | 60 |
Step-by-Step Workflow
1
Preview the design
$ doe info --config use_cases/307_wine_tasting_panel/config.json
2
Generate the runner script
$ doe generate --config use_cases/307_wine_tasting_panel/config.json \
--output use_cases/307_wine_tasting_panel/results/run.sh --seed 42
3
Execute the experiments
$ bash use_cases/307_wine_tasting_panel/results/run.sh
4
Analyze results
$ doe analyze --config use_cases/307_wine_tasting_panel/config.json
5
Get optimization recommendations
$ doe optimize --config use_cases/307_wine_tasting_panel/config.json
6
Multi-objective optimization
With 2 competing responses, use --multi to find the best compromise via Derringer–Suich desirability.
$ doe optimize --config use_cases/307_wine_tasting_panel/config.json --multi
7
Generate the HTML report
$ doe report --config use_cases/307_wine_tasting_panel/config.json \
--output use_cases/307_wine_tasting_panel/results/report.html
Features Exercised
| Feature | Value |
| Design type | box_behnken |
| Factor types | continuous (all 3) |
| Arg style | double-dash |
| Responses | 2 (aroma_score ↑, balance_score ↑) |
| Total runs | 45 |
Analysis Results
Generated from actual experiment runs using the DOE Helper Tool.
Response: aroma_score
Top factors: oak_aging (43.6%), sugar_residual (43.0%), sulfite_level (13.4%).
ANOVA
| Source | DF | SS | MS | F | p-value |
| Source | DF | SS | MS | F | p-value |
| oak_aging | 2 | 1.7678 | 0.8839 | 0.879 | 0.4233 |
| sugar_residual | 2 | 2.5892 | 1.2946 | 1.288 | 0.2876 |
| sulfite_level | 2 | 0.2131 | 0.1066 | 0.106 | 0.8997 |
| Lack | of | Fit | 6 | 14.3064 | 2.3844 |
| Pure | Error | 32 | 32.1667 | | |
| Error | 38 | 46.4731 | 1.0052 | | |
| Total | 44 | 51.0431 | 1.1601 | | |
Response: balance_score
Top factors: sugar_residual (60.2%), sulfite_level (25.0%), oak_aging (14.8%).
ANOVA
| Source | DF | SS | MS | F | p-value |
| Source | DF | SS | MS | F | p-value |
| oak_aging | 2 | 0.0893 | 0.0447 | 0.082 | 0.9214 |
| sugar_residual | 2 | 1.0941 | 0.5470 | 1.005 | 0.3757 |
| sulfite_level | 2 | 0.2632 | 0.1316 | 0.242 | 0.7865 |
| Lack | of | Fit | 6 | 2.2747 | 0.3791 |
| Pure | Error | 32 | 17.4267 | | |
| Error | 38 | 19.7014 | 0.5446 | | |
| Total | 44 | 21.1480 | 0.4806 | | |
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.8432
Per-Response Desirability
| Response | Weight | Desirability | Predicted | Dir |
aroma_score |
1.5 |
|
7.50 0.7448 7.50 pts |
↑ |
balance_score |
1.5 |
|
7.90 0.9545 7.90 pts |
↑ |
Recommended Settings
| Factor | Value |
oak_aging | 10.5 months |
sugar_residual | 1 g/L |
sulfite_level | 60 mg/L |
Source: from observed run #23
Trade-off Summary
Sacrifice = how much worse than single-objective best.
| Response | Predicted | Best Observed | Sacrifice |
balance_score | 7.90 | 7.90 | +0.00 |
Top 3 Runs by Desirability
| Run | D | Factor Settings |
| #4 | 0.8384 | oak_aging=10.5, sugar_residual=8, sulfite_level=60 |
| #35 | 0.8119 | oak_aging=18, sugar_residual=4.5, sulfite_level=20 |
Model Quality
| Response | R² | Type |
balance_score | 0.1898 | quadratic |
Full Multi-Objective Output
============================================================
MULTI-OBJECTIVE OPTIMIZATION
Method: Derringer-Suich Desirability Function
============================================================
Overall desirability: D = 0.8432
Response Weight Desirability Predicted Direction
---------------------------------------------------------------------
aroma_score 1.5 0.7448 7.50 pts ↑
balance_score 1.5 0.9545 7.90 pts ↑
Recommended settings:
oak_aging = 10.5 months
sugar_residual = 1 g/L
sulfite_level = 60 mg/L
(from observed run #23)
Trade-off summary:
aroma_score: 7.50 (best observed: 8.40, sacrifice: +0.90)
balance_score: 7.90 (best observed: 7.90, sacrifice: +0.00)
Model quality:
aroma_score: R² = 0.0318 (linear)
balance_score: R² = 0.1898 (quadratic)
Top 3 observed runs by overall desirability:
1. Run #23 (D=0.8432): oak_aging=10.5, sugar_residual=1, sulfite_level=60
2. Run #4 (D=0.8384): oak_aging=10.5, sugar_residual=8, sulfite_level=60
3. Run #35 (D=0.8119): oak_aging=18, sugar_residual=4.5, sulfite_level=20
Full Analysis Output
=== Main Effects: aroma_score ===
Factor Effect Std Error % Contribution
--------------------------------------------------------------
oak_aging 0.5417 0.1606 43.6%
sugar_residual 0.5345 0.1606 43.0%
sulfite_level 0.1667 0.1606 13.4%
=== ANOVA Table: aroma_score ===
Source DF SS MS F p-value
-----------------------------------------------------------------------------
oak_aging 2 1.7678 0.8839 0.879 0.4233
sugar_residual 2 2.5892 1.2946 1.288 0.2876
sulfite_level 2 0.2131 0.1066 0.106 0.8997
Lack of Fit 6 14.3064 2.3844 2.372 0.0522
Pure Error 32 32.1667 1.0052
Error 38 46.4731 1.0052
Total 44 51.0431 1.1601
=== Summary Statistics: aroma_score ===
oak_aging:
Level N Mean Std Min Max
------------------------------------------------------------
10.5 21 6.4619 1.0581 4.5000 8.4000
18 12 6.2167 0.8664 5.0000 7.7000
3 12 6.7583 1.3014 4.6000 8.4000
sugar_residual:
Level N Mean Std Min Max
------------------------------------------------------------
1 12 6.7583 0.8649 5.2000 8.4000
4.5 21 6.2238 1.1353 4.5000 7.8000
8 12 6.6333 1.1460 5.0000 8.4000
sulfite_level:
Level N Mean Std Min Max
------------------------------------------------------------
20 12 6.4833 1.2540 4.6000 8.4000
40 21 6.5333 1.0365 4.5000 8.4000
60 12 6.3667 1.0465 4.6000 7.7000
=== Main Effects: balance_score ===
Factor Effect Std Error % Contribution
--------------------------------------------------------------
sugar_residual 0.4250 0.1033 60.2%
sulfite_level 0.1762 0.1033 25.0%
oak_aging 0.1048 0.1033 14.8%
=== ANOVA Table: balance_score ===
Source DF SS MS F p-value
-----------------------------------------------------------------------------
oak_aging 2 0.0893 0.0447 0.082 0.9214
sugar_residual 2 1.0941 0.5470 1.005 0.3757
sulfite_level 2 0.2632 0.1316 0.242 0.7865
Lack of Fit 6 2.2747 0.3791 0.696 0.6545
Pure Error 32 17.4267 0.5446
Error 38 19.7014 0.5446
Total 44 21.1480 0.4806
=== Summary Statistics: balance_score ===
oak_aging:
Level N Mean Std Min Max
------------------------------------------------------------
10.5 21 6.6714 0.7142 5.4000 7.7000
18 12 6.5667 0.5742 5.6000 7.7000
3 12 6.6583 0.8107 5.4000 7.9000
sugar_residual:
Level N Mean Std Min Max
------------------------------------------------------------
1 12 6.8667 0.6272 6.0000 7.7000
4.5 21 6.6238 0.8130 5.4000 7.9000
8 12 6.4417 0.4776 5.6000 7.2000
sulfite_level:
Level N Mean Std Min Max
------------------------------------------------------------
20 12 6.6000 0.7663 5.4000 7.5000
40 21 6.5905 0.7224 5.4000 7.7000
60 12 6.7667 0.6020 5.8000 7.9000
Optimization Recommendations
=== Optimization: aroma_score ===
Direction: maximize
Best observed run: #4
oak_aging = 10.5
sugar_residual = 1
sulfite_level = 60
Value: 8.4
RSM Model (linear, R² = 0.0642, Adj R² = -0.0043):
Coefficients:
intercept +6.4756
oak_aging +0.1083
sugar_residual -0.1042
sulfite_level +0.3375
RSM Model (quadratic, R² = 0.2719, Adj R² = 0.0847):
Coefficients:
intercept +6.4111
oak_aging +0.1083
sugar_residual -0.1042
sulfite_level +0.3375
oak_aging*sugar_residual +0.0333
oak_aging*sulfite_level -0.2167
sugar_residual*sulfite_level +0.2250
oak_aging^2 -0.0764
sugar_residual^2 +0.7153
sulfite_level^2 -0.5181
Curvature analysis:
sugar_residual coef=+0.7153 convex (has a minimum)
sulfite_level coef=-0.5181 concave (has a maximum)
oak_aging coef=-0.0764 negligible curvature
Predicted optimum (from quadratic model, at observed points):
oak_aging = 18
sugar_residual = 1
sulfite_level = 40
Predicted value: 7.2292
Surface optimum (via L-BFGS-B, quadratic model):
oak_aging = 14.0923
sugar_residual = 1
sulfite_level = 40.1684
Predicted value: 7.2490
Model quality: Weak fit — consider adding center points or using a different design.
Factor importance:
1. sulfite_level (effect: 0.9, contribution: 45.5%)
2. sugar_residual (effect: 0.9, contribution: 43.5%)
3. oak_aging (effect: 0.2, contribution: 10.9%)
=== Optimization: balance_score ===
Direction: maximize
Best observed run: #23
oak_aging = 3
sugar_residual = 4.5
sulfite_level = 60
Value: 7.9
RSM Model (linear, R² = 0.0762, Adj R² = 0.0086):
Coefficients:
intercept +6.6400
oak_aging +0.1500
sugar_residual +0.0542
sulfite_level +0.2042
RSM Model (quadratic, R² = 0.1741, Adj R² = -0.0383):
Coefficients:
intercept +6.6778
oak_aging +0.1500
sugar_residual +0.0542
sulfite_level +0.2042
oak_aging*sugar_residual -0.0833
oak_aging*sulfite_level -0.1667
sugar_residual*sulfite_level +0.2417
oak_aging^2 +0.0319
sugar_residual^2 +0.1403
sulfite_level^2 -0.2431
Curvature analysis:
sulfite_level coef=-0.2431 concave (has a maximum)
sugar_residual coef=+0.1403 convex (has a minimum)
oak_aging coef=+0.0319 negligible curvature
Predicted optimum (from linear model, at observed points):
oak_aging = 18
sugar_residual = 4.5
sulfite_level = 60
Predicted value: 6.9942
Surface optimum (via L-BFGS-B, linear model):
oak_aging = 18
sugar_residual = 8
sulfite_level = 60
Predicted value: 7.0483
Model quality: Weak fit — consider adding center points or using a different design.
Factor importance:
1. sulfite_level (effect: 0.5, contribution: 47.4%)
2. oak_aging (effect: 0.3, contribution: 31.0%)
3. sugar_residual (effect: 0.2, contribution: 21.6%)