Development of an AI system for monitoring livestock production
Large livestock farms—with 500+ head of cattle or 10,000+ pigs—don't allow a veterinarian to examine every animal daily. IoT monitoring systems with AI analyze behavioral sensors, video, and feeding data to address three key issues: early disease detection, heat/calving, and feed optimization.
Sensor infrastructure
Typical sensors on an animal:
sensor_types = {
'ear_tag_accelerometer': {
'measures': ['activity_count', 'rumination_time', 'lying_time'],
'vendors': ['SCR (Merck Animal Health)', 'Allflex SenseHub', 'Moocall'],
'frequency': '2-min aggregates'
},
'rumen_bolus': {
'measures': ['rumen_pH', 'rumen_temperature', 'rumen_motility'],
'vendors': ['SmaXtec', 'Medria'],
'frequency': '10-min readings'
},
'milk_meter': {
'measures': ['yield_kg', 'conductivity', 'flow_rate', 'milk_temperature'],
'vendors': ['DeLaval ALPRO', 'Lely T4C'],
'frequency': 'per milking'
},
'weigh_scale': {
'measures': ['body_weight_kg'],
'frequency': 'daily at feeding station'
}
}
Estrus Detection
Algorithm for activity and rumination:
import pandas as pd
import numpy as np
from scipy.signal import find_peaks
def detect_estrus(animal_id: str, sensor_data: pd.DataFrame,
baseline_days: int = 21) -> dict:
"""
Охота у КРС: резкий рост активности + снижение руминации
Цикл ~21 день — паттерн периодический
"""
recent = sensor_data[sensor_data['animal_id'] == animal_id].tail(baseline_days * 24)
# Нормировка по индивидуальному baseline
activity_baseline = recent['activity_count'].quantile(0.5)
rumination_baseline = recent['rumination_time'].quantile(0.5)
current_24h = sensor_data[
sensor_data['animal_id'] == animal_id
].tail(12) # последние 2 часа (12 × 10-мин блоков)
activity_ratio = current_24h['activity_count'].mean() / (activity_baseline + 1e-9)
rumination_ratio = current_24h['rumination_time'].mean() / (rumination_baseline + 1e-9)
# Охота: активность выше нормы в 2+ раза, руминация снижена
estrus_score = activity_ratio * (2 - rumination_ratio)
# Дополнительно: проверяем повторение 21 день назад
prev_cycle_score = check_previous_cycle(animal_id, sensor_data, days_back=21)
return {
'animal_id': animal_id,
'estrus_score': float(estrus_score),
'estrus_detected': estrus_score > 2.5,
'confidence': 'high' if prev_cycle_score > 2.0 else 'medium',
'recommended_action': 'insemination_window_12-18h' if estrus_score > 2.5 else None
}
Early detection of mastitis
Milk conductivity is the main signal:
def mastitis_risk_score(milking_data: pd.DataFrame, animal_id: str) -> float:
"""
Мастит → воспаление → рост ионов Na+, Cl- → рост электропроводности
Сравниваем четверти вымени между собой и с историей
"""
today_milking = milking_data[
(milking_data['animal_id'] == animal_id) &
(milking_data['date'] == milking_data['date'].max())
]
if today_milking.empty:
return 0.0
quarters = ['LF', 'RF', 'LR', 'RR'] # левая передняя, правая передняя, etc.
conductivities = {q: today_milking[f'conductivity_{q}'].mean()
for q in quarters if f'conductivity_{q}' in today_milking.columns}
if len(conductivities) < 2:
return 0.0
mean_cond = np.mean(list(conductivities.values()))
max_deviation = max(abs(v - mean_cond) for v in conductivities.values())
# Порог: >0.5 мСм/см отклонение от среднего = подозрение
relative_deviation = max_deviation / (mean_cond + 1e-9)
# Также: снижение удоя на четверти
yield_deviation = check_yield_drop(animal_id, milking_data, today_milking)
risk_score = 0.6 * (relative_deviation / 0.1) + 0.4 * yield_deviation
return min(1.0, risk_score)
Additional signs of mastitis:
- Increase in milk temperature in the quartet (+0.5°C)
- Flocculation - change in flow rate pattern
- Decrease in overall milk yield while maintaining appetite
- Change in behavior on the milking machine (connection time)
Health monitoring by rumination
Rumen acidosis (SARA) - decreased pH:
def detect_sara_risk(rumen_bolus_data: pd.DataFrame, animal_id: str) -> dict:
"""
SARA (Sub-Acute Ruminal Acidosis): pH < 5.8 более 3 часов в сутки
Данные от rumen bolus SmaXtec обновляются каждые 10 минут
"""
today_data = rumen_bolus_data[
(rumen_bolus_data['animal_id'] == animal_id) &
(rumen_bolus_data['date'] == pd.Timestamp.today().date())
]
low_ph_minutes = len(today_data[today_data['rumen_pH'] < 5.8]) * 10
# Снижение руминации + низкий pH = SARA
avg_ph = today_data['rumen_pH'].mean() if not today_data.empty else 6.5
rumination_today = today_data['rumen_motility'].mean() if not today_data.empty else 1.0
sara_risk = 'high' if low_ph_minutes > 180 else (
'medium' if low_ph_minutes > 60 else 'low'
)
return {
'animal_id': animal_id,
'low_ph_hours': round(low_ph_minutes / 60, 1),
'avg_ph': round(avg_ph, 2),
'sara_risk': sara_risk,
'action': 'adjust_roughage_ratio' if sara_risk == 'high' else None
}
Group analysis and feeding optimization
Automatic formation of production groups:
from sklearn.cluster import KMeans
def form_feeding_groups(herd_data: pd.DataFrame, n_groups: int = 4) -> dict:
"""
Группировка КРС для точного кормления (TMR-рационы)
Признаки: ДИМ (дней в молоке), удой, BCS (упитанность), вес
"""
features = ['days_in_milk', 'milk_yield_7d_avg', 'body_condition_score', 'body_weight']
X = herd_data[features].dropna()
kmeans = KMeans(n_clusters=n_groups, random_state=42, n_init=10)
herd_data.loc[X.index, 'feeding_group'] = kmeans.fit_predict(X)
group_recommendations = {}
for group_id in range(n_groups):
group = herd_data[herd_data['feeding_group'] == group_id]
group_recommendations[group_id] = {
'n_animals': len(group),
'avg_days_in_milk': group['days_in_milk'].mean(),
'target_energy_NEL': calculate_nel_requirement(group),
'crude_protein_pct': calculate_cp_requirement(group)
}
return group_recommendations
Dashboard and alerts: The system generates a daily list of priority animals for inspection: the top 10 by composite risk score (mastitis + disease + heat). Integration with herd management software: DairyComp 305, Herd Navigator, SAP Animal Management.
Timeframe: Estrus + mastitis detection + basic dashboard – 4-5 weeks. SARA monitoring, group feeding, predictive disease models, and DairyComp integration – 2-3 months.







