Source code for mhkit.loads.general

from scipy.stats import binned_statistic
import pandas as pd 
import numpy as np
import fatpack

[docs]def bin_statistics(data,bin_against,bin_edges,data_signal=[]): """ Bins calculated statistics against data signal (or channel) according to IEC TS 62600-3:2020 ED1. Parameters ----------- data : pandas DataFrame Time-series statistics of data signal(s) bin_against : array Data signal to bin data against (e.g. wind speed) bin_edges : array Bin edges with consistent step size data_signal : list, optional List of data signal(s) to bin, default = all data signals Returns -------- bin_mean : pandas DataFrame Mean of each bin bin_std : pandas DataFrame Standard deviation of each bim """ assert isinstance(data, pd.DataFrame), 'data must be of type pd.DataFram' try: bin_against = np.asarray(bin_against) except: 'bin_against must be of type np.ndarray' try: bin_edges = np.asarray(bin_edges) except: 'bin_edges must be of type np.ndarray' # Determine variables to analyze if len(data_signal)==0: # if not specified, bin all variables data_signal=data.columns.values else: assert isinstance(data_signal, list), 'must be of type list' # Pre-allocate list variables bin_stat_list = [] bin_std_list = [] # loop through data_signal and get binned means for signal_name in data_signal: # Bin data bin_stat = binned_statistic(bin_against,data[signal_name], statistic='mean',bins=bin_edges) # Calculate std of bins std = [] stdev = pd.DataFrame(data[signal_name]) stdev.set_index(bin_stat.binnumber,inplace=True) for i in range(1,len(bin_stat.bin_edges)): try: temp = stdev.loc[i].std(ddof=0) std.append(temp[0]) except: std.append(np.nan) bin_stat_list.append(bin_stat.statistic) bin_std_list.append(std) # Convert to DataFrames bin_mean = pd.DataFrame(np.transpose(bin_stat_list),columns=data_signal) bin_std = pd.DataFrame(np.transpose(bin_std_list),columns=data_signal) # Check for nans if bin_mean.isna().any().any(): print('Warning: some bins may be empty!') return bin_mean, bin_std
[docs]def blade_moments(blade_coefficients,flap_offset,flap_raw,edge_offset,edge_raw): ''' Transfer function for deriving blade flap and edge moments using blade matrix. Parameters ----------- blade_coefficients : numpy array Derived blade calibration coefficients listed in order of D1, D2, D3, D4 flap_offset : float Derived offset of raw flap signal obtained during calibration process flap_raw : numpy array Raw strain signal of blade in the flapwise direction edge_offset : float Derived offset of raw edge signal obtained during calibration process edge_raw : numpy array Raw strain signal of blade in the edgewise direction Returns -------- M_flap : numpy array Blade flapwise moment in SI units M_edge : numpy array Blade edgewise moment in SI units ''' try: blade_coefficients = np.asarray(blade_coefficients) except: 'blade_coefficients must be of type np.ndarray' try: flap_raw = np.asarray(flap_raw) except: 'flap_raw must be of type np.ndarray' try: edge_raw = np.asarray(edge_raw) except: 'edge_raw must be of type np.ndarray' assert isinstance(flap_offset, (float,int)), 'flap_offset must be of type int or float' assert isinstance(edge_offset, (float,int)), 'edge_offset must be of type int or float' # remove offset from raw signal flap_signal = flap_raw - flap_offset edge_signal = edge_raw - edge_offset # apply matrix to get load signals M_flap = blade_coefficients[0]*flap_signal + blade_coefficients[1]*edge_signal M_edge = blade_coefficients[2]*flap_signal + blade_coefficients[3]*edge_signal return M_flap, M_edge
[docs]def damage_equivalent_load(data_signal, m, bin_num=100, data_length=600): ''' Calculates the damage equivalent load of a single data signal (or channel) based on IEC TS 62600-3:2020 ED1. 4-point rainflow counting algorithm from fatpack module is based on the following resources: - `C. Amzallag et. al. Standardization of the rainflow counting method for fatigue analysis. International Journal of Fatigue, 16 (1994) 287-293` - `ISO 12110-2, Metallic materials - Fatigue testing - Variable amplitude fatigue testing.` - `G. Marsh et. al. Review and application of Rainflow residue processing techniques for accurate fatigue damage estimation. International Journal of Fatigue, 82 (2016) 757-765` Parameters: ----------- data_signal : array Data signal being analyzed m : float/int Fatigue slope factor of material bin_num : int Number of bins for rainflow counting method (minimum=100) data_length : float/int Length of measured data (seconds) Returns -------- DEL : float Damage equivalent load (DEL) of single data signal ''' try: data_signal = np.array(data_signal) except: 'data_signal must be of type np.ndarray' assert isinstance(m, (float,int)), 'm must be of type float or int' assert isinstance(bin_num, (float,int)), 'bin_num must be of type float or int' assert isinstance(data_length, (float,int)), 'data_length must be of type float or int' rainflow_ranges = fatpack.find_rainflow_ranges(data_signal,k=256) # Range count and bin Nrf, Srf = fatpack.find_range_count(rainflow_ranges, bin_num) DELs = Srf**m * Nrf / data_length DEL = DELs.sum() ** (1/m) return DEL