Input Features
Complete reference for the 44-dimensional observation vector used by the FeedRight DQN agent.
The DQN agent observes the world through a 44-dimensional continuous state vector. Every feature is min-max normalised to the [0, 1] range before being fed into the neural network. This page documents every dimension, its physical meaning, units, and normalisation bounds.
Feature Layout Summary
| Group | Dimensions | Index Range | Count |
|---|---|---|---|
| Environmental | DO, temperature, salinity, O₂ sat, cloud, wind, humidity, trends, time | 0 – 12 | 13 |
| Biomass | total biomass, fish count, avg weight, growth rate, stocking age, growth stage | 13 – 18 | 6 |
| Video | motion intensity, feeding frenzy, surface activity, pellet sink time, uneaten count | 19 – 23 | 5 |
| Feeding History | time since feed, last amount, consumption rate, daily avg, feeds today, interval, totals | 24 – 32 | 9 |
| Performance | FCR, SGR (7d/30d), waste rate, cost per kg growth | 33 – 37 | 5 |
| Cage | depth, volume, stocking density, water flow, location, age | 38 – 43 | 6 |
Environmental Features (13 dimensions)
| Index | Feature | Units | Min | Max | Description |
|---|---|---|---|---|---|
| 0 | dissolved_oxygen | mg/L | 4.0 | 9.0 | Dissolved oxygen concentration at cage depth. Below 5.0 is dangerous. |
| 1 | temperature | °C | 22.0 | 32.0 | Water temperature. Optimal range is 26–29 °C for most tropical species. |
| 2 | salinity | PSU | 28.0 | 36.0 | Salinity level. Affects fish metabolism and feed palatability. |
| 3 | oxygen_saturation | % | 60.0 | 100.0 | O₂ saturation percentage. Below 65% triggers a safety block. |
| 4 | cloud_cover | % | 0.0 | 100.0 | Cloud cover percentage. Affects light penetration and fish behaviour. |
| 5 | wind_speed | m/s | 0.0 | 20.0 | Wind speed at cage site. Above 15 m/s triggers a safety block. |
| 6 | wind_direction | ° | 0.0 | 360.0 | Wind direction in degrees. Influences surface current and pellet drift. |
| 7 | humidity | % | 40.0 | 100.0 | Relative humidity. Used as a weather-condition proxy. |
| 8 | temp_change_1h | °C/h | −2.0 | 2.0 | Temperature change over the last hour. Rapid shifts (> 1.5 °C) stress fish. |
| 9 | oxygen_trend_3h | mg/L | −1.0 | 1.0 | 3-hour dissolved oxygen trend. Negative values indicate declining O₂. |
| 10 | temp_deviation_from_optimal | °C | −5.0 | 5.0 | Deviation from the species-specific optimal temperature. |
| 11 | hour_of_day | h | 0 | 23 | Current hour (0–23). Encodes diurnal feeding patterns. |
| 12 | is_daylight | bool | 0 | 1 | Whether the sun is currently up. Fish feed primarily during daylight. |
Biomass Features (6 dimensions)
These features are produced by the biomass estimation pipeline, which runs a fine-tuned YOLO fish-detection model on sampled video frames. Each detected bounding box is converted to a length / girth / weight estimate using the allometric relationship W = a × L^b × G^c, calibrated with a per-camera pixels_per_cm constant. Individual weights are averaged and scaled by the known stocking count to compute total cage biomass.
| Index | Feature | Units | Min | Max | Description |
|---|---|---|---|---|---|
| 13 | current_total_biomass | kg | 2 000 | 15 000 | Estimated live biomass in the cage (stocking count × avg weight from YOLO detections). |
| 14 | estimated_fish_count | count | 1 000 | 15 000 | Stocking count (supplied externally; not derived from detection count since only a fraction of fish are visible per frame). |
| 15 | average_fish_weight | g | 200 | 3 000 | Mean individual fish weight estimated from YOLO bounding-box morphometrics. |
| 16 | biomass_growth_rate_7d | g/week | 10 | 150 | Weekly biomass growth rate per individual. |
| 17 | days_since_stocking | days | 0 | 365 | Number of days since fish were stocked into the cage. |
| 18 | growth_stage | enum | 0 | 2 | Discrete growth stage: 0 = Juvenile, 1 = Growing, 2 = Mature (derived from avg weight thresholds). |
Video Features (5 dimensions)
These features are produced by the video behaviour analysis pipeline using two complementary signal sources:
- Farnebäck dense optical flow — computed between consecutive greyscale frames with spatial attention and temporal smoothing to quantify fish swimming dynamics.
- YOLO pellet-detection model (optional) — detects uneaten feed pellets for direct waste measurement with temporal consistency filtering. When unavailable, the pipeline falls back to motion-deficit heuristics.
| Index | Feature | Units | Min | Max | How it is derived |
|---|---|---|---|---|---|
| 19 | motion_intensity | 0–100 | 0.0 | 100.0 | 75th-percentile of the Farnebäck optical-flow magnitude histogram, temporally smoothed with an EMA (α = 0.3). Isolates fish motion from static background. |
| 20 | feeding_frenzy_score | 0–1 | 0.0 | 1.0 | Product of upward-flow surface convergence ratio and directional coherence (cosine similarity) in the top third of a 3×3 spatial grid. Filters out camera shake and turbulence — only coordinated upward rushes score high. This is the primary hunger signal for the DQN reward function. |
| 21 | surface_activity | 0–1 | 0.0 | 1.0 | Vertical energy-profile skew: squared-magnitude energy in the top bands minus the uniform-distribution baseline. Captures fish redistribution toward the surface independent of overall activity level. |
| 22 | pellet_sinking_time | seconds | 0.0 | 30.0 | With pellet model: median sinking time from depth-weighted pellet tracklets across consecutive frames. Without pellet model: inverse-activity proxy (low motion + high surface activity → longer sinking time). |
| 23 | uneaten_pellet_count | count | 0 | 500 | With pellet model: YOLO pellet count with NMS (IoU ≥ 0.5) and temporal consistency filtering (pellet must appear in ≥ 2 of 3 consecutive frames). Without pellet model: motion-deficit heuristic (current motion below trailing 60 s EMA). |
Feeding History Features (9 dimensions)
| Index | Feature | Units | Min | Max | Description |
|---|---|---|---|---|---|
| 24 | time_since_last_feed | hours | 0.0 | 12.0 | Hours elapsed since the last feed event. The agent learns optimal feeding intervals. |
| 25 | last_feed_amount | grams | 0.0 | 5 000 | Amount dispensed in the most recent feed event (stored in grams in state). |
| 26 | last_feed_consumption_rate | 0–1 | 0.0 | 1.0 | Proportion of the last feed that was actually consumed. |
| 27 | avg_daily_feed_7d | grams | 0.0 | 10 000 | 7-day rolling average of daily total feed. |
| 28 | feeds_today | count | 0 | 8 | Number of feed events already executed today. The safety layer blocks feeds beyond 6. |
| 29 | avg_interval_7d | hours | 2.0 | 8.0 | 7-day average interval between consecutive feeds. |
| 30 | total_feed_30d | kg | 0.0 | 300.0 | Cumulative feed dispensed over the last 30 days. |
| 31 | feeding_efficiency_7d | 0–1 | 0.5 | 1.0 | 7-day rolling feed efficiency (consumed / dispensed). |
| 32 | baseline_activity | 0–100 | 0.0 | 100.0 | Baseline pre-feed activity level for comparison with current motion. |
Performance Features (5 dimensions)
| Index | Feature | Units | Min | Max | Description |
|---|---|---|---|---|---|
| 33 | current_fcr | ratio | 0.8 | 3.0 | Feed Conversion Ratio. Lower is better (industry target < 1.5). |
| 34 | sgr_7d | %/day | 0.0 | 3.0 | Specific Growth Rate over the last 7 days. |
| 35 | sgr_30d | %/day | 0.0 | 3.0 | Specific Growth Rate over the last 30 days. |
| 36 | feed_waste_rate | 0–0.5 | 0.0 | 0.5 | Fraction of feed wasted (not consumed). Above 0.3 triggers a safety reduction. |
| 37 | cost_per_kg_growth | $/kg | 1.0 | 5.0 | Economic cost of feed per kilogram of fish growth. |
Cage Features (6 dimensions)
| Index | Feature | Units | Min | Max | Description |
|---|---|---|---|---|---|
| 38 | cage_depth | metres | 5.0 | 20.0 | Depth of the net cage. |
| 39 | cage_volume | m³ | 500 | 5 000 | Total cage volume. |
| 40 | stocking_density | kg/m³ | 5.0 | 25.0 | Current stocking density. |
| 41 | water_flow_rate | m/s | 0.0 | 2.0 | Water current speed through the cage. |
| 42 | cage_location_encoded | int | 0 | 100 | Encoded cage location identifier. |
| 43 | cage_age_days | days | 0 | 365 | Days since the cage was deployed. |
Normalisation
All 44 features are min-max normalised before being passed to the DQN:
normalised = (raw - min) / (max - min + ε)where ε = 1e-8 prevents division by zero. The result is clipped to [0, 1].
The feature_mins and feature_maxs arrays in FishFeedingEnv.__init__ define the exact bounds. If a feature value falls outside these bounds at inference time it is clamped, so the agent always sees valid inputs.
Denormalisation (used internally for reward calculation and rendering) reverses the transformation:
raw = normalised × (max - min) + min