Summary
This experiment investigates tropical fish tank health. Box-Behnken design to maximize fish vitality and minimize algae by tuning water change frequency, feeding amount, and light duration.
The design varies 3 factors: water change pct (%/week), ranging from 10 to 40, feed g day (g/day), ranging from 0.5 to 3.0, and light hrs (hrs), ranging from 6 to 12. The goal is to optimize 2 responses: vitality score (pts) (maximize) and algae level (pts) (minimize). Fixed conditions held constant across all runs include tank L = 200, fish count = 20.
A Box-Behnken design was chosen because it efficiently fits quadratic models with 3 continuous factors while avoiding extreme corner combinations — requiring only 15 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 vitality score, the most influential factors were feed g day (56.7%), water change pct (34.3%), light hrs (9.0%). The best observed value was 7.8 (at water change pct = 40, feed g day = 3, light hrs = 9).
For algae level, the most influential factors were feed g day (67.5%), water change pct (17.9%), light hrs (14.6%). The best observed value was 2.1 (at water change pct = 40, feed g day = 1.75, light hrs = 6).
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 |
water_change_pct | 10 | 40 | %/week |
feed_g_day | 0.5 | 3.0 | g/day |
light_hrs | 6 | 12 | hrs |
Fixed: tank_L = 200, fish_count = 20
Responses
| Response | Direction | Unit |
vitality_score | ↑ maximize | pts |
algae_level | ↓ minimize | pts |
Configuration
{
"metadata": {
"name": "Tropical Fish Tank Health",
"description": "Box-Behnken design to maximize fish vitality and minimize algae by tuning water change frequency, feeding amount, and light duration"
},
"factors": [
{
"name": "water_change_pct",
"levels": [
"10",
"40"
],
"type": "continuous",
"unit": "%/week"
},
{
"name": "feed_g_day",
"levels": [
"0.5",
"3.0"
],
"type": "continuous",
"unit": "g/day"
},
{
"name": "light_hrs",
"levels": [
"6",
"12"
],
"type": "continuous",
"unit": "hrs"
}
],
"fixed_factors": {
"tank_L": "200",
"fish_count": "20"
},
"responses": [
{
"name": "vitality_score",
"optimize": "maximize",
"unit": "pts"
},
{
"name": "algae_level",
"optimize": "minimize",
"unit": "pts"
}
],
"settings": {
"operation": "box_behnken",
"test_script": "use_cases/170_fish_tank_health/sim.sh"
}
}
Experimental Matrix
The Box-Behnken Design produces 15 runs. Each row is one experiment with specific factor settings.
| Run | water_change_pct | feed_g_day | light_hrs |
| 1 | 25 | 0.5 | 6 |
| 2 | 25 | 1.75 | 9 |
| 3 | 40 | 1.75 | 12 |
| 4 | 40 | 1.75 | 6 |
| 5 | 25 | 1.75 | 9 |
| 6 | 25 | 1.75 | 9 |
| 7 | 10 | 1.75 | 12 |
| 8 | 40 | 0.5 | 9 |
| 9 | 25 | 0.5 | 12 |
| 10 | 40 | 3 | 9 |
| 11 | 10 | 1.75 | 6 |
| 12 | 25 | 3 | 12 |
| 13 | 10 | 0.5 | 9 |
| 14 | 10 | 3 | 9 |
| 15 | 25 | 3 | 6 |
Step-by-Step Workflow
1
Preview the design
$ doe info --config use_cases/170_fish_tank_health/config.json
2
Generate the runner script
$ doe generate --config use_cases/170_fish_tank_health/config.json \
--output use_cases/170_fish_tank_health/results/run.sh --seed 42
3
Execute the experiments
$ bash use_cases/170_fish_tank_health/results/run.sh
4
Analyze results
$ doe analyze --config use_cases/170_fish_tank_health/config.json
5
Get optimization recommendations
$ doe optimize --config use_cases/170_fish_tank_health/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/170_fish_tank_health/config.json --multi
7
Generate the HTML report
$ doe report --config use_cases/170_fish_tank_health/config.json \
--output use_cases/170_fish_tank_health/results/report.html
Features Exercised
| Feature | Value |
| Design type | box_behnken |
| Factor types | continuous (all 3) |
| Arg style | double-dash |
| Responses | 2 (vitality_score ↑, algae_level ↓) |
| Total runs | 15 |
Analysis Results
Generated from actual experiment runs using the DOE Helper Tool.
Response: vitality_score
Top factors: feed_g_day (56.7%), water_change_pct (34.3%), light_hrs (9.0%).
ANOVA
| Source | DF | SS | MS | F | p-value |
| Source | DF | SS | MS | F | p-value |
| water_change_pct | 2 | 0.8430 | 0.4215 | 6.022 | 0.0254 |
| feed_g_day | 2 | 2.3802 | 1.1901 | 17.001 | 0.0013 |
| light_hrs | 2 | 0.0530 | 0.0265 | 0.379 | 0.6963 |
| Lack | of | Fit | 6 | 7.1010 | 1.1835 |
| Pure | Error | 2 | 0.1400 | | |
| Error | 8 | 7.2410 | 0.0700 | | |
| Total | 14 | 10.5173 | 0.7512 | | |
Pareto Chart
Main Effects Plot
Normal Probability Plot of Effects
Half-Normal Plot of Effects
Model Diagnostics
Response: algae_level
Top factors: feed_g_day (67.5%), water_change_pct (17.9%), light_hrs (14.6%).
ANOVA
| Source | DF | SS | MS | F | p-value |
| Source | DF | SS | MS | F | p-value |
| water_change_pct | 2 | 1.0762 | 0.5381 | 7.687 | 0.0137 |
| feed_g_day | 2 | 13.3473 | 6.6736 | 95.338 | 0.0000 |
| light_hrs | 2 | 0.7087 | 0.3543 | 5.062 | 0.0380 |
| Lack | of | Fit | 6 | 11.3012 | 1.8835 |
| Pure | Error | 2 | 0.1400 | | |
| Error | 8 | 11.4412 | 0.0700 | | |
| Total | 14 | 26.5733 | 1.8981 | | |
Pareto Chart
Main Effects Plot
Normal Probability Plot of Effects
Half-Normal Plot of Effects
Model Diagnostics
Response Surface Plots
3D surfaces fitted with quadratic RSM. Red dots are observed data points.
algae level feed g day vs light hrs
algae level water change pct vs feed g day
algae level water change pct vs light hrs
vitality score feed g day vs light hrs
vitality score water change pct vs feed g day
vitality score water change pct vs light hrs
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.8196
Per-Response Desirability
| Response | Weight | Desirability | Predicted | Dir |
vitality_score |
1.5 |
|
7.00 0.7038 7.00 pts |
↑ |
algae_level |
1.5 |
|
2.10 0.9545 2.10 pts |
↓ |
Recommended Settings
| Factor | Value |
water_change_pct | 40 %/week |
feed_g_day | 0.5 g/day |
light_hrs | 9 hrs |
Source: from observed run #4
Trade-off Summary
Sacrifice = how much worse than single-objective best.
| Response | Predicted | Best Observed | Sacrifice |
algae_level | 2.10 | 2.10 | +0.00 |
Top 3 Runs by Desirability
| Run | D | Factor Settings |
| #5 | 0.7067 | water_change_pct=40, feed_g_day=1.75, light_hrs=12 |
| #10 | 0.6908 | water_change_pct=25, feed_g_day=1.75, light_hrs=9 |
Model Quality
| Response | R² | Type |
algae_level | 0.0486 | linear |
Full Multi-Objective Output
============================================================
MULTI-OBJECTIVE OPTIMIZATION
Method: Derringer-Suich Desirability Function
============================================================
Overall desirability: D = 0.8196
Response Weight Desirability Predicted Direction
---------------------------------------------------------------------
vitality_score 1.5 0.7038 7.00 pts ↑
algae_level 1.5 0.9545 2.10 pts ↓
Recommended settings:
water_change_pct = 40 %/week
feed_g_day = 0.5 g/day
light_hrs = 9 hrs
(from observed run #4)
Trade-off summary:
vitality_score: 7.00 (best observed: 7.80, sacrifice: +0.80)
algae_level: 2.10 (best observed: 2.10, sacrifice: +0.00)
Model quality:
vitality_score: R² = 0.8888 (quadratic)
algae_level: R² = 0.0486 (linear)
Top 3 observed runs by overall desirability:
1. Run #4 (D=0.8196): water_change_pct=40, feed_g_day=0.5, light_hrs=9
2. Run #5 (D=0.7067): water_change_pct=40, feed_g_day=1.75, light_hrs=12
3. Run #10 (D=0.6908): water_change_pct=25, feed_g_day=1.75, light_hrs=9
Full Analysis Output
=== Main Effects: vitality_score ===
Factor Effect Std Error % Contribution
--------------------------------------------------------------
feed_g_day 0.9429 0.2238 56.7%
water_change_pct 0.5714 0.2238 34.3%
light_hrs 0.1500 0.2238 9.0%
=== ANOVA Table: vitality_score ===
Source DF SS MS F p-value
-----------------------------------------------------------------------------
water_change_pct 2 0.8430 0.4215 6.022 0.0254
feed_g_day 2 2.3802 1.1901 17.001 0.0013
light_hrs 2 0.0530 0.0265 0.379 0.6963
Lack of Fit 6 7.1010 1.1835 16.907 0.0569
Pure Error 2 0.1400 0.0700
Error 8 7.2410 0.0700
Total 14 10.5173 0.7512
=== Summary Statistics: vitality_score ===
water_change_pct:
Level N Mean Std Min Max
------------------------------------------------------------
10 4 6.6000 0.4899 6.0000 7.0000
25 7 6.8714 0.8883 5.5000 7.7000
40 4 6.3000 1.1860 4.9000 7.8000
feed_g_day:
Level N Mean Std Min Max
------------------------------------------------------------
0.5 4 6.5000 1.1633 4.9000 7.5000
1.75 7 7.0429 0.6754 6.0000 7.8000
3 4 6.1000 0.6683 5.5000 7.0000
light_hrs:
Level N Mean Std Min Max
------------------------------------------------------------
12 4 6.7000 1.1225 5.5000 7.8000
6 4 6.5500 0.6856 5.7000 7.2000
9 7 6.6714 0.9376 4.9000 7.7000
=== Main Effects: algae_level ===
Factor Effect Std Error % Contribution
--------------------------------------------------------------
feed_g_day 2.4250 0.3557 67.5%
water_change_pct 0.6429 0.3557 17.9%
light_hrs 0.5250 0.3557 14.6%
=== ANOVA Table: algae_level ===
Source DF SS MS F p-value
-----------------------------------------------------------------------------
water_change_pct 2 1.0762 0.5381 7.687 0.0137
feed_g_day 2 13.3473 6.6736 95.338 0.0000
light_hrs 2 0.7087 0.3543 5.062 0.0380
Lack of Fit 6 11.3012 1.8835 26.908 0.0363
Pure Error 2 0.1400 0.0700
Error 8 11.4412 0.0700
Total 14 26.5733 1.8981
=== Summary Statistics: algae_level ===
water_change_pct:
Level N Mean Std Min Max
------------------------------------------------------------
10 4 4.2000 1.6553 2.1000 6.1000
25 7 4.0571 1.5109 2.4000 6.9000
40 4 4.7000 1.0924 4.0000 6.3000
feed_g_day:
Level N Mean Std Min Max
------------------------------------------------------------
0.5 4 5.1750 1.5692 3.7000 6.9000
1.75 7 4.6143 0.7819 4.0000 6.3000
3 4 2.7500 0.8505 2.1000 4.0000
light_hrs:
Level N Mean Std Min Max
------------------------------------------------------------
12 4 4.6250 1.7988 2.5000 6.9000
6 4 4.1000 1.6228 2.4000 6.3000
9 7 4.1571 1.1731 2.1000 6.1000
Optimization Recommendations
=== Optimization: vitality_score ===
Direction: maximize
Best observed run: #10
water_change_pct = 40
feed_g_day = 3
light_hrs = 9
Value: 7.8
RSM Model (linear, R² = 0.3459, Adj R² = 0.1675):
Coefficients:
intercept +6.6467
water_change_pct +0.6250
feed_g_day -0.2125
light_hrs +0.1375
RSM Model (quadratic, R² = 0.9099, Adj R² = 0.7477):
Coefficients:
intercept +7.0000
water_change_pct +0.6250
feed_g_day -0.2125
light_hrs +0.1375
water_change_pct*feed_g_day +0.3500
water_change_pct*light_hrs -0.3500
feed_g_day*light_hrs +0.6250
water_change_pct^2 -0.1375
feed_g_day^2 +0.3375
light_hrs^2 -0.8625
Curvature analysis:
light_hrs coef=-0.8625 concave (has a maximum)
feed_g_day coef=+0.3375 convex (has a minimum)
water_change_pct coef=-0.1375 concave (has a maximum)
Notable interactions:
feed_g_day*light_hrs coef=+0.6250 (synergistic)
water_change_pct*feed_g_day coef=+0.3500 (synergistic)
water_change_pct*light_hrs coef=-0.3500 (antagonistic)
Predicted optimum (from quadratic model, at observed points):
water_change_pct = 40
feed_g_day = 3
light_hrs = 9
Predicted value: 7.9625
Surface optimum (via L-BFGS-B, quadratic model):
water_change_pct = 40
feed_g_day = 3
light_hrs = 9.71739
Predicted value: 8.0118
Model quality: Excellent fit — surface predictions are reliable.
Factor importance:
1. water_change_pct (effect: 1.2, contribution: 43.3%)
2. light_hrs (effect: 1.0, contribution: 35.1%)
3. feed_g_day (effect: 0.6, contribution: 21.5%)
=== Optimization: algae_level ===
Direction: minimize
Best observed run: #4
water_change_pct = 40
feed_g_day = 1.75
light_hrs = 6
Value: 2.1
RSM Model (linear, R² = 0.0930, Adj R² = -0.1544):
Coefficients:
intercept +4.2667
water_change_pct +0.2750
feed_g_day -0.1750
light_hrs +0.4500
RSM Model (quadratic, R² = 0.8100, Adj R² = 0.4679):
Coefficients:
intercept +5.8000
water_change_pct +0.2750
feed_g_day -0.1750
light_hrs +0.4500
water_change_pct*feed_g_day -0.1500
water_change_pct*light_hrs +1.4000
feed_g_day*light_hrs +0.3000
water_change_pct^2 -0.6250
feed_g_day^2 -0.7250
light_hrs^2 -1.5250
Curvature analysis:
light_hrs coef=-1.5250 concave (has a maximum)
feed_g_day coef=-0.7250 concave (has a maximum)
water_change_pct coef=-0.6250 concave (has a maximum)
Notable interactions:
water_change_pct*light_hrs coef=+1.4000 (synergistic)
Predicted optimum (from quadratic model, at observed points):
water_change_pct = 25
feed_g_day = 1.75
light_hrs = 9
Predicted value: 5.8000
Surface optimum (via L-BFGS-B, quadratic model):
water_change_pct = 40
feed_g_day = 3
light_hrs = 6
Predicted value: 0.7250
Model quality: Good fit — general trends are captured, some noise remains.
Factor importance:
1. light_hrs (effect: 1.9, contribution: 55.8%)
2. feed_g_day (effect: 0.7, contribution: 22.2%)
3. water_change_pct (effect: 0.7, contribution: 22.0%)