Overview
AgriVolt is a comprehensive platform for agrivoltaic project development, combining AI-powered yield predictions, financial modeling, and hardware optimization. This documentation covers the technical implementation and integration of our core systems.
Yield Predictions
pvlib-based solar modeling
Financial Models
NPV, IRR, cashflow analysis
Optimization
ML-trained tilt control
System Architecture
agrivolt/
├── src/
│ ├── app/ # Next.js app router pages
│ ├── components/ # React components
│ ├── lib/ # Utilities & API clients
│ └── types/ # TypeScript definitions
├── backend/
│ ├── main.py # FastAPI application
│ ├── pv_model.py # Solar yield modeling
│ └── financial_model.py # NPV/IRR calculations
└── supabase/
└── schema.sql # Database schemaAPI Reference
/api/simulateRun a complete agrivoltaic simulation for a site.
{
"latitude": 41.9028,
"longitude": 12.4964,
"capacity_mwp": 15.0,
"mounting": "single",
"monthly_demand_gwh": [1.5, 2.5, 2.0, ...],
"retail_rate": 0.19,
"export_rate": 0.10
}/api/weatherFetch historical weather data for a location.
lat: number # Latitude (-90 to 90)
lon: number # Longitude (-180 to 180)
years: number # Years of historical data (default: 20)Yield Prediction Model
Our yield prediction model uses pvlib for precise solar position calculations and NASA POWER data for historical irradiance. The model supports fixed, single-axis, and dual-axis tracking configurations.
def day_energy(alpha, beta, solar_vector, Dt, Temp=25):
"""
Calculate daily energy production for a PV panel.
Args:
alpha: Panel pitch angle (radians)
beta: Panel azimuth angle (radians)
solar_vector: 3D solar direction vectors [3, N]
Dt: Time step in seconds
Temp: Ambient temperature (Celsius)
Returns:
Daily energy in Wh/kWpeak
"""
# Temperature derating: -0.5% per degree above 25°C
temperature_effect = 1 - 0.005 * (Temp - 25)
# Filter low-elevation sun positions
el_threshold = np.radians(15)
keep_idx = solar_vector[2, :] < -np.sin(el_threshold)
solar_vector = solar_vector[:, keep_idx]
# Panel normal vector
p_x = np.sin(alpha) * np.sin(beta)
p_y = np.sin(alpha) * np.cos(beta)
p_z = np.cos(alpha)
# Irradiance calculation (dot product)
irradiance = -(solar_vector[0]*p_x + solar_vector[1]*p_y + solar_vector[2]*p_z)
irradiance = irradiance[irradiance > 0]
irradiance *= 1000 * temperature_effect # W/kWpeak
return np.sum(irradiance) * Dt / 3600 # Wh/kWpeakKey Parameters
- Solar Vector: 3D unit vector representing incoming radiation direction
- Panel Angles: Alpha (pitch) and Beta (azimuth) define panel orientation
- Temperature Effect: Efficiency loss of 0.5% per degree above 25°C
- Elevation Filter: Ignore sun positions below 15° elevation
Financial Model
The financial model evaluates project economics over a 30-year lifetime, accounting for self-consumption, grid export, degradation, and time value of money.
@dataclass
class Costs:
panel_capex_per_kwp: float = 600.0
tracker_capex_per_kwp: float = 25.0
inverter_capex_per_kwp: float = 50.0
bos_capex_per_kwp: float = 125.0
opex_pct_of_capex_per_year: float = 0.015 # 1.5%
@property
def total_capex_per_kwp(self) -> float:
return (self.panel_capex_per_kwp + self.tracker_capex_per_kwp +
self.inverter_capex_per_kwp + self.bos_capex_per_kwp)
def evaluate_capacity(capacity_mwp, monthly_demand_gwh, monthly_kwh_per_kwp,
pricing, costs, rates, export_ref):
"""
Evaluate NPV for a given system capacity.
"""
# Calculate CAPEX
capex = capacity_mwp * 1000.0 * costs.total_capex_per_kwp
opex_per_year = capex * costs.opex_pct_of_capex_per_year
# Year 1 savings
pv_y1 = pv_gen_gwh_per_month(capacity_mwp, monthly_kwh_per_kwp)
year1_savings = yearly_savings_eur(monthly_demand_gwh, pv_y1, pricing)
# NPV calculation with degradation
npv_stream = 0.0
for t in range(1, rates.lifetime_years + 1):
degr_factor = (1.0 - rates.yearly_degradation) ** (t - 1)
gross_saving_t = year1_savings * degr_factor
net_saving_t = gross_saving_t - opex_per_year
npv_stream += net_saving_t / ((1.0 + rates.discount_rate) ** t)
return npv_stream - capexDefault Assumptions
- Total CAPEX: €800/kWp
- OPEX: 1.5% of CAPEX/year
- Degradation: 0.5%/year
- Discount Rate: 5%
- Project Life: 30 years
Energy Accounting
- Self-consumed: min(PV, Demand)
- Exported: max(0, PV - Demand)
- Grid import: max(0, Demand - PV)
- Retail rate for self-consumption
- Export tariff for surplus
Optimization Engine
The optimization engine uses scipy to find optimal panel trajectories that maximize energy capture while minimizing mechanical stress.
def objective(z):
"""
Optimization objective: maximize irradiance, minimize movement.
Args:
z: Decision vector [alpha_0, ..., alpha_N, beta_0, ..., beta_N]
Returns:
Cost value to minimize
"""
R = 1 # Movement penalty weight
alpha = z[:N] # Pitch angles
beta = z[N:] # Azimuth angles
# Panel normal vector components
p_x = np.sin(alpha) * np.sin(beta)
p_y = np.sin(alpha) * np.cos(beta)
p_z = np.cos(alpha)
# Movement penalty (smooth trajectories)
movement_cost = np.sum(np.diff(alpha)**2)
# Irradiance integral (dot product with sun vector)
irradiance = -(solar_vector[0]*p_x + solar_vector[1]*p_y + solar_vector[2]*p_z)
energy_gain = np.sum(irradiance)
# Minimize movement, maximize energy (hence negative)
return R * movement_cost - energy_gainIntegration Guide
1. Environment Setup
# Install Python dependencies
pip install fastapi uvicorn pvlib pandas numpy scipy requests
# Start the backend server
cd backend
uvicorn main:app --host 0.0.0.0 --port 80002. Frontend API Client
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
export async function runSimulation(input: SimulationInput) {
const response = await fetch(`${API_BASE_URL}/api/simulate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(input),
});
if (!response.ok) {
throw new Error('Simulation failed');
}
return response.json();
}3. Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
NEXT_PUBLIC_API_URL=https://your-backend.railway.appNeed More Help?
Book a consultation with our engineering team for integration support.
Book Appointment