IV Failure Classification with Neural Networks
This notebook demonstrates the use of the pvops.iv.models.nn
module for classification of faults.
[1]:
import os
import sys
from pvops.iv import simulator, extractor, preprocess
from pvops.iv.models import nn
Create iv column dictionary with format {pvops variable: user-specific column names}. This establishes a connection between the user’s data columns and the pvops library.
[2]:
iv_col_dict = {
"mode": "mode",
"current": "current", # Populated in simulator
"voltage": "voltage", # Populated in simulator
"irradiance": "E", # Populated in simulator
"temperature": "T", # Populated in simulator
"power": "power", # Populated in preprocess
"derivative": "derivative", # Populated in feature_generation
"current_diff": "current_diff", # Populated in feature_generation
}
Step 1: Collect your IV curves.
In this case, we simulate some curves, but you can replace this step by reading in your own data, if wanted.
[3]:
def define_failure_at_environment(sim, E, Tc, N_samples = 10):
def namer(name):
suffix = f"-{E}_{Tc}"
return name + suffix
sim.pristine_condition = {'identifier': 'pristine',
'E': E,
'Tc': Tc,
'Rsh_mult': 1,
'Rs_mult': 1,
'Io_mult': 1,
'Il_mult': 1,
'nnsvth_mult': 1,
}
condition = {'identifier':namer('weathered_pristine')}
sim.add_preset_conditions('complete', condition, save_name = namer('Complete_weathered_pristine'))
condition = {'identifier':namer('shade'),'Il_mult':0.6}
sim.add_preset_conditions('complete', condition, save_name = namer('Complete_shading'))
condition = {'identifier':namer('cracking'),'Rs_mult':1.5}
sim.add_preset_conditions('complete', condition, save_name = namer('Complete_cracking'))
dicts = {'Il_mult':{'mean': 0.6,
'std': 0.7,
'low': 0.33,
'upp': 0.95,
}
}
sim.generate_many_samples(namer('shade'), N_samples, dicts)
dicts = {
'Rs_mult':{'mean':1.3,
'std':0.6,
'low':1.1,
'upp':1.8
},
'Rsh_mult':{'mean':0.5,
'std':0.6,
'low':0.3,
'upp':0.7
}
}
sim.generate_many_samples(namer('cracking'), N_samples, dicts)
sim.build_strings({
namer('Partial Soiling (1M)'): [namer('Complete_weathered_pristine')]*11 + [namer('Complete_shading')]*1,
namer('Partial Soiling (6M)'): [namer('Complete_weathered_pristine')]*6 + [namer('Complete_shading')]*6,
namer('Cell cracking (4M)'): [namer('Complete_weathered_pristine')]*8 + [namer('Complete_cracking')]*4,
})
return sim
[4]:
import numpy as np
sim = simulator.Simulator(
pristine_condition = {
'identifier': 'pristine',
'E': 1000,
'Tc': 50,
'Rsh_mult': 1,
'Rs_mult': 1,
'Io_mult': 1,
'Il_mult': 1,
'nnsvth_mult': 1,
})
sim.build_strings({'Pristine array': ['pristine']*12})
Tc = 35
for E in np.arange(200,1100,100):
for Tc in np.arange(35,60,5):
define_failure_at_environment(sim, E, Tc, N_samples = 25)
sim.simulate()
Simulating cells: 0%| | 0/136 [00:00<?, ?it/s]/home/klbonne/.local/bin/anaconda3/envs/pvops_dev/lib/python3.8/site-packages/scipy/optimize/_zeros_py.py:466: RuntimeWarning: some failed to converge after 100 iterations
warnings.warn(msg, RuntimeWarning)
Simulating cells: 100%|██████████| 136/136 [00:39<00:00, 3.43it/s]
Adding up simulations: 100%|██████████| 136/136 [00:45<00:00, 3.02it/s]
Adding up other definitions: 100%|██████████| 136/136 [00:00<00:00, 584452.20it/s]
[5]:
df = sim.sims_to_df(focus=['string'], cutoff=True)
df.head()
[5]:
current | voltage | E | T | mode | level | |
---|---|---|---|---|---|---|
0 | [9.214203000284689, 9.210691359222285, 9.20726... | [3.834932371660216e-12, 11.207809937682319, 22... | 1000.0 | 50.0 | Pristine array | string |
1 | [1.828797118809955, 1.8281227256242998, 1.8274... | [9.598528688982285, 19.45539770828682, 29.0763... | 200.0 | 35.0 | Partial Soiling (1M)-200_35 | string |
2 | [1.828797118809955, 1.8281227256242998, 1.8274... | [9.598528688982285, 19.45539770828682, 29.0763... | 200.0 | 35.0 | Partial Soiling (1M)-200_35 | string |
3 | [1.828797118809955, 1.8281227256242998, 1.8274... | [9.598528688982285, 19.45539770828682, 29.0763... | 200.0 | 35.0 | Partial Soiling (1M)-200_35 | string |
4 | [1.828797118809955, 1.8281227256242998, 1.8274... | [9.598528688982285, 19.45539770828682, 29.0763... | 200.0 | 35.0 | Partial Soiling (1M)-200_35 | string |
[6]:
# Convert modes to be the discrete failure modes
df['mode'] = [x.split('-')[0] for x in df['mode']]
Visualize generated samples for each failure mode.
[15]:
import matplotlib.pyplot as plt
colors = ['k', 'tab:red', 'tab:blue', 'tab:green']
# plt.figure(figsize=(12,8))
unique_modes = df['mode'].unique()
for md_idx, md in enumerate(unique_modes):
plt.figure(figsize=(10,5))
subdf = df[df['mode'] == md]
i = 0
for ind,row in subdf.iterrows():
if i == 0:
plt.plot(row['voltage'], row['current'], linewidth=1, color=colors[md_idx], label=md)
plt.plot(row['voltage'], row['current'], linewidth=1, color=colors[md_idx])
i += 1
plt.legend()
plt.xlabel("Voltage (V)")
plt.ylabel("Current (A)")
Next, process the data for irradiance and temperature correction, and normalize the axes. Shuffle the data in preparation for classification.
[8]:
prep_df = preprocess.preprocess(df, 0.05, iv_col_dict, resmpl_cutoff=0.03,
correct_gt=True, normalize_y=False,
CECmodule_parameters=sim.module_parameters,
n_mods=12, gt_correct_option=3)
# Shuffle
bigdf = prep_df.sample(frac=1).reset_index(drop=True)
bigdf.dropna(inplace=True)
bigdf.head(n=2)
[8]:
mode | current | voltage | power | E | T | |
---|---|---|---|---|---|---|
0 | Partial Soiling (6M) | [9.208600987136746, 9.195882051686299, 9.18315... | [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ... | [0.2762580296141024, 0.735670564134904, 1.1938... | 600.0 | 50.0 |
1 | Partial Soiling (6M) | [9.212759790227, 9.200363798497587, 9.18796074... | [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ... | [0.27638279370681, 0.736029103879807, 1.194434... | 200.0 | 40.0 |
[9]:
# Feature generation
feat_df = nn.feature_generation(bigdf, iv_col_dict)
feat_df.head(n=2)
[9]:
mode | current | voltage | power | E | T | current_diff | derivative | |
---|---|---|---|---|---|---|---|---|
0 | Partial Soiling (6M) | [9.208600987136746, 9.195882051686299, 9.18315... | [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ... | [0.2762580296141024, 0.735670564134904, 1.1938... | 600.0 | 50.0 | [0.0015998674001220792, 0.007648488303704681, ... | [0.0, -0.012718935450447333, -0.01272509254493... |
1 | Partial Soiling (6M) | [9.212759790227, 9.200363798497587, 9.18796074... | [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ... | [0.27638279370681, 0.736029103879807, 1.194434... | 200.0 | 40.0 | [-0.0025589356901321025, 0.0031667414924161363... | [0.0, -0.01239599172941297, -0.012403058265777... |
[10]:
fig = nn.plot_profiles(feat_df,
iv_col_dict['voltage'],
iv_col_dict['current'],
iv_col_dict)
fig = nn.plot_profiles(feat_df,
iv_col_dict['voltage'],
iv_col_dict['derivative'],
iv_col_dict)
fig = nn.plot_profiles(feat_df,
iv_col_dict['voltage'],
iv_col_dict['current_diff'],
iv_col_dict)
[11]:
# To provide a clean output, we filter warnings. We encourage you to *remove* this filter.
import logging
import tensorflow as tf
tf.get_logger().setLevel(logging.ERROR)
nn_config = {
# NN parameters
"model_choice": "1DCNN", # or "LSTM_multihead"
"params": ['current', 'power', 'derivative', 'current_diff'],
"dropout_pct": 0.5,
"verbose": 1,
# Training parameters
"train_size": 0.9,
"shuffle_split": True,
"balance_tactic": 'truncate',
"n_CV_splits": 5,
"batch_size": 8,
"max_epochs": 100,
# LSTM parameters
"use_attention_lstm": False,
"units": 50,
# 1DCNN parameters
"nfilters": 64,
"kernel_size": 12,
}
nn.classify_curves(feat_df, iv_col_dict, nn_config)
Balance data by mode:
[Class Partial Soiling (1M)]: Resampled, 1170 == 1170
[Class Partial Soiling (6M)]: Resampled, 1170 == 1170
[Class Cell cracking (4M)]: Resampled, 1170 == 1170
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv1d (Conv1D) (None, 10, 64) 3136
dropout (Dropout) (None, 10, 64) 0
flatten (Flatten) (None, 640) 0
dense (Dense) (None, 100) 64100
dense_1 (Dense) (None, 3) 303
=================================================================
Total params: 67,539
Trainable params: 67,539
Non-trainable params: 0
_________________________________________________________________
None
20/20 [==============================] - 0s 1ms/step - loss: 0.0025 - categorical_accuracy: 1.0000
categorical_accuracy: 100.00%
20/20 [==============================] - 0s 960us/step - loss: 2.5271e-04 - categorical_accuracy: 1.0000
categorical_accuracy: 100.00%
20/20 [==============================] - 0s 1ms/step - loss: 0.0010 - categorical_accuracy: 1.0000
categorical_accuracy: 100.00%
20/20 [==============================] - 0s 2ms/step - loss: 1.8145e-04 - categorical_accuracy: 1.0000
categorical_accuracy: 100.00%
20/20 [==============================] - 0s 2ms/step - loss: 2.1883e-05 - categorical_accuracy: 1.0000
categorical_accuracy: 100.00%
44/44 [==============================] - 0s 1ms/step
precision recall f1-score support
Cell cracking (4M) 1.00 1.00 1.00 117
Partial Soiling (1M) 1.00 1.00 1.00 117
Partial Soiling (6M) 1.00 1.00 1.00 117
accuracy 1.00 351
macro avg 1.00 1.00 1.00 351
weighted avg 1.00 1.00 1.00 351
[[117 0 0]
[ 0 117 0]
[ 0 0 117]]
accuracy on test: 1.0
[11]:
(<pvops.iv.models.nn.IVClassifier at 0x7f149043b6a0>,
mode current \
546 Partial Soiling (6M) [9.210855299765184, 9.198167892156352, 9.18547...
308 Partial Soiling (6M) [9.203746007748741, 9.190451335406063, 9.17714...
1985 Partial Soiling (1M) [9.213877334936674, 9.206654363996044, 9.19943...
1150 Partial Soiling (6M) [9.209214372643126, 9.196397972209853, 9.18357...
1354 Partial Soiling (6M) [9.204381949246688, 9.191145738106723, 9.17790...
... ... ...
517 Cell cracking (4M) [9.211188954334622, 9.201364333368181, 9.19153...
1913 Cell cracking (4M) [9.214349750807305, 9.206652654143795, 9.19893...
1402 Partial Soiling (1M) [9.218452597921566, 9.211327251671754, 9.20420...
585 Partial Soiling (6M) [9.204333662518495, 9.191016941963325, 9.17769...
1599 Cell cracking (4M) [9.216763526435322, 9.209357893492049, 9.20195...
voltage \
546 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
308 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
1985 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
1150 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
1354 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
... ...
517 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
1913 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
1402 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
585 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
1599 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
power E T \
546 [0.2763256589929555, 0.7358534313725081, 1.194... 300.0 35.0
308 [0.2761123802324622, 0.7352361068324851, 1.193... 800.0 35.0
1985 [0.2764163200481002, 0.7365323491196836, 1.195... 800.0 40.0
1150 [0.2762764311792938, 0.7357118377767883, 1.193... 600.0 55.0
1354 [0.2761314584774006, 0.7352916590485379, 1.193... 1000.0 50.0
... ... ... ...
517 [0.27633566863003867, 0.7361091466694545, 1.19... 700.0 50.0
1913 [0.27643049252421914, 0.7365322123315037, 1.19... 300.0 55.0
1402 [0.27655357793764695, 0.7369061801337403, 1.19... 500.0 35.0
585 [0.27613000987555486, 0.735281355357066, 1.193... 1000.0 50.0
1599 [0.27650290579305964, 0.736748631479364, 1.196... 300.0 45.0
current_diff \
546 [-0.0006544452283154811, 0.005362647833651479,...
308 [0.006454846788127355, 0.013079204583940296, 0...
1985 [-0.003676480399805726, -0.0031238240060407207...
1150 [0.0009864818937419528, 0.007132567780150367, ...
1354 [0.005818905290180254, 0.012384801883280616, 0...
... ...
517 [-0.0009880997977536055, 0.0021662066218226528...
1913 [-0.004148896270436353, -0.0031221141537915997...
1402 [-0.008251743384697363, -0.007796711681750779,...
585 [0.005867192018373046, 0.012513598026679063, 0...
1599 [-0.006562671898453942, -0.00582735350204544, ...
derivative
546 [0.0, -0.012687407608831691, -0.01269405943970...
308 [0.0, -0.013294672342677671, -0.01330449252423...
1985 [0.0, -0.007222970940629736, -0.00722314079898...
1150 [0.0, -0.012816400433273145, -0.01282259372674...
1354 [0.0, -0.013236211139965093, -0.01324473877031...
... ...
517 [0.0, -0.009824620966440989, -0.00982576267010...
1913 [0.0, -0.007697096663509484, -0.00771783576816...
1402 [0.0, -0.007125346249811315, -0.00712545816528...
585 [0.0, -0.013316720555170747, -0.01332550767503...
1599 [0.0, -0.007405632943273233, -0.00740591956582...
[3159 rows x 8 columns],
mode current \
982 Partial Soiling (6M) [9.20744270094472, 9.194422397339585, 9.181395...
2403 Partial Soiling (1M) [9.215729670026459, 9.208782958532584, 9.20183...
2457 Partial Soiling (6M) [9.207748461504096, 9.19472827135731, 9.181700...
3099 Partial Soiling (1M) [9.2123011775, 9.206447516934828, 9.1994454726...
456 Partial Soiling (6M) [9.205895947108852, 9.192859018813232, 9.17981...
... ... ...
1032 Partial Soiling (1M) [9.210283333095331, 9.204441131746087, 9.19733...
2985 Partial Soiling (1M) [9.214969316893278, 9.20771246203145, 9.200455...
2753 Partial Soiling (1M) [9.2196017576896, 9.212665143862107, 9.2057283...
2015 Cell cracking (4M) [9.211289735739712, 9.202459882066014, 9.19452...
1447 Partial Soiling (1M) [9.21846129632336, 9.211350447604229, 9.204239...
voltage \
982 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
2403 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
2457 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
3099 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
456 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
... ...
1032 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
2985 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
2753 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
2015 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
1447 [0.03, 0.08, 0.13, 0.18000000000000002, 0.23, ...
power E T \
982 [0.2762232810283416, 0.7355537917871667, 1.193... 700.0 50.0
2403 [0.27647189010079376, 0.7367026366826067, 1.19... 400.0 50.0
2457 [0.27623245384512285, 0.7355782617085848, 1.19... 600.0 45.0
3099 [0.276369035325, 0.7365158013547862, 1.1959279... 500.0 55.0
456 [0.27617687841326555, 0.7354287215050586, 1.19... 700.0 40.0
... ... ... ...
1032 [0.27630849999285995, 0.736355290539687, 1.195... 700.0 55.0
2985 [0.2764490795067983, 0.736616996962516, 1.1960... 800.0 35.0
2753 [0.27658805273068804, 0.7370132115089686, 1.19... 300.0 40.0
2015 [0.27633869207219136, 0.7361967905652812, 1.19... 600.0 55.0
1447 [0.2765538388897008, 0.7369080358083383, 1.196... 500.0 35.0
current_diff \
982 [0.0027581535921488154, 0.009108142650418927, ...
2403 [-0.0055288154895904995, -0.005252418542580628...
2457 [0.0024523930327724486, 0.008802268632694066, ...
3099 [-0.0021003229631322284, -0.002916976944824512...
456 [0.004304907428016591, 0.010671521176771392, 0...
... ...
1032 [-8.247855846299501e-05, -0.000910591756083434...
2985 [-0.004768462356409486, -0.0041819220414467395...
2753 [-0.009400903152732454, -0.009134603872103852,...
2015 [-0.0010888812028433392, 0.0010706579239894154...
1447 [-0.008260441786491768, -0.00781990761422513, ...
derivative
982 [0.0, -0.013020303605134842, -0.01302728621376...
2403 [0.0, -0.006946711493874602, -0.00694699702618...
2457 [0.0, -0.013020190146786348, -0.01302736006087...
3099 [0.0, -0.005853660565172447, -0.00700204423561...
456 [0.0, -0.013036928295619532, -0.01304477339346...
... ...
1032 [0.0, -0.0058422013492442915, -0.0071043446507...
2985 [0.0, -0.0072568548618274775, -0.0072569856979...
2753 [0.0, -0.006936613827493332, -0.00693677041243...
2015 [0.0, -0.008829853673697485, -0.00793823468386...
1447 [0.0, -0.0071108487191313685, -0.0071109598167...
[351 rows x 8 columns])