Turning raw inverter data into actionable solar plant intelligence.
Built to mirror the analytical workflows used by industrial PV asset managers.
π 38,376 daylight readings Β· 22 inverters Β· 34 days Β· 2 datasets merged
Solar power plants generate enormous amounts of operational data β but raw data alone doesn't prevent downtime or recover lost energy. This project applies data analytics and machine learning to Plant 1, an industrial solar facility in India, to extract three categories of operational intelligence:
- Which inverters are underperforming? β and by how much, in quantified kWh terms
- When do panels need cleaning? β detected from efficiency degradation patterns, not guesswork
- How much power will be generated tomorrow? β to support grid balancing decisions
This mirrors the exact analytical workflows deployed by companies in their commercial Smart O&M platforms.
| # | Problem | Why It Matters |
|---|---|---|
| 1 | Identify faulty or suboptimally performing equipment | Chronic underperformance loses thousands of kWh annually β invisible without data |
| 2 | Detect need for panel cleaning / maintenance | Dirty panels silently erode output; early detection prevents critical efficiency loss |
| 3 | Predict power generation for the next couple of days | Grid operators need generation forecasts for load balancing and energy trading |
Source: Kaggle β Solar Power Generation Data (India)
Two files for Plant 1 were used:
π data/
βββ Plant_1_Generation_Data.csv # Inverter-level power output
βββ Plant_1_Weather_Sensor_Data.csv # Plant-level sensor readings
| Column | Description |
|---|---|
DATE_TIME |
Timestamp (15-minute intervals) |
PLANT_ID |
Plant identifier (constant: 4135001) |
SOURCE_KEY |
Unique inverter ID (22 inverters) |
DC_POWER |
DC power output from solar panels (W) |
AC_POWER |
AC power after inverter conversion (W) |
DAILY_YIELD |
Cumulative daily energy yield (kWh) |
TOTAL_YIELD |
Lifetime energy yield (kWh) |
| Column | Description |
|---|---|
DATE_TIME |
Timestamp (15-minute intervals) |
AMBIENT_TEMPERATURE |
Air temperature at plant (Β°C) |
MODULE_TEMPERATURE |
Solar panel surface temperature (Β°C) |
IRRADIATION |
Solar irradiation intensity (W/mΒ²) |
β
Zero missing values in both files
β
No date gaps β complete 34-day coverage
β
3,157 common timestamps successfully merged
β
38,376 valid daylight rows after nighttime filtering (IRRADIATION > 0)
β οΈ 1,047 negative electricity readings in raw data (explained: net grid export)
β οΈ ~47% zero power readings (explained: nighttime β physically correct)
Raw Data
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β DATA PREPARATION β
β β’ Parse & standardise datetimes β
β β’ Merge generation + sensor data β
β β’ Drop redundant columns β
β β’ Engineer time features β
β β’ Filter to daylight hours only β
ββββββββββββββββ¬βββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β THREE ANALYSES β
β β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββ β
β β Fault Detection β β Maintenance Det. β βForecast β β
β β β β β β β β
β β Peer comparison β β Efficiency ratio β β LinReg β β
β β across 22 β β vs 7-day rolling β β Random β β
β β inverters β β average baseline β β Forest β β
β βββββββββββββββββββ ββββββββββββββββββββ βββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
Actionable Insights
Method: Peer comparison β all inverters share identical weather conditions, so consistent underperformers indicate structural faults.
# Performance ratio: how each inverter compares to plant average
inverter_avg['PERFORMANCE_RATIO'] = (inverter_avg['AVG_DC_POWER'] / plant_avg) * 100Results:
| Inverter ID | Avg DC Power | Underperformance | Energy Lost (34 days) | Projected Annual Loss |
|---|---|---|---|---|
bvBOhCH3iADSZry |
5,091.55 W | 10.54% | 262.79 kWh | 2,821 kWh/year |
1BY6WEcLGh8j5v7 |
5,173.35 W | 9.10% | 226.81 kWh | 2,435 kWh/year |
| Healthy Average | 5,691.19 W | β | β | β |
π‘ Combined annual energy loss: ~5,256 kWh/year from just 2 of 22 inverters.
Both inverters showed consistent underperformance across all 34 days β confirming structural fault, not weather-related variation.
Possible root causes:
- Degraded solar panel strings connected to these inverters
- Partial shading from nearby obstructions
- Loose wiring or connection degradation
- Inverter hardware degradation
Method: Track the ratio of DC power output to irradiation daily. A progressive drop in this efficiency ratio (below a 7-day rolling baseline) signals panel soiling.
daily_perf['efficiency_ratio'] = daily_perf['avg_dc_power'] / daily_perf['avg_irradiation']
daily_perf['rolling_efficiency'] = daily_perf['efficiency_ratio'].rolling(window=7, min_periods=1).mean()Correlation between irradiation and DC power: 0.97 β β confirms irradiation is a valid baseline for expected output.
Flagged Days:
| Date | Efficiency Ratio | Drop vs Baseline | Status |
|---|---|---|---|
| 2020-05-20 | 13,392.03 | 2.66% | |
| 2020-05-21 | 13,086.75 | 4.21% | |
| 2020-05-22 | 13,194.44 | 3.18% | |
| 2020-05-24 | 13,051.62 | 2.99% | |
| 2020-06-06 | 13,344.54 | 2.26% | |
| 2020-06-07 | 12,808.82 | 5.13% | π΄ CRITICAL |
π‘ The May 20β22 cluster and the June 6β7 consecutive drop are classic progressive soiling signatures in dry, dusty conditions. Early detection on May 20th could have prevented the June 7th critical breach.
Method: Aggregate daily plant-level generation, train on 29 days, test on last 5 days.
Features used:
avg_irradiation β solar energy input (dominant driver)
avg_module_temp β panel surface temperature
avg_ambient_temp β air temperature
day_number β captures temporal trend
Model Comparison:
| Model | MAE | RΒ² Score |
|---|---|---|
| Linear Regression | 36,392 W | 0.7098 |
| Random Forest | 35,373 W | 0.7541 β |
Feature Importance (Random Forest):
avg_irradiation ββββββββββββββββββββββββββββ 69.3% β dominant driver
avg_module_temp βββββββ 18.1%
day_number βββ 8.5%
avg_ambient_temp β 4.1%
π‘ Irradiation drives 69.3% of generation. This confirms that solar power forecasting is fundamentally a weather forecasting problem β accurate irradiation prediction unlocks accurate generation prediction.
Instead of using a fixed threshold (e.g., "flag if below 3,000W"), peer comparison dynamically adjusts for weather β on a cloudy day, all inverters produce less. This approach flags inverters that produce less than their peers on the same day, eliminating weather as a confounding factor.
A static efficiency baseline would miss seasonal drift. A 7-day rolling average creates a dynamic local baseline β if the plant gradually improves (e.g., after rain cleans panels naturally), the threshold moves with it. Only drops relative to the recent trend are flagged.
Linear regression assumes a linear relationship between features and output. Solar generation has non-linear effects (e.g., extreme heat reduces panel efficiency non-linearly). Random Forest captures these without overfitting on such a small dataset (34 days).
Being transparent about limitations is part of good data science practice.
| Limitation | Impact | Mitigation |
|---|---|---|
| Only 34 days of data | No seasonality captured; forecasting model is limited | Collect 1β2 years for robust seasonal modelling |
| Single plant | Model may not generalise to other plants/geographies | Validate on Plant 2 before production deployment |
| No string-level data | Cannot pinpoint exact panel causing inverter fault | Integrate string-level monitoring |
| No external weather forecast | Forecasting uses historical weather, not future predictions | Integrate Solcast or NASA POWER API for true forecasting |
| India-specific dataset | Irradiance patterns differ by geography | Retrain model per region |
"I built a Random Forest forecasting model that achieved RΒ² of 0.75 on the test window, but when I ran cross-validation the score dropped to 0.19 with high variance. This told me the model was getting lucky on those 5 days β 34 days simply isn't enough training data for a reliable forecast. In production I would need at minimum 1β2 years of data and replace same-day sensor readings with weather forecast API inputs like Solcast."
Python 3.8+# Clone the repository
git clone https://github.com/Manas-singh14/Solar-PV-power-generation-analysis.git
cd solar-pv-analytics
# Create virtual environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txtpandas>=1.3.0
numpy>=1.21.0
scikit-learn>=1.0.0
matplotlib>=3.5.0
seaborn>=0.11.0
jupyter>=1.0.0# Launch Jupyter Notebook
jupyter notebook
# Or run the full pipeline as a script
python src/analysis.pyPlace the Kaggle dataset files in the data/ directory:
data/
βββ Plant_1_Generation_Data.csv
βββ Plant_1_Weather_Sensor_Data.csv
solar-pv-analytics/
β
βββ π data/
β βββ Plant_1_Generation_Data.csv
β βββ Plant_1_Weather_Sensor_Data.csv
β
βββ π notebooks/
β βββ 01_data_preparation.ipynb # Merging, cleaning, feature engineering
β βββ 02_fault_detection.ipynb # Inverter peer comparison analysis
β βββ 03_maintenance_detection.ipynb # Panel soiling detection
β βββ 04_forecasting.ipynb # Power generation forecasting
β
βββ π src/
β βββ data_prep.py # Data loading and preprocessing
β βββ fault_detection.py # Inverter analysis functions
β βββ maintenance.py # Efficiency ratio analysis
β βββ forecasting.py # ML model training and evaluation
β βββ visualisation.py # Reusable plotting functions
β
βββ π outputs/
β βββ charts/ # Generated visualisations
β βββ Solar_PV_Analysis_Report.docx # Full project report
β
βββ π docs/
β βββ Solar_PV_Analysis_Report.docx
β
βββ requirements.txt
βββ README.md
βββ LICENSE
Domain Knowledge:
- Understood the full hardware hierarchy: Solar Panels β Inverters β Grid
- Learned the difference between DC power (panel output) and AC power (inverter output) and what faults each reveals
- Understood why nighttime zeros and negative net electricity readings are physically valid, not data errors
Analytical Skills:
- Peer comparison is more robust than fixed thresholds for anomaly detection in weather-dependent systems
- Rolling baselines are more reliable than static ones for efficiency monitoring
- Feature importance analysis revealed that solar forecasting is 69% a weather problem
Honest Data Science:
- A 34-day dataset is insufficient for capturing seasonality β always disclose limitations
- Correlation (0.97) should be verified before using a variable as a baseline
- Data "sparsity" from nighttime zeros is not a flaw β understanding the domain prevents misdiagnosis