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)")
../../_images/pages_tutorials_tutorial_iv_classifier_10_0.png
../../_images/pages_tutorials_tutorial_iv_classifier_10_1.png
../../_images/pages_tutorials_tutorial_iv_classifier_10_2.png
../../_images/pages_tutorials_tutorial_iv_classifier_10_3.png

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)
../../_images/pages_tutorials_tutorial_iv_classifier_14_0.png
../../_images/pages_tutorials_tutorial_iv_classifier_14_1.png
../../_images/pages_tutorials_tutorial_iv_classifier_14_2.png
[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])