Technical Documentation

AgriVolt Documentation

Comprehensive guides, API references, and code examples for integrating AgriVolt's agrivoltaic optimization platform.

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

Frontend (Next.js)
API Layer (FastAPI)
ML Models (Python)
Database (Supabase)
Project Structure
text
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 schema

API Reference

POST/api/simulate

Run a complete agrivoltaic simulation for a site.

Request Body
json
{
  "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
}
GET/api/weather

Fetch historical weather data for a location.

Query Parameters
text
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.

pv_model.py - Core Energy Calculation
python
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/kWpeak

Key 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.

financial_model.py - NPV Calculation
python
@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 - capex

Default 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.

Optimization Objective Function
python
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_gain

Integration Guide

1. Environment Setup

Backend Requirements
bash
# 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 8000

2. Frontend API Client

src/lib/api.ts
typescript
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

Environment Variables
bash
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.app

Need More Help?

Book a consultation with our engineering team for integration support.

Book Appointment