Source code for raw_data

""" Module for reading and compensating data from raw test files produced by the biaxial testing machine
"""

import numpy as np

    
[docs]def read(name, min_num_columns=9, num_rows=0): """Read the raw experiment data file into a numpy array and include additional information from the header. :param name: The path to the file to be read :type name: str :param min_num_columns: The minimum number of floating numbers that a line should be converted to in order to be considered a data line :type min_num_columns: int :param num_rows: How many rows to read. If 0, read all :type num_rows: int :returns: A np.array with test data and an information dictionary containing the test date (key='date') :rtype: tuple( np.array, dict ) If the file would have been formatted nicely, np.loadtxt() would be faster. The comments at the top makes this a bit more difficult. The function detects when the data starts by checking that the line converts into sufficient number of floating point numbers. Thereafter, all lines are assumed to be data lines. """ with open(name, 'r') as fid: headers = [] data = [] num_rows = num_rows if num_rows != 0 else np.inf for line in fid: split_line = line.split() try: data_line = [float(item) for item in split_line] except ValueError: data_line = [] # Couldn't convert => not a data line if len(data_line) >= min_num_columns: data.append(data_line) break else: headers.append(line) row_nr = 1 for line in fid: data.append([float(item) for item in line.split()]) row_nr += 1 if row_nr > num_rows: break info = {'date': 'not_found'} for hl in headers: date_split = hl.split('Date: ') if len(date_split) > 1: info['date'] = date_split[-1].strip() return np.array(data), info
[docs]def compensate(data, cols, od, tstr_sign=0): """ Compensate data wrt. scaling, stiffness and cross-talk :param data: The data matrix to be compensated (as returned from :py:func:`read`) :param cols: Dictionary giving the column number in data. Required keys are (with expected unit in parenthesis) - ``forc``: Axial force [kN] - ``torq``: Torque [Nm] Optional keys are - ``astr``: Axial strain [-] - ``tstr``: Angular strain [rad] (Rotational strain measured by the extensometer, which is the rotation over the gauge length calibrated for a 10 mm bar) - ``disp``: Test bar elongation [mm] - ``rota``: Test bar rotation [rad] - ``acnt``: Axial cycle counter [cycle] (half cycles are counted as 0.5) - ``tcnt``: Torsional cycle counter [cycle] :param od: The outer diameter of the test bar [mm] :param tstr_sign: The sign with which to scale the torsional strain in relation to the torque. -1 if extensometer text upside down, -1 otherwise). If 0 (default), try to automatically detect by correlation with the torque. :returns: The compensated data array, an information string about the compensations and the tstr_sign used :rtype: tuple( np.array, str, int) """ # Compensation values from Meyer et al. (2018) [https://doi.org/10.1016/j.ijsolstr.2017.10.007] k_axial = 198.71e3 # N/mm Machine axial stiffness, to compensate disp values k_torsional = 25920e3 # Nmm/rad Machine torsional stiffness, to compensate rota values torque_per_force = 0.0901 # Nmm/N Cross talk force to torque, note sign change due to reversed rotation axis. # Other parameters ext_cal_dia = 10.0 # mm The diameter for which the extensometer was calibrated. # Automatically determine sign of shear strain scaling if tstr_sign == 0 and 'tstr' in cols: # Remove last 10 % when looking max min to avoid evaluating after failure. n = int(data.shape[0]*0.9) # Find max and min torque i_max = np.argmax(data[:n, cols['torq']]) i_min = np.argmin(data[:n, cols['torq']]) # Get sign of inclination for torque versus shear strain. If positive maintain sign versus torque. tsgn = np.sign((data[i_max, cols['torq']] - data[i_min, cols['torq']]) / (data[i_max, cols['tstr']] - data[i_min, cols['tstr']])) else: tsgn = tstr_sign # Scale channels scale_factors = {'forc': 1000.0, # Convert from kN to N 'torq': -1000.0, # Convert from kNmm to Nmm and switch sign 'rota': -1.0, # Reverse rotation direction 'tstr': -tsgn*ext_cal_dia/od, # Reverse strain and compensate for different outer diameter. 'tcnt': 2, # Counters in half step, double to make integers 'acnt': 2, } for key in scale_factors: if key in cols: data[:, cols[key]] = scale_factors[key]*data[:, cols[key]] # Compensate for machine stiffness if 'disp' in cols: data[:, cols['disp']] -= data[:, cols['forc']]/k_axial if 'rota' in cols: data[:, cols['rota']] -= data[:, cols['torq']]/k_torsional stiffness_comp = '' if all([c in cols for c in ['disp', 'rota']]): stiffness_comp = ('Machine stiffness compensation:\n' + ' disp = disp - forc * ({:0.6e} mm/N)\n'.format(1/k_axial) + ' rota = rota - torq * ({:0.6e} rad/Nmm)\n'.format(1/k_torsional)) # Compensate for cross talk data[:, cols['torq']] -= data[:, cols['forc']]*torque_per_force info = ('' + 'Rotation (torq,rota) reversed from machine\n' + '' if (tstr_sign == 0 or 'tstr' not in cols) else ('tstr_sign = ' + str(tsgn) + '\n') + stiffness_comp # Only add if disp and rota part of data + 'Cross talk compensation:\n' + ' torq = torq - forc * ({:0.4f} Nmm/N)\n'.format(torque_per_force) + 'Reference: https://doi.org/10.1016/j.ijsolstr.2017.10.007\n') return data, info, tsgn