├── Supycap ├── cc_analysis │ ├── cccap │ │ ├── __init__.py │ │ ├── __pycache__ │ │ │ ├── cc_cap.cpython-37.pyc │ │ │ ├── __init__.cpython-37.pyc │ │ │ └── utilities.cpython-37.pyc │ │ ├── utilities.py │ │ └── cc_cap.py │ ├── __pycache__ │ │ ├── __init__.cpython-37.pyc │ │ ├── supercap.cpython-37.pyc │ │ ├── utilities.cpython-37.pyc │ │ ├── glob_analysis.cpython-37.pyc │ │ └── load_capacitor.cpython-37.pyc │ ├── __init__.py │ ├── utilities.py │ ├── load_capacitor.py │ ├── glob_analysis.py │ └── supercap.py ├── cv_analysis │ ├── __init__.py │ ├── __pycache__ │ │ ├── cv_calc.cpython-37.pyc │ │ ├── __init__.cpython-37.pyc │ │ ├── utilities.cpython-37.pyc │ │ └── cv_analysis.cpython-37.pyc │ ├── cv_analysis.py │ ├── utilities.py │ └── cv_calc.py ├── __pycache__ │ ├── __init__.cpython-37.pyc │ ├── supercap.cpython-37.pyc │ ├── utilities.cpython-37.pyc │ ├── glob_analysis.cpython-37.pyc │ └── load_capacitor.cpython-37.pyc └── __init__.py ├── requirements.txt ├── setup.py ├── LICENSE.txt └── README.md /Supycap/cc_analysis/cccap/__init__.py: -------------------------------------------------------------------------------- 1 | from .cc_cap import* 2 | from .utilities import* -------------------------------------------------------------------------------- /Supycap/cv_analysis/__init__.py: -------------------------------------------------------------------------------- 1 | from .cv_calc import* 2 | from .cv_analysis import* 3 | from .utilities import* -------------------------------------------------------------------------------- /Supycap/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/__pycache__/supercap.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/__pycache__/supercap.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/__pycache__/utilities.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/__pycache__/utilities.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/__pycache__/glob_analysis.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/__pycache__/glob_analysis.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/__pycache__/load_capacitor.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/__pycache__/load_capacitor.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/__init__.py: -------------------------------------------------------------------------------- 1 | name = 'Supercap_analysis' 2 | 3 | from .cc_analysis import* 4 | from .cv_analysis import* 5 | 6 | 7 | __version__ ='27.09.2020' -------------------------------------------------------------------------------- /Supycap/cv_analysis/__pycache__/cv_calc.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cv_analysis/__pycache__/cv_calc.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/cc_analysis/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cc_analysis/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/cc_analysis/__pycache__/supercap.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cc_analysis/__pycache__/supercap.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/cc_analysis/__pycache__/utilities.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cc_analysis/__pycache__/utilities.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/cv_analysis/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cv_analysis/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/cv_analysis/__pycache__/utilities.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cv_analysis/__pycache__/utilities.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/cc_analysis/cccap/__pycache__/cc_cap.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cc_analysis/cccap/__pycache__/cc_cap.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/cv_analysis/__pycache__/cv_analysis.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cv_analysis/__pycache__/cv_analysis.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/cc_analysis/__init__.py: -------------------------------------------------------------------------------- 1 | from .supercap import * 2 | from .load_capacitor import * 3 | from .glob_analysis import * 4 | from .cccap import * 5 | from .utilities import* -------------------------------------------------------------------------------- /Supycap/cc_analysis/__pycache__/glob_analysis.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cc_analysis/__pycache__/glob_analysis.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/cc_analysis/__pycache__/load_capacitor.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cc_analysis/__pycache__/load_capacitor.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/cc_analysis/cccap/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cc_analysis/cccap/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /Supycap/cc_analysis/cccap/__pycache__/utilities.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaYuanChen/Supycap/HEAD/Supycap/cc_analysis/cccap/__pycache__/utilities.cpython-37.pyc -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | To run the library, the following libraries need to be pre-installed: 2 | 3 | scipy, 4 | matplotlib, 5 | numpy, 6 | IPython, 7 | glob, 8 | functools, 9 | datetime. -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools as setuptools 2 | import re 3 | from os.path import join 4 | 5 | 6 | 7 | 8 | with open("README.md", "r") as fh: 9 | long_description = fh.read() 10 | 11 | setuptools.setup( 12 | name="Supycap", 13 | version= '2.2', 14 | author="Ada Yuan Chen", 15 | author_email="yuan.chen18@imperial.ac.uk", 16 | description="A python library for electrochemical analysis of supercapacitors", 17 | long_description=long_description, 18 | long_description_content_type="text/markdown", 19 | url="https://github.com/AdaYuanChen/Supycap", 20 | packages=setuptools.find_packages(), 21 | install_requires=( 22 | 'scipy', 23 | 'matplotlib', 24 | 'numpy', 25 | 'pandas', 26 | 'IPython', 27 | 'sklearn', 28 | 'datetime', 29 | ), 30 | include_package_data = True, 31 | platforms = 'any', 32 | classifiers=[ 33 | "Programming Language :: Python :: 3", 34 | "License :: OSI Approved :: MIT License", 35 | "Operating System :: OS Independent", 36 | ], 37 | ) -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Supycap/cc_analysis/cccap/utilities.py: -------------------------------------------------------------------------------- 1 | from numpy import* 2 | 3 | #Capacitance timed 2 for symmetrical capacitor, given that the graident is obtained from the decreasing slope 4 | #Recieve current in A and mass in g 5 | def Cap_calc(grad, I, m1, m2): 6 | return (m1 + m2)*I/(m1*m2*-1*grad) 7 | 8 | 9 | def Cap_norm(grad, I,): 10 | return I/(-1*grad) 11 | 12 | 13 | #Calculating the capacitance given a list of gradients 14 | #Recieve current in A and mass in g 15 | def Cap_ls(gradient_ls, current, m1=False , m2=False, cap_grav=True): 16 | if cap_grav is True: 17 | cap_ls = [Cap_calc(i, current, m1, m2) for i in gradient_ls] 18 | 19 | elif m1 is False and m2 is False: 20 | cap_ls = [Cap_norm(i, current,) for i in gradient_ls] 21 | 22 | else: 23 | cap_ls = [Cap_norm(i, current) for i in gradient_ls] 24 | 25 | return cap_ls 26 | 27 | 28 | #finding the intersect between a slope and a vertical line (3 methods available) 29 | #method 0 (no longer used!!) 30 | def Intersect(grad, intc, pk): 31 | return grad*pk+intc 32 | 33 | 34 | #method 1 (first n point), by default the first 1 point after the peak are taken 35 | def ConstantPoints(V_ls, pk_index, set_n = False): 36 | if set_n is False: 37 | dv = V_ls[pk_index]-V_ls[pk_index + 1] 38 | 39 | else: 40 | dv =V_ls[pk_index]-V_ls[pk_index + set_n] 41 | 42 | return dv 43 | 44 | 45 | #method 2 (2nd derivative cut off point) 46 | def ConstantDeriv(xset, yset, pk_index, tr_index, set_deriv = False,): 47 | #calculaltion for first and second derivative 48 | dy = diff(yset[pk_index:tr_index], 1) 49 | dx = diff(xset[pk_index:tr_index], 1) 50 | dV1=dy/dx 51 | dt1 = 0.5*(xset[pk_index:tr_index][:-1]+xset[pk_index:tr_index][1:]) 52 | 53 | dy2 = diff(dV1, 1) 54 | dx2 = diff(dt1, 1) 55 | dV2=dy2/dx2 56 | dt2 = 0.5*(dx[:-1]+dx[1:]) 57 | 58 | if set_deriv is False: 59 | deriv = 1 60 | else: 61 | deriv = set_deriv 62 | 63 | num_pt=0 64 | for i in range(0, len(dV2)): 65 | if dV2[i] > deriv: 66 | num_pt = i 67 | 68 | dv = yset[pk_index] - yset[pk_index + 1 + num_pt] 69 | 70 | return dv 71 | 72 | 73 | #receive current in A 74 | def ESR_calc(dv, current): 75 | return dv/(2*current) 76 | 77 | 78 | #calculate average ESR 79 | #receive current in A 80 | def ESR_ls(esr_ls, current): 81 | if esr_ls == False: 82 | return False 83 | 84 | else: 85 | esr=[ESR_calc(i, current) for i in esr_ls] 86 | 87 | return esr 88 | 89 | def Half_pt_ind(lst, half_value): 90 | for i, x in enumerate(lst): 91 | if x deriv: 115 | num_pt = i 116 | 117 | return dt2, dV2, num_pt 118 | -------------------------------------------------------------------------------- /Supycap/cc_analysis/utilities.py: -------------------------------------------------------------------------------- 1 | from numpy import* 2 | import pandas as pd 3 | 4 | def Fast_load(path, skip_header, t_set = False, V_set = False, delimiter = False): 5 | if t_set is False: 6 | t_set = 0 7 | elif t_set is True: 8 | t_set = input('Please enter the index of the coloumn for x values (starting from zero) or the name of the coloumn (for csv files only):') 9 | else: 10 | pass 11 | 12 | if V_set is False: 13 | V_set = 1 14 | elif V_set is True: 15 | V_set = input('Please enter the index of the coloumn for y values (starting from zero) or the name of the coloumn (for csv files only):') 16 | else: 17 | pass 18 | 19 | 20 | if '.txt' in path: 21 | if delimiter == False: 22 | delimiter = None 23 | elif delimiter == True: 24 | delimiter = input('Please enter the delimiter') 25 | else: 26 | pass 27 | 28 | try: 29 | t_set = int(t_set) 30 | V_set = int(V_set) 31 | except: 32 | print('The indices for the x and y coloumns have to be integers!') 33 | t_set = int(input('Please enter the index of the x coloumn (an INTEGER starting from zero)')) 34 | V_set = int(input('Please enter the index of the y coloumn (an INTEGER starting from zero)')) 35 | with open (path, 'r') as f: 36 | file = [i.split(delimiter) for i in f][skip_header:] 37 | xset = [float(i[t_set]) for i in file] 38 | xset = array(xset) 39 | yset = [float(i[V_set]) for i in file] 40 | yset = array(yset) 41 | 42 | elif '.csv' in path: 43 | if delimiter == False: 44 | delimiter = ',' 45 | elif delimiter == True: 46 | delimiter = input('Please enter the delimiter') 47 | else: 48 | pass 49 | 50 | file = pd.read_csv(path, skiprows = skip_header-1, delimiter = delimiter) 51 | try: 52 | indices = [int(t_set), int(V_set)] 53 | xset = pd.file.iloc[:, indices[0]].to_numpy() 54 | yset = pd.file.iloc[:,indices[1]].to_numpy() 55 | except: 56 | indices = [t_set, V_set] 57 | xset = pd.file[indices[0]].to_numpy() 58 | yset = pd.file[indices[1]].to_numpy() 59 | 60 | else: 61 | print('Unsupported format. The program only supports documents in txt and csv formats.') 62 | 63 | return xset, yset 64 | 65 | 66 | #Read the current value in a file name. 67 | #In the filename, the current is stated at the very front of the file 68 | #current needs to be seperated from other elements of the filename and/or seperated by '_' and '/' 69 | #current needs to end with '_mA' 70 | def Readcurrent(filename): 71 | for i in range(len(filename)-1): 72 | if filename[i] + filename[i+1] == 'mA': 73 | k = i-2 74 | while filename[k] != '_' and filename[k] != '/' and filename[k] != '\\' and filename[k] != ' ' and k >= 0: 75 | k -= 1 76 | return float(filename[k+1:i-1]) 77 | 78 | return False 79 | 80 | 81 | #calculate mass errors as the major source of uncertainties in capacitance 82 | #error analysis: only uncertainty from mass is considered as other errors are insignificant compare to this 83 | def delt_m(m_1, m_2): 84 | m1 = mean (m_1) 85 | m2 = mean (m_2) 86 | d1 = std (m_1) 87 | d2 = std (m_2) 88 | p1 = d1/m1 89 | p2 = d2/m2 90 | d1p2_1p2 = (d1**2 + d2**2)**0.5/(m1 + m2) 91 | d1t2_1t2 = (p1**2 + p2**2)**0.5 92 | return (d1t2_1t2**2 + d1p2_1p2**2)**0.5 93 | 94 | def Round_ls(ls, rounding): 95 | return [round(i, rounding) for i in ls] 96 | 97 | -------------------------------------------------------------------------------- /Supycap/cv_analysis/cv_analysis.py: -------------------------------------------------------------------------------- 1 | from ..cc_analysis.utilities import Fast_load 2 | from .cv_calc import* 3 | 4 | def CV_analysis(pathway, m1 = False, m2 = False, scan_r = False, row_skip = False, V_set = False, I_set = False, delimiter = False, int_method = False, calc_method = False): 5 | """ 6 | Calculate the gravimetric capacitance from every cycle of CV scans and output a list of calculated capacitance (F g^-1) for all cycles. 7 | 8 | Notes 9 | ----- 10 | UNITS: current(mA), voltage (V), scan rate (mV/s), mass of the electrodes (mg), and capacitance (F g^-1). 11 | The scan rate (mV/s) will be directly read from the filename (i.e. the fielname has to include the current followed by '_mvs' and seperated by '_', '/' or it is the first component of the filename). 12 | 13 | Parameters 14 | ---------- 15 | pathway : :class:`str` 16 | The path in which the data files are located. 17 | The scan rate of each file has to be specified and seperated by either '/' or '_' and followed by '_mvs' at the end, otherwise the scan rate needs to be input as scan_r 18 | Example: './CV_folder/1_mvs_0.8_V_CV.txt' 19 | 20 | m1 : :class:`float` 21 | The mass of electrode 1 of the supercapacitor. The mass is in mg. 22 | 23 | m2 : :class:`float` 24 | The mass of electrode 2 of the supercapacitor. The mass is in mg. 25 | 26 | scan_r : :class:`float`, optional 27 | The scan rate for the CV measurement in mV/s. If scan_r = False, the program will attempt to extract the scan rate from the file name, given that the scan rate is seperated from other elements of the filename and/or seperated by '_' and/or '/' and that it ends with '_mvs'. 28 | 29 | row_skip : :class:`int`, optional 30 | The number of rows of headers to skip in the text files. 31 | row_skip = False (row_skip = 1) 32 | = : :class:`int` (The specified number of rows will be skipped for all files in the path) 33 | 34 | x_name : :class:`int`/`str`, optional 35 | Specify the coloumn index for the voltage(V) data, coloumn 0 being the first coloumn starting from the left 36 | x_name = False (t_set = 0) 37 | True (The prompt will ask for the column index to be entered) 38 | : :class: `int` (specify the coloumn which will be used as current) 39 | 40 | y_name : :class:`int`/`str`, optional 41 | Specify the coloumn index for the current(mA) data, coloumn 0 being the first coloumn starting from the left 42 | y_name = False (V_set = 0) 43 | True (The prompt will ask for the column index to be entered) 44 | : :class: `int` (specify the coloumn which will be used as voltage) 45 | 46 | delimiter : :class:`str`, optional 47 | The symbol which seperates one data coloumn from the other. If delimiter = False, the delimiter is assumed to be space ''. 48 | 49 | int_method : :class:`int`, optional 50 | The method for integration for the enclosed area. 51 | int_method = False or 1 (Integration using the trapezoidal rule, discharging curve only) 52 | = 102 (Integration using the trapezoidal rule, charging and discharging) 53 | = 2 (Integration using the Simpson's rule, discharging curve only) 54 | = 202 (Integration using the Simpson's rule, charging and discharging) 55 | 56 | 57 | returns 58 | ------- 59 | : :class:`list 60 | A list of capacitance calculated from each CV cycle. 61 | """ 62 | 63 | if scan_r is False: 64 | scan_r = Read_scan_r(pathway) 65 | if scan_r is False: 66 | print('Missing scan rate value. Please enter the scan rate for the CV analysis in mV/s') 67 | return None 68 | else: 69 | pass 70 | 71 | 72 | if row_skip is False: 73 | row_skip = 1 74 | elif row_skip is True: 75 | row_skip = int(input('Please enter the number of header row(s) in this file:')) 76 | else: 77 | pass 78 | 79 | if type(m1) is list: 80 | m1 = mean(m1) 81 | m2 = mean(m2) 82 | 83 | 84 | CV_raw = Fast_load(pathway, skip_header = row_skip, t_set = V_set, V_set = I_set, delimiter = delimiter) 85 | x = CV_raw[0] 86 | y = CV_raw[1] 87 | 88 | return CV_calc(x, y, m1, m2, scan_r, int_method = int_method, calc_method = calc_method) -------------------------------------------------------------------------------- /Supycap/cv_analysis/utilities.py: -------------------------------------------------------------------------------- 1 | from scipy.integrate import simps 2 | from sklearn.metrics import auc 3 | from scipy.signal import find_peaks 4 | from numpy import* 5 | 6 | #Read the scan rate in a file name. 7 | #In the filename, the scan rate is stated at the very front of the file, OR 8 | #the scan rate seperated from other elements of the filename and/or seperated by '_' and/or '/' 9 | #the scan rate needs to end with '_mvs' 10 | def Read_scan_r(filename): 11 | for i in range(len(filename)-2): 12 | if filename[i:i+3] == 'mvs' or filename[i:i+3] == 'mVs': 13 | k = i-2 14 | while filename[k] != '_' and filename[k] != '/' and filename[k] != '\\' and filename[k] != ' ' and k >= 0: 15 | k -= 1 16 | return float(filename[k+1:i-1]) 17 | return False 18 | 19 | 20 | def Pos_split(x, y): 21 | 22 | x_split1=[] 23 | y_split1=[] 24 | x_split2=[] 25 | y_split2=[] 26 | 27 | i=0 28 | max_x = max(x) 29 | while x[i] < max_x: 30 | i += 1 31 | 32 | x_split2 = x[:i] 33 | y_split2 = y[:i] 34 | x_split1 = x[i:] 35 | y_split1 = y[i:] 36 | 37 | return x_split1, y_split1, x_split2, y_split2 38 | 39 | 40 | def Neg_split(x, y): 41 | 42 | x_split1=[] 43 | y_split1=[] 44 | x_split2=[] 45 | y_split2=[] 46 | 47 | i=0 48 | while x[i] < max(x): 49 | i += 1 50 | 51 | x_split1 = x[:i] 52 | y_split1 = y[:i] 53 | x_split2 = x[i:] 54 | y_split2 = y[i:] 55 | 56 | return x_split1, y_split1, x_split2, y_split2 57 | 58 | 59 | def Trapz_area2(x_split1, y_split1, x_split2, y_split2): 60 | 61 | try: 62 | status = 0 63 | bigger_area = auc(x_split2, y_split2) 64 | smaller_area = auc(x_split1, y_split1) 65 | 66 | except: 67 | status = 1 68 | x_split2 = linspace(x_split2[0], x_split2[-1], len(x_split2)) 69 | x_split1 = linspace(x_split1[0], x_split1[-1], len(x_split1)) 70 | bigger_area = auc(x_split2, y_split2) 71 | smaller_area = auc(x_split1, y_split1) 72 | 73 | return bigger_area-smaller_area, status 74 | 75 | def Trapz_area(x_split1, y_split1, x_split2, y_split2): 76 | 77 | try: 78 | status = 0 79 | bigger_area = auc(x_split2, y_split2) 80 | smaller_area = auc(x_split1, y_split1) 81 | 82 | except: 83 | status = 1 84 | x_split2 = linspace(x_split2[0], x_split2[-1], len(x_split2)) 85 | x_split1 = linspace(x_split1[0], x_split1[-1], len(x_split1)) 86 | bigger_area = auc(x_split2, y_split2) 87 | smaller_area = auc(x_split1, y_split1) 88 | 89 | return bigger_area + smaller_area, status 90 | 91 | 92 | def Simps_area2(x_split1, y_split1, x_split2, y_split2): 93 | 94 | dx1 =(max(x_split1)-min(x_split1))/len(x_split1) 95 | dx2 =(max(x_split2)-min(x_split2))/len(x_split2) 96 | area2 = simps(y_split2, dx=dx2) 97 | area1 = simps(y_split1, dx=dx1) 98 | 99 | return area2 - area1 100 | 101 | 102 | def Simps_area(x_split1, y_split1, x_split2, y_split2): 103 | 104 | dx1 =(max(x_split1)-min(x_split1))/len(x_split1) 105 | dx2 =(max(x_split2)-min(x_split2))/len(x_split2) 106 | area2 = simps(y_split2, dx=dx2) 107 | area1 = simps(y_split1, dx=dx1) 108 | 109 | return area2 + area1 110 | 111 | 112 | def Load_cycle(CV_x, CV_y): 113 | mini, _= find_peaks(-CV_x, prominence = 0.1) 114 | 115 | comb_ls = [] 116 | cycle_xls=[] 117 | cycle_yls=[] 118 | 119 | for i in range(len(mini)-1): 120 | comb_ls += [[mini[i],mini[i+1]]] 121 | 122 | for i in comb_ls: 123 | cycle_xls += [CV_x[i[0]:i[1]]] 124 | cycle_yls += [CV_y[i[0]:i[1]]] 125 | return cycle_xls, cycle_yls, len(cycle_xls) 126 | 127 | 128 | 129 | 130 | def Pn_slice(cycle_xls, cycle_yls, cycle_n): 131 | y_pos = [] 132 | x_pos = [] 133 | y_neg = [] 134 | x_neg = [] 135 | 136 | for i in range(cycle_n): 137 | cond_p = [yi > 0 for yi in cycle_yls[i]] 138 | y_pos += [cycle_yls[i][cond_p]] 139 | x_pos += [cycle_xls[i][cond_p]] 140 | 141 | cond_n = [yi < 0 for yi in cycle_yls[i]] 142 | y_neg += [cycle_yls[i][cond_n]] 143 | x_neg += [cycle_xls[i][cond_n]] 144 | 145 | return x_pos, y_pos, x_neg, y_neg, cycle_n 146 | 147 | 148 | ###scan rate in mv/s and mass in mg!!! 149 | def CV_cap_cal(Integrated, m1, m2, scan_r, potential_r): 150 | return 1000 * Integrated * (m1 + m2) / (m1*m2*scan_r*potential_r) 151 | 152 | #calculation for non-gravimetric capacitance 153 | def CV_non_grav(Integrated, scan_r, potential_r): 154 | return Integrated / (scan_r*potential_r) 155 | 156 | def CV_capacity(Integrated, m1, m2): 157 | return Integrated * (m1 + m2) / ((m1*m2)*2) -------------------------------------------------------------------------------- /Supycap/cv_analysis/cv_calc.py: -------------------------------------------------------------------------------- 1 | from .utilities import* 2 | 3 | 4 | ###y in mA, voltage in V, scan rate in mv/s!!! 5 | #first cycle and last cycle are omitted as long as they are incomplete 6 | 7 | def CV_calc(x, y, m1, m2, scan_r, int_method = False, calc_method = False): 8 | """ 9 | Calculate the gravimetric capacitance from every cycle of CV scans and output a list of calculated capacitance (F g^-1) for all cycles. 10 | 11 | Notes 12 | ----- 13 | For the CV data, the unit is mA for current, V for voltage and mV/s for scan rate. The mass of the electrodes should be recorded in mg. The gravimetric capacitance is output in F g^-1. 14 | 15 | Parameter 16 | ---------- 17 | x : :class:`numpy.ndarray` 18 | The voltage readings in V. 19 | 20 | y : :class:`numpy.ndarray` 21 | The current readings in mA. 22 | 23 | m1 : :class:`float` 24 | The mass of electrode 1 of the supercapacitor. The mass is in mg. 25 | 26 | m2 : :class:`float` 27 | The mass of electrode 2 of the supercapacitor. The mass is in mg. 28 | 29 | scan_r : :class:`float` 30 | The scan rate for the CV measurement in mV/s. 31 | 32 | int_method : :class:`bool` or `int`, optional 33 | The method used for integration (Trapezoidal or Simpsons's rules) 34 | int_method = False or 1 (Integration using the Simpson's rule, discharging curve only) 35 | int_method = 102 (Integration using the Simpson's rule, charging and discharging) 36 | int_method = 2 (Integration using the trapezoidal rule, discharging curve only) 37 | int_method = 202 (Integration using the trapezoidal rule, charging and discharging) 38 | 39 | calc_method : :class:`int`, optional 40 | The method which determines whether capacitance or capacity (enclosed area divided by mass) is being calculated 41 | calc_method = 1 (capacitance is calculated) 42 | calc_method = 2 (capacity is calculated by dividng the enclosed area by ) 43 | 44 | Return 45 | ------ 46 | A list of gravimetric capacitance calculated from each CV cycle. 47 | 48 | """ 49 | 50 | if int_method is False: 51 | int_method = 1 52 | elif int_method is True: 53 | int_method = int(input('Please select the method for integration (1, 102, 2 or 202):')) 54 | else: 55 | pass 56 | 57 | if calc_method is 2 and int_method is 1: 58 | print('Capacity calculation requires the entire enclosed area. int_method is changed to 102') 59 | int_method = 102 60 | elif calc_method is 2 and int_method is 2: 61 | print('Capacity calculation requires the entire enclosed area. int_method is changed to 202') 62 | int_method = 202 63 | else: 64 | pass 65 | 66 | y = array(y) 67 | cycles = Load_cycle(x,y) 68 | potential_r = (max(x)-min(x)) 69 | #print('potential range: ', potential_r) 70 | x_pos, y_pos, x_neg, y_neg, cycle_n = Pn_slice(cycles[0], cycles[1], cycles[2]) 71 | print(cycle_n, ' CV cycles are being analysed using integration method', int_method) 72 | 73 | area_ls = [] 74 | sta = 0 75 | if int_method is False or int_method is 1: 76 | for i in range(cycle_n): 77 | pox1, poy1, pox2, poy2 = Pos_split(x_pos[i], y_pos[i]) 78 | nex1, ney1, nex2, ney2 = Neg_split(x_neg[i], y_neg[i]) 79 | a = Simps_area(pox1, poy1, nex2, ney2) 80 | area_ls += [-a] 81 | 82 | elif int_method is 102: 83 | for i in range(cycle_n): 84 | pox1, poy1, pox2, poy2 = Pos_split(x_pos[i], y_pos[i]) 85 | nex1, ney1, nex2, ney2 = Neg_split(x_neg[i], y_neg[i]) 86 | a2 = Simps_area2(pox1, poy1, pox2, poy2) 87 | a1 = Simps_area2(nex1, ney1, nex2, ney2) 88 | area_ls += [(a2-a1)/2] 89 | 90 | elif int_method is 2: 91 | for i in range(cycle_n): 92 | pox1, poy1, pox2, poy2 = Pos_split(x_pos[i], y_pos[i]) 93 | nex1, ney1, nex2, ney2 = Neg_split(x_neg[i], y_neg[i]) 94 | a, sta1 = Trapz_area(pox1, poy1, nex2, ney2) 95 | area_ls += [-a] 96 | sta += sta1 97 | 98 | if sta != 0: 99 | print('slicing of x values has been unccessful for', sta/2, ' out of the total', cycle_n, 'cycles') 100 | print('x values are assumed to be evenly spaced from minimum to maximum voltage for those cycles') 101 | 102 | else: 103 | pass 104 | 105 | elif int_method is 202: 106 | for i in range(cycle_n): 107 | pox1, poy1, pox2, poy2 = Pos_split(x_pos[i], y_pos[i]) 108 | nex1, ney1, nex2, ney2 = Neg_split(x_neg[i], y_neg[i]) 109 | a2, sta2 = Trapz_area2(pox1, poy1, pox2, poy2) 110 | a1, sta1 = Trapz_area2(nex1, ney1, nex2, ney2) 111 | area_ls += [(a2-a1)/2] 112 | sta += sta2 + sta1 113 | 114 | if sta != 0: 115 | print('slicing of x values has been unccessful for', sta/2, ' out of the total', cycle_n, 'cycles') 116 | print('x values are assumed to be evenly spaced from minimum to maximum voltage for those cycles') 117 | 118 | else: 119 | pass 120 | 121 | else: 122 | method = int(input('''Integration method has to be either 1 (Simpson's, discharging only), 102 (Simpson's, charging and discharging), 2 (trapezoidal, discharging only), or 202 (trapezoidal, charging and discharging)''')) 123 | CV_analysis(x,y,method = method) 124 | 125 | if calc_method is 2: 126 | print('Capacity is returned') 127 | CV_ls = [round(CV_capacity(i, m1, m2), 1) for i in area_ls] 128 | 129 | elif m1 is False or m2 is False: 130 | print('Non-gravimetric capacitance is returned.') 131 | CV_ls = [round(CV_non_grav(i, scan_r, potential_r), 1) for i in area_ls] 132 | 133 | else: 134 | print('Gravimetric capacitance is returned.') 135 | CV_ls = [round(CV_cap_cal(i, m1, m2, scan_r, potential_r), 1) for i in area_ls] 136 | 137 | return CV_ls 138 | -------------------------------------------------------------------------------- /Supycap/cc_analysis/cccap/cc_cap.py: -------------------------------------------------------------------------------- 1 | from scipy.signal import find_peaks 2 | from numpy import* 3 | 4 | from .utilities import ConstantDeriv, ConstantPoints, ESR_ls, Cap_ls, Half_pt_ind 5 | 6 | 7 | #Capacitance analysis (given x and y dataset, current and masses) 8 | #Recieve current in mA and mass in mg and convert to A and g for calculations 9 | def CC_Cap(xset, yset, current, m1 = False, m2 = False, ESR_method = True, setting = False, cap_method = False, filename = False, cap_grav = True): 10 | """ 11 | Data manipulation 12 | 13 | 14 | Notes 15 | ----- 16 | Capacitance and ESR analysis 17 | 18 | Parameters 19 | ---------- 20 | xset : :class:`list` 21 | List of time reading 22 | 23 | yset : :class:`list` 24 | List of corresponding voltage reading 25 | 26 | current : :class:`float` 27 | The current under which the GCD is operated. The current is in mA. 28 | 29 | m1 : :class:`float`, optional 30 | The mass of electrode 1 of the supercapacitor. The mass is in mg. 31 | 32 | m2 : :class:`float`, optional 33 | The mass of electrode 2 of the supercapacitor. The mass is in mg. 34 | 35 | ESR_method : :class:`int`, optional 36 | The method for ESR analysis. 37 | ESR_method = 1 (default constant point analyis using the first point after the peak for calculating voltage drop) 38 | = 101 (constant point analysis using the nth point after the peak, where n is specified using setting) 39 | = 2 or True (default constant second derivative method using the point where the second derivative is greater than 1) 40 | = 201 (constant second derivative method where the cut off derivative is specified using setting) 41 | 42 | setting : :class:`float`, optional 43 | The setting for ESR analysis 44 | setting = False for ESR_method = 1, 2 or True 45 | setting = nth point/cut off second derivative depending on the ESR_method 46 | 47 | cap_method : :class:`int`, optional 48 | The method for capacitance analysis 49 | cap_method = 1 (default method where the lower voltage range is used) 50 | = 2 (upper voltage range is used) 51 | 52 | 53 | filename : :class:`string`, optional 54 | Name of the text file being analysed 55 | 56 | 57 | cap_grav : :class:`bool` 58 | cap_grav = False, output non-gravimetric capacitance 59 | cap_grav = True, output gravimetric capacitance 60 | 61 | returns 62 | ------- 63 | : :class:`list, list, list, list, int` 64 | [list of capacitance], [list of ESR], [list of peak indices], [list of trough indices], number of cycles 65 | 66 | 67 | """ 68 | 69 | if filename != False: 70 | print('The file currently being analysed is:', filename) 71 | 72 | else: 73 | pass 74 | 75 | 76 | 77 | troughs, _= find_peaks(-yset, prominence=(0.5)) 78 | peaks, _= find_peaks(yset, prominence=(0.5)) 79 | N_cycle=0 80 | 81 | #Checking the number of cycle(s) 82 | if len(peaks) == len(troughs): 83 | N_cycle = len(peaks) 84 | 85 | else: 86 | peaks = peaks[:-1] 87 | if len(peaks) == len(troughs): 88 | N_cycle = len(peaks) 89 | else: 90 | print('Error! The number of peaks cannot match the number of troughs') 91 | 92 | 93 | mid_ind = [Half_pt_ind(yset[peaks[i]:troughs[i]],(yset[peaks[i]]+yset[troughs[i]])/2) for i in range(len(peaks))] 94 | 95 | peak_step = int(floor(len(peaks)/20))+1 96 | ave_peak = mean(yset[peaks[::peak_step]]) 97 | ave_trough = mean(yset[troughs[::peak_step]]) 98 | ave_length = ave_peak-ave_trough 99 | 100 | cc_grad = [] 101 | faulty_cyc_ind = [] 102 | for i in range(len(peaks)): 103 | if i<=10: 104 | sel_peaks = peaks[:10] 105 | ave_len = mean([len(xset[peaks[k]:troughs[k]]) for k in range(len(sel_peaks))]) 106 | else: 107 | ave_len = mean([len(xset[peaks[k]:troughs[k]]) for k in range(i-10, i)]) 108 | 109 | if len(xset[peaks[i]:troughs[i]]) < ave_len*0.5: 110 | faulty_cyc_ind += [i] 111 | print('Cycle ' + str(i+1)+ ' has insufficient data points (50% less than average). Skipped for capacitance calculation') 112 | 113 | elif len(xset[peaks[i]:troughs[i]]) > ave_len*1.5: 114 | faulty_cyc_ind += [i] 115 | print('Cycle ' + str(i+1)+ ' has significantly more data points (50% more than average). Skipped for capacitance calculation') 116 | 117 | elif yset[peaks[i]] < ave_peak*0.9: 118 | faulty_cyc_ind += [i] 119 | print('Cycle ' + str(i+1)+ ' did not reach the maximum cycling voltage ' + str(round(ave_peak, 2)) + ' V. Skipped for capacitance calculation') 120 | 121 | elif yset[peaks[i]]-yset[troughs[i]] < ave_length*0.9 or yset[peaks[i]]-yset[troughs[i]] > ave_length*1.1: 122 | faulty_cyc_ind += [i] 123 | print('Cycle ' + str(i+1)+ ' has abnormal charging/discharging voltage range. Skipped for capacitance calculation') 124 | 125 | else: 126 | if cap_method is 1 or cap_method is False: 127 | try: 128 | cc_grad += [polyfit(xset[peaks[i]:troughs[i]][mid_ind[i]:], yset[peaks[i]:troughs[i]][mid_ind[i]:],1, cov=False)[0]] 129 | except: 130 | faulty_cyc_ind += [i] 131 | print('Error found in cycle ' + str(i+1)+ '. Skipped for capacitance calculation') 132 | 133 | elif cap_method is 2: 134 | try: 135 | cc_grad += [polyfit(xset[peaks[i]:troughs[i]][:mid_ind[i]], yset[peaks[i]:troughs[i]][:mid_ind[i]],1, cov=False)[0]] 136 | except: 137 | faulty_cyc_ind += [i] 138 | print('Error found in cycle ' + str(i+1)+ '. Skipped for capacitance calculation') 139 | 140 | 141 | 142 | 143 | if ESR_method == 1 or ESR_method == 101: 144 | esr_v = [ConstantPoints(yset, peaks[i], set_n = setting) for i in range(len(peaks))] 145 | 146 | elif ESR_method is True or ESR_method == 2 or ESR_method == 201: 147 | esr_v = [ConstantDeriv(xset, yset, peaks[i], troughs[i], set_deriv = setting) for i in range(len(peaks))] 148 | 149 | elif ESR_method is False: 150 | esr_v = False 151 | 152 | else: 153 | print('ESR method not specified. ESR values will not be calculated.') 154 | esr_v= False 155 | 156 | if cap_grav is True and m1 is not False and m2 is not False: 157 | cap_ls_calc = Cap_ls(cc_grad, current*10**(-3), m1*10**(-3), m2*10**(-3)) 158 | 159 | else: 160 | cap_ls_calc = Cap_ls(cc_grad, current*10**(-3), cap_grav = False) 161 | 162 | 163 | esr_ls_calc = ESR_ls(esr_v, current*10**(-3)) 164 | 165 | return cap_ls_calc, esr_ls_calc, peaks, troughs, N_cycle, faulty_cyc_ind 166 | 167 | 168 | -------------------------------------------------------------------------------- /Supycap/cc_analysis/load_capacitor.py: -------------------------------------------------------------------------------- 1 | from numpy import* 2 | 3 | from .utilities import* 4 | from .cccap.cc_cap import* 5 | from .supercap import* 6 | 7 | #load a single supercapacitor GDC txt file and save it in the Supercap class. First line being the header. The first coloumn is the elapsed time in second, the second coloumn is Voltage. 8 | #mass_ls is a list of two lists of the mass of each electrode 9 | #if current is not entered, it is going to be generated from the filename (the file name has to include the current in mA, seperated by '/' or '_' and followed by '_mA') 10 | #recieve mass and current in mg and mA respectively, output as mg and mA 11 | def Load_capacitor(pathway, t_set = False, V_set = False, delimiter = False, mass_ls = False, current = False, row_skip = False, ESR_method = True, setting = False, cap_method = False, cap_grav = True): 12 | """ 13 | Loading all relevant information of the measured supercapacitor the of the specified text file 14 | 15 | Parameters 16 | ---------- 17 | pathway : :class:`str` 18 | The path in which the data files are located. 19 | The current of each file has to be specified and seperated by either '/' or '_' and followed by '_mA' at the end 20 | Example: './folder_x/0.1_mA_GCD_sample_A.txt' 21 | 22 | t_set : :class:`int`, optional 23 | Specify the coloumn index for the time(s) data, coloumn 0 being the first coloumn starting from the left 24 | t_set = False (t_set = 0) 25 | True (The prompt will ask for the column index to be entered) 26 | : :class: `int` (specify the coloumn which will be used as time) 27 | 28 | V_set : :class:`int`, optional 29 | Specify the coloumn index for the volatge(V) data, coloumn 0 being the first coloumn starting from the left 30 | V_set = False (V_set = 0) 31 | True (The prompt will ask for the column index to be entered) 32 | : :class: `int` (specify the coloumn which will be used as voltage) 33 | 34 | delimiter : :class:`str`, optional 35 | The symbol which seperates one data coloumn from the other. If delimiter = False, the delimiter is assumed to be space ''. 36 | 37 | mass_ls : :class:`list` 38 | Measurements of the mass of each electrode. mass_ls will result in non-gravimetric capacitance being calculated. 39 | mass_ls = False (calculate non-gravimetric capacitance) 40 | = [[List of mass measurements for electrode 1], [List of mass measurements for electrode 2]] 41 | (calculate gravimetric capacitance) 42 | 43 | current : :class:`float`, optional 44 | The current for the GCD analysis. If current = False, the program will attempt to extract the current value from the file name. 45 | 46 | row_skip : :class:`int`, optional 47 | The number of rows of headers to skip in the text files. 48 | row_skip = False (row_skip = 1) 49 | = : :class:`int` (The specified number of rows will be skipped for all files in the path) 50 | 51 | ESR_method : :class:`int`, optional 52 | The method for ESR analysis. 53 | ESR_method = 1 (default constant point analyis using the first point after the peak for calculating voltage drop) 54 | = 101 (constant point analysis using the nth point after the peak, where n is specified using setting) 55 | = 2 or True (default constant second derivative method using the point where the second derivative is greater than 1) 56 | = 201 (constant second derivative method where the cut off derivative is specified using setting) 57 | = False (ESR value will be returned as False) 58 | 59 | setting : :class:`int`, optional 60 | The cut off second derivative or the cut off number of points used for ESR determination. 61 | setting = False (setting = 1 by default) 62 | 63 | cap_method : :class:`int`, optional 64 | The method for capacitance analysis. 65 | cap_method = 1 or False (the capacitance is analysed from the lower half of the voltage range) 66 | cap_method = 2 (the capacitance is analysed from the upper half of the voltage range) 67 | 68 | cap_grav : :class:`bool` 69 | cap_grav = True, output gravimetric capacitance 70 | cap_grav = False, output non-gravimetric capacitance 71 | 72 | returns 73 | ------- 74 | : :class:`list, list` 75 | [list of current density], [list of Supercap classes for each current density], [list of peak indices] 76 | 77 | 78 | """ 79 | if current is False: 80 | current = Readcurrent(pathway) 81 | if current is False: 82 | current = float(input('Missing current argument. Please include the current argument in mA:')) 83 | else: 84 | pass 85 | 86 | 87 | if row_skip is False: 88 | row_skip = 1 89 | elif row_skip is True: 90 | row_skip = int(input('Please enter the number of header row(s) in this file:')) 91 | else: 92 | pass 93 | 94 | 95 | GDC = Fast_load(pathway, skip_header = row_skip, t_set = t_set, V_set = V_set, delimiter = delimiter) 96 | GDC_t = GDC[0] 97 | GDC_V = GDC[1] 98 | 99 | if mass_ls==False: 100 | m1 = False 101 | m2 = False 102 | error = False 103 | mm1 = False 104 | mm2 = False 105 | std1= False 106 | std2 = False 107 | 108 | else: 109 | m1 = mass_ls[0] 110 | m2 = mass_ls[1] 111 | error = delt_m(m1, m2) 112 | mm1 = mean(m1) 113 | mm2 = mean(m2) 114 | std1 = std(m1) 115 | std2 = std(m2) 116 | 117 | if mass_ls != False and cap_grav is False: 118 | print('Mass of electrodes presents. Non-gravimetric capacitance is returned') 119 | elif mass_ls is False and cap_grav is True: 120 | print('Mass of electrodes absents. Non-gravimetric capacitance is returned') 121 | else: 122 | pass 123 | 124 | 125 | if ESR_method == 101 and setting is False: 126 | setting = int(input('How many points after the peak would you like to be considered for the ESR analysis? (the default value is 1)')) 127 | 128 | elif ESR_method == 201 and setting is False: 129 | setting = float(input('Please specify a cut-off derivative (the default value is 1)')) 130 | 131 | else: 132 | pass 133 | 134 | 135 | if ESR_method is 1: 136 | setting = 1 137 | elif ESR_method is 2: 138 | setting = 1 139 | elif ESR_method is True: 140 | ESR_method = 2 141 | setting = 1 142 | else: 143 | pass 144 | 145 | 146 | if cap_method is False: 147 | cap_method = 1 148 | elif cap_method is True or cap_method not in [1, 2]: 149 | cap_method = int(input('Please enter the desired capacitance analysis method. (1 or 2)')) 150 | else: 151 | pass 152 | 153 | 154 | cap_data = CC_Cap(GDC_t, GDC_V, current, mm1, mm2, ESR_method= ESR_method, setting = setting, cap_method = cap_method, cap_grav = cap_grav) 155 | 156 | 157 | return Supercap(current, [GDC_t, GDC_V], [[mm1, std1],[mm2, std2]], cap_data[0], cap_data[1], [cap_data[2], cap_data[3]], cap_data[4], error, [ESR_method, setting], cap_method, cap_data[5]) -------------------------------------------------------------------------------- /Supycap/cc_analysis/glob_analysis.py: -------------------------------------------------------------------------------- 1 | from numpy import* 2 | from matplotlib import* 3 | from matplotlib import pylab, mlab, pyplot 4 | from matplotlib.font_manager import FontProperties 5 | from pylab import* 6 | from IPython.core.pylabtools import figsize, getfigs 7 | import glob 8 | from functools import reduce 9 | import datetime 10 | 11 | from .load_capacitor import Load_capacitor 12 | from .utilities import Round_ls 13 | 14 | 15 | #Analyse one supercapacitor under different currents (use multiple supercap()) with error bars 16 | #path is directed to the folder which contains all relevant txt files for the analysis 17 | #m1, m2 are recived in unit of mg 18 | def Glob_analysis(path, t_set = False, V_set = False, delimiter = False, mass_ls = False, row_skip = False, ESR_method = True, setting = False, cap_method = False, plot_set = False, plotting = True, save_plot = False): 19 | """ 20 | Loading all text files in the folder as specified in path. Good for analysing how capacitance changes with current density. 21 | 22 | Notes 23 | ----- 24 | 1. Capacitance and ESR analysis for one supercapacitor under different currents. 25 | 2. Error bars are calculated from the mass errors of the electrodoes as other errors are insignificant compared to that caused by mass. 26 | 3. The masses in mass_ls is in mg. 27 | 4. It is assumed that all data files in the folder are measured from the same capacitor, hence they all have the same mass_ls 28 | 5. The current has to be included in the file name in the current format as specified under Parameters >> path 29 | 30 | Parameters 31 | ---------- 32 | path : :class:`str` 33 | The path in which the data files are located. 34 | The current of each file has to be specified and seperated by either '/' or '_' and followed by '_mA' at the end 35 | Example: './folder_x/0.1_mA_GCD_sample_A.txt' 36 | 37 | t_set : :class:`int` or `ls`, optional 38 | Specify the coloumn index for the time(s) data, coloumn 0 being the first coloumn starting from the left 39 | t_set = False (t_set = 0) 40 | True (The prompt will ask for the column index to be entered) 41 | : :class: `int` (specify the coloumn which will be used as time) 42 | 43 | V_set : :class:`int` or `ls`, optional 44 | Specify the coloumn index for the Volatge(V) data, coloumn 0 being the first coloumn starting from the left 45 | V_set = False (V_set = 0) 46 | True (The prompt will ask for the column index to be entered) 47 | : :class: `int` (specify the coloumn which will be used as time) 48 | 49 | delimiter : :class:`str`, optional 50 | A string which is used to seperate the data coloumns in the data file. If delimiter = False, the delimiter is assumed to be space ' '. 51 | 52 | mass_ls : :class:`list` 53 | Measurements of the mass of each electrode. mass_ls will result in non-gravimetric capacitance being calculated. 54 | mass_ls = False (calculate non-gravimetric capacitance) 55 | = [[List of mass measurements for electrode 1], [List of mass measurements for electrode 2]] 56 | (calculate gravimetric capacitance) 57 | 58 | row_skip : :class:`int` 59 | The number of rows of headers to skip in the text files. 60 | row_skip = False (row_skip = 1) 61 | = True (The prompt will ask for rows to skip for each files) 62 | = : :class:`int` (The specified number of rows will be skipped for all files in the path) 63 | 64 | ESR_method : :class:`int`, optional 65 | The method for ESR analysis. 66 | ESR_method = 1 (default constant point analyis using the first point after the peak for calculating voltage drop) 67 | = 101 (constant point analysis using the nth point after the peak, where n is specified using setting) 68 | = 2 or True (default constant second derivative method where the cut off second derivative is greater than 1) 69 | = 201 (constant second derivative method where the cut off derivative is specified using setting) 70 | = False (ESR value will be returned as False) 71 | 72 | setting : :class:`float`, optional 73 | The setting for ESR analysis 74 | setting = False (for ESR_method = 1, 2 or True, the default setting will be used) 75 | = : :class:`int` (nth point/cut off second derivative depending on the ESR_method) 76 | 77 | cap_method : :class:`int`, optional 78 | The method for capacitance analysis. 79 | cap_method = 1 or False (the capacitance is analysed from the lower half of the voltage range) 80 | cap_method = 2 (the capacitance is analysed from the upper half of the voltage range) 81 | 82 | plot_set : :class:`bool`, optional 83 | Figure parameters for plotting 84 | plot_set = False (default settings will be used for plotting) 85 | True (prompts to allow customised settings for plotting) 86 | 87 | plotting : :class:`bool`, optional 88 | Whether the capacitance vs. current density plot will be plotted 89 | plotting = False (the figure will not be plotted) 90 | = True (the figure will be plotted) 91 | 92 | save_plot : :`bool`, optional 93 | Whether the capacitance vs. current density plot will be saved 94 | save_plot = False (the figure will not be saved) 95 | = True (the figure will be saved as 'Gravimetric specific capacitance vs. current density [datetime].png') 96 | 97 | returns 98 | ------- 99 | : :class:`Supercap` 100 | 101 | """ 102 | if row_skip is True: 103 | decision = input('''Do you want to enter the header's row number for each file individually? yes/no''') 104 | if decision == 'yes': 105 | pass 106 | else: 107 | row_skip = int(input('Please enter the number of row(s) of headers to skip for all files:')) 108 | else: 109 | pass 110 | 111 | if ESR_method == 101 and setting is False: 112 | setting = int(input('How many points after the peak would you like to be considered for the ESR analysis? (the default value is 1)')) 113 | 114 | elif ESR_method == 201 and setting is False: 115 | setting = float(input('Please specify a cut-off derivative (the default value is 1)')) 116 | 117 | elif ESR_method == 1 or ESR_method == 2: 118 | setting = False 119 | 120 | else: 121 | pass 122 | 123 | #cap_norm setting 124 | if mass_ls is False: 125 | cap_grav = False 126 | else: 127 | cap_grav = True 128 | 129 | #print(ESR_method, 'glob') 130 | Glob_set = glob.glob(path) 131 | 132 | 133 | #loading data into the Supercap file 134 | supc_ls = [Load_capacitor(i, t_set = t_set, V_set = V_set, delimiter = delimiter, mass_ls = mass_ls, row_skip = row_skip, ESR_method = ESR_method, setting = setting, cap_method = cap_method, cap_grav = cap_grav) for i in Glob_set] 135 | 136 | 137 | #titles for the figure 138 | if mass_ls == False: 139 | print('current density cannot be calculated, current (mA) is returned. Non-gravimetric capacitance is calculated.') 140 | Cd_ls =[i.current for i in supc_ls] 141 | x_lab = 'Current (mA)' 142 | y_lab = 'Non-gravimetric capacitance (F)' 143 | error_bar = 0 144 | 145 | else: 146 | Cd_ls =[i.current/(i.masses[0][0]+i.masses[1][0]) for i in supc_ls] 147 | x_lab = 'Current density $(A$ $g^{-1})$' 148 | y_lab = 'Gravimetric capacitance $C_g$ $(F$ $g^{-1})$' 149 | 150 | 151 | #sorting the list of current density corresponding supercap entities according to the values 152 | Cd_ls = Round_ls(Cd_ls, 3) #rounding the current density values 153 | Cd_ls = array(Cd_ls) 154 | supc_ls = array(supc_ls) 155 | 156 | ind = Cd_ls.argsort() 157 | Cd_ls = Cd_ls[ind] 158 | supc_ls = supc_ls[ind] 159 | 160 | #Analyze each set of data 161 | Cap_ls_g = [mean(i.cap_ls) for i in supc_ls] 162 | Cap_error = [i.error for i in supc_ls] 163 | esr_data = [mean(i.esr_ls) for i in supc_ls] 164 | 165 | 166 | #plot set up 167 | if plot_set == False: 168 | width = 20 169 | length = 20 170 | font_size = 40 171 | line_colour = 'black' 172 | linewidth = 8 173 | error_bar = 6 174 | marker = 27 175 | rotation = 0 176 | if plot_set == True: 177 | width = int(input('Please specify the width of the figure')) 178 | length = int(input('Please specify the length of the figure')) 179 | font_size = int(input('Please specify the font size')) 180 | line_colour = input('Please specify the colour of the plot') 181 | linewidth = int(input('Please specify the linewidth')) 182 | error_bar = int(input('Please specify the size of the error bars')) 183 | marker = int(input('Please specify the size of the markers')) 184 | rotation = int(input('Please specify the rotation degrees of the x ticks')) 185 | 186 | 187 | 188 | #plotting 189 | if plotting == True: 190 | figure(figsize(length, width)) 191 | ax = gca() 192 | for label in ax.get_xticklabels() + ax.get_yticklabels(): 193 | label.set_fontsize(font_size) 194 | label.set_family('sans-serif') 195 | label.set_name('Arial') 196 | 197 | tx = ax.xaxis.get_offset_text() 198 | tx.set_fontsize(font_size) 199 | tx.set_family('sans-serif') 200 | tx.set_name('Arial') 201 | 202 | font = FontProperties() 203 | font.set_family('sans-serif') 204 | font.set_name('Arial') 205 | font.set_size(font_size+10) 206 | 207 | errorbar(Cd_ls, Cap_ls_g, yerr=Cap_error*array(Cap_ls_g), linewidth = linewidth, elinewidth = error_bar, capthick = error_bar, capsize = error_bar*3, ecolor = line_colour, marker ='x', color = line_colour, ms = marker, mew = marker/3) 208 | xlabel(x_lab, fontproperties=font) 209 | ylabel(y_lab, fontproperties=font) 210 | xticks(rotation = rotation) 211 | show() 212 | 213 | else: 214 | pass 215 | 216 | show() 217 | 218 | if save_plot == True: 219 | savefig('Gravimetric specific capacitance vs. current density'+' Date{0:%d%m}_Time{0:%I_%M}'.format(datetime.datetime.now())+'.png',transparent=True) 220 | 221 | else: 222 | pass 223 | 224 | 225 | 226 | #function returns lists of current, current density, averaged capacitance, the standard deviation of capcitance, ESR average, and ESR std accordingly. 227 | return Cd_ls, supc_ls 228 | 229 | 230 | -------------------------------------------------------------------------------- /Supycap/cc_analysis/supercap.py: -------------------------------------------------------------------------------- 1 | from numpy import* 2 | from matplotlib import* 3 | from matplotlib import pylab, mlab, pyplot 4 | from matplotlib.font_manager import FontProperties 5 | from pylab import* 6 | from scipy.signal import find_peaks 7 | from IPython.core.pylabtools import figsize, getfigs 8 | 9 | from .cccap.utilities import ConstantDeriv, ConstantPoints, ESR_ls, ESR_dv2, Half_pt_ind, Cap_ls 10 | 11 | 12 | 13 | #accept current in mA, output current in mA. 14 | #accept masses in mg, output in mg 15 | #The capacitpor is assumed to be the 2-electrode type and symmertric (the two electrodes can have different masses) 16 | class Supercap(): 17 | """ 18 | Stores all relevant information for the capacitance/ESR analysis of the supercapacitor 19 | 20 | Available methods 21 | ----------------- 22 | __init__ 23 | __repr__ 24 | ESR_method_change 25 | Show_dV2 26 | Cap_vs_cycles 27 | Get_info 28 | Check_analysis 29 | 30 | """ 31 | 32 | 33 | 34 | def __init__(self, current, t_V_ls, masses, cap_ls, esr_ls, extrema, cycle_n, m_error, ESR_method, cap_method, faulty_cycles): 35 | """ 36 | Initialize a :class:`.Supercap`. 37 | 38 | 39 | Notes 40 | ----- 41 | All current values are in mA 42 | All mass values are in mg 43 | 44 | 45 | Parameters 46 | ---------- 47 | current : :class:`float` 48 | Current at which the GCD analysis is undertaken. The current is in mA. 49 | 50 | t_V_ls : :class:`list` 51 | The raw data of the GCD analysis 52 | Input:[[list of time readings], [list of voltage readings]] 53 | 54 | masses : :class:`list` 55 | The mass measurements for the two electrodes. The mass is in mg. 56 | Input:[[average mass of m1, std of m1], [average mass of m2, std of m2]] 57 | 58 | cap_ls : :class:`list` 59 | The calculated capacitance for each cycle 60 | input: [list of calculated capacitance for each cycle] 61 | 62 | esr_ls : :class:`list` 63 | The calculated ESR values for each cycle 64 | input: [list of calculated ESR value for each cycle] 65 | 66 | extrema : :class:`list` 67 | The indices for the peaks and troughs of the voltage readings 68 | input: [[peak indices], [trough indices]] 69 | 70 | cycle_n : :class:`int` 71 | Number of cycles conducted 72 | input: number of cycles 73 | 74 | m_error : :class:`list` 75 | The uncertainty for each calculated capacitance value 76 | input: [list of uncertainties] 77 | 78 | ESR_method : :class:`int` 79 | The method for ESR analysis 80 | ESR_method = 1/102/2/202 81 | 82 | cap_method : :class:`int` 83 | The method for capacitance analysis 84 | cap_method = 1/2 85 | 86 | faulty_cycles : :class:`list` 87 | A list of cycle numbers for the faulty cycles 88 | input: [list of faulty cycle numbers] 89 | 90 | """ 91 | 92 | self.current = current 93 | self.masses = masses #output as: [average mass of m1, std of m1], [average mass of m2, std of m2] 94 | self.t_ls = t_V_ls[0] 95 | self.V_ls = t_V_ls[1] 96 | self.cap_ls = array(cap_ls) 97 | self.esr_ls = array(esr_ls) 98 | self.cycle_n = int(cycle_n) #has to be an interger value! 99 | self.error = m_error #only mass error is considered 100 | self.peaks = extrema[0] #output the indices of all the peaks in the dataset 101 | self.troughs = extrema[1] #output the indices of all the troughs in the dataset 102 | self.esr_method = ESR_method#[ESR method, setting] 103 | self.cap_method = cap_method 104 | self.faulty_cycles = array(faulty_cycles)+1 #cycle number for the faulty cycles (starting from 1) 105 | 106 | def __repr__(self): 107 | """ 108 | Initialize a :class:`.Supercap`. 109 | 110 | Return 111 | ----- 112 | Returns a string which state the current, maximum voltage and number of cycle analysed in the Supercap class 113 | 114 | """ 115 | peak_step = int(floor(len(self.peaks)/10))+1 116 | ave_peak = mean(self.V_ls[self.peaks[::peak_step]]) 117 | 118 | return f'' 119 | 120 | def ESR_method_change(self, ESR_method = True, setting = False): 121 | """ 122 | Initialize from a :class:`.Supercap`. 123 | 124 | 125 | Notes 126 | ----- 127 | Changing the ESR analysis method used for calculating esr_ls 128 | 129 | Parameters 130 | ---------- 131 | ESR_method : :class:`int`, optional 132 | The method for ESR analysis. 133 | ESR_method = 1 (default constant point analyis using the first point after the peak for calculating voltage drop) 134 | = 101 (constant point analysis using the nth point after the peak, where n is specified using setting) 135 | = 2 or True (default constant second derivative method where the cut off second derivative is greater than 1) 136 | = 201 (constant second derivative method where the cut off derivative is specified using setting) 137 | 138 | setting : :class:`float`, optional 139 | The setting for ESR analysis 140 | setting = False for ESR_method = 1, 2 or True 141 | setting = nth point/cut off second derivative depending on the ESR_method 142 | 143 | Return 144 | ------ 145 | :class:`.Supercap` 146 | self.esr_ls 147 | 148 | """ 149 | print('The original ESR method is', self.esr_method[0], ', and the setting is', self.esr_method[1]) 150 | 151 | if ESR_method is True: 152 | ESR_method = 2 153 | print('ESR method is changed to the default constant second derivative analysis, where the cut off second derivative is 1') 154 | elif ESR_method is False: 155 | print('ESR calculation is turned off') 156 | else: 157 | pass 158 | 159 | if ESR_method is 101 and setting is False: 160 | setting = int(input('How many points after the peak would you like to be considered for the ESR analysis? (the default value is 1)')) 161 | 162 | elif ESR_method is 201 and setting is False: 163 | setting = float(input('Please specify a cut-off derivative (the default value is 1)')) 164 | 165 | elif ESR_method is 1: 166 | setting = 1 167 | 168 | elif ESR_method is 2: 169 | setting = 1 170 | 171 | else: 172 | pass 173 | 174 | if ESR_method is 1 or ESR_method is 101: 175 | esr_v = [ConstantPoints(self.V_ls, self.peaks[i], set_n = setting) for i in range(self.cycle_n)] 176 | 177 | elif ESR_method is 2 or ESR_method is 201: 178 | esr_v = [ConstantDeriv(self.t_ls, self.V_ls, self.peaks[i], self.troughs[i], set_deriv = setting) for i in range(self.cycle_n)] 179 | 180 | else: 181 | esr_v = False 182 | 183 | 184 | self.esr_ls = array(ESR_ls(esr_v, self.current*10**(-3))) 185 | self.esr_method=[ESR_method, setting] 186 | 187 | return self.esr_ls 188 | 189 | 190 | def Cap_method_change(self, cap_method = False, cap_grav = True, m1 = False, m2 = False): 191 | print('The original cap_method is {}'.format(self.cap_method)) 192 | 193 | if cap_method is False: 194 | cap_method = int(input('Please enter the desired cap_method: (1/2)')) 195 | print('The cap_method is changed to {}'.format(cap_method)) 196 | 197 | if cap_grav is True: 198 | print('Gravimetric capacitance (F g^-1) is being calculated.') 199 | if m1 is False or m2 is False: 200 | if mean(self.masses[0]) == False or mean(self.masses[1]) == False: 201 | print('electrode masses are missing for the gravimetric capacitance calculation.') 202 | m1 = float(input('Please enter the mass of one of the electrode (mg):')) 203 | m2 = float(input('Please enter the mass of the other electrode (mg):')) 204 | 205 | else: 206 | print('Electrode masses are taken as specified previously.') 207 | m1 = mean(self.masses[0]) 208 | m2 = mean(self.masses[1]) 209 | 210 | else: 211 | pass 212 | else: 213 | print('Non-gravimetric capacitance (F) is being calculated.') 214 | 215 | mid_ind = [Half_pt_ind(self.V_ls[self.peaks[i]:self.troughs[i]],(self.V_ls[self.peaks[i]]+self.V_ls[self.troughs[i]])/2) for i in range(len(self.peaks))] 216 | 217 | cc_grad = [] 218 | faulty_cyc_ind = [] 219 | for i in range(len(self.peaks)): 220 | if i<=10: 221 | sel_peaks = self.peaks[:10] 222 | ave_len = mean([len(self.t_ls[self.peaks[k]:self.troughs[k]]) for k in range(len(sel_peaks))]) 223 | else: 224 | ave_len = mean([len(self.t_ls[self.peaks[k]:self.troughs[k]]) for k in range(i-10, i)]) 225 | 226 | if len(self.t_ls[self.peaks[i]:self.troughs[i]]) < ave_len*0.5: 227 | faulty_cyc_ind += [i] 228 | print('Cycle ' + str(i+1)+ ' has insufficient data points (50% less than average). Skipped for capacitance calculation') 229 | 230 | elif len(self.t_ls[self.peaks[i]:self.troughs[i]]) > ave_len*1.5: 231 | faulty_cyc_ind += [i] 232 | print('Cycle ' + str(i+1)+ ' has significantly more data points (50% more than average). Skipped for capacitance calculation') 233 | 234 | else: 235 | if cap_method is 1 or cap_method is False: 236 | try: 237 | cc_grad += [polyfit(self.t_ls[self.peaks[i]:self.troughs[i]][mid_ind[i]:], self.V_ls[self.peaks[i]:self.troughs[i]][mid_ind[i]:],1, cov=False)[0]] 238 | except: 239 | faulty_cyc_ind += [i] 240 | print('Error found in cycle ' + str(i+1)+ '. Skipped for capacitance calculation') 241 | 242 | elif cap_method is 2: 243 | try: 244 | cc_grad += [polyfit(self.t_ls[self.peaks[i]:self.troughs[i]][:mid_ind[i]], self.V_ls[self.peaks[i]:self.troughs[i]][:mid_ind[i]],1, cov=False)[0]] 245 | except: 246 | faulty_cyc_ind += [i] 247 | print('Error found in cycle ' + str(i+1)+ '. Skipped for capacitance calculation') 248 | 249 | if cap_grav is True: 250 | cap_ls_calc = Cap_ls(cc_grad, self.current*10**(-3), m1*10**(-3), m2*10**(-3)) 251 | 252 | else: 253 | cap_ls_calc = Cap_ls(cc_grad, self.current*10**(-3), cap_grav = False) 254 | 255 | self.cap_ls = array(cap_ls_calc) 256 | self.cap_method = cap_method 257 | 258 | return self.cap_ls 259 | 260 | 261 | 262 | 263 | #For visualising the second derivative for method 2 and/or method 201 and manually changing the second derivative cutt off point 264 | def Show_dV2(self, cycle_check = False, zoom_in = False): 265 | """ 266 | Initialize from a :class:`.Supercap`. 267 | 268 | Notes 269 | ----- 270 | Visualising the second derivative and the charge/discharge curve of a specified cycle with the option of changing the ESR analysis method used for calculating esr_ls 271 | 272 | Parameters 273 | ---------- 274 | cycle_check : :class:`int`, optional 275 | The method for ESR analysis. 276 | Specify the cycle of the charge/discharge curve and the second derivative to be plotted on the same axes 277 | input: a interger between 0 and the total number of cycles 278 | 279 | setting : :class:`float`, optional 280 | The setting for ESR analysis 281 | setting = the cut off second derivative being used in the ESR_method. (setting = 1 for ESR_method = 1 or 2) 282 | 283 | Return 284 | ------ 285 | A plot of charge discharge curve and the corresponding second derivative 286 | :class:`.Supercap`, optional 287 | self.esr_ls 288 | 289 | """ 290 | 291 | if self.esr_method[0] != 2 and self.esr_method[0] != 201: 292 | print('The current ESR method is neither 2 or 201. Please change the ESR method to constant second derivative analysis using .ESR_method_change().') 293 | return False 294 | else: 295 | pass 296 | 297 | if cycle_check is False: 298 | cycle_check = int(input('Of which cycle would you like to see the second derivative? enter a number between 1 and '+str(self.cycle_n))) 299 | else: 300 | pass 301 | 302 | proceed = True 303 | cycle_check -= 1 304 | 305 | while proceed is True: 306 | if cycle_check in self.faulty_cycles: 307 | cycle_check = int(input('The cycle enteres is a faulty cycle. Please enter another number between 1 and '+str(self.cycle_n))) 308 | cycle_check -= 1 309 | else: 310 | proceed = False 311 | 312 | 313 | setting = self.esr_method[1] 314 | while proceed is False: 315 | print('The cut off second derivative currently being used is '+str(setting)) 316 | esr_dV2 = [ESR_dv2(self.t_ls, self.V_ls, self.peaks[i], self.troughs[i], set_deriv = setting)[1] for i in range(self.cycle_n)] 317 | num_pt = [ESR_dv2(self.t_ls, self.V_ls, self.peaks[i], self.troughs[i], set_deriv = setting)[2] for i in range(self.cycle_n)] 318 | 319 | peak1 = self.peaks[cycle_check] 320 | trough1 = self.troughs[cycle_check] 321 | num1 = num_pt[cycle_check] 322 | dV_ls1 = esr_dV2[cycle_check] 323 | t_ls1 = array(self.t_ls[peak1:trough1])-self.t_ls[peak1] 324 | V_ls1 = self.V_ls[peak1:trough1] 325 | 326 | if zoom_in is False: 327 | zoom_in = int(floor(len(t_ls1)/2)) 328 | 329 | 330 | figure(figsize(20,15)) 331 | fig, ax1 = plt.subplots() 332 | 333 | font = FontProperties() 334 | font.set_family('sans-serif') 335 | font.set_name('Arial') 336 | font.set_size(35) 337 | 338 | color = 'tab:red' 339 | ax1.set_xlabel('Time (s)', fontproperties=font) 340 | ax1.set_ylabel('Second derivative $ dV^2/dt $', color=color, fontproperties=font) 341 | ax1.plot(t_ls1[1:zoom_in-2], dV_ls1[:zoom_in-3], linewidth=5, marker='x', ms=12, mew=5, color=color) 342 | ax1.plot(t_ls1[num1+2], dV_ls1[num1+1], linewidth=5, marker='x', ms=20, mew=6, color='g') 343 | ax1.tick_params(axis='y', labelcolor=color) 344 | 345 | 346 | ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis 347 | color = 'tab:blue' 348 | ax2.set_ylabel('Voltage (V)', color=color, fontproperties=font) # we already handled the x-label with ax1 349 | ax2.plot(t_ls1[:zoom_in-2], V_ls1[:zoom_in-2], linewidth=5, marker='x',ms=12, mew=5, color=color) 350 | ax2.plot(t_ls1[num1+1], V_ls1[num1+1], linewidth=5, marker='x',ms=20, mew=6, color='g') 351 | ax2.tick_params(axis='y', labelcolor=color) 352 | 353 | 354 | ax = gca() 355 | for label in ax1.get_xticklabels() + ax1.get_yticklabels() + ax2.get_yticklabels(): 356 | label.set_fontsize(30) 357 | label.set_family('sans-serif') 358 | label.set_name('Arial') 359 | 360 | show() 361 | 362 | opinion = input('Are you happy with the cut off point? (yes/no)') 363 | if opinion == 'yes': 364 | proceed = True 365 | change_setting = input('Do you wish to change the cut off point to the current value? (setting =' + str(setting)+ ')[yes/no]') 366 | if change_setting == 'yes': 367 | self.ESR_method_change(ESR_method = 201, setting = setting) 368 | break 369 | 370 | else: 371 | setting = float(input('Please input the value of desired cut off second derivative.')) 372 | 373 | 374 | 375 | #Tp plot capacitance against the number of cycles 376 | def Cap_vs_cycles(self, set_fig=False, save_fig=False): 377 | """ 378 | Initialize from a :class:`.Supercap`. 379 | 380 | 381 | Notes 382 | ----- 383 | Plotting capacitance against cycle and saving it as 'current mA_cap_vs_cycles_datetime.png' 384 | 385 | Parameter 386 | ---------- 387 | set_fig : :class:`bool`, optional 388 | Changing the setting of the figure 389 | 390 | save_fig : :class:`bool`, optional 391 | whether the figure will be saved 392 | 393 | Return 394 | ------ 395 | A figure of capacitance over cycle number 396 | 397 | """ 398 | 399 | if set_fig ==True: 400 | length = float(input('Please input length for the figure:')) 401 | width = float(input('Please input width for the figure:')) 402 | label_size = float(input('Please input the font size for the figure:')) 403 | lw = float(input('Please input the line width for the figure:')) 404 | clr = input('Please input the line colour for the figure:') 405 | else: 406 | length = 20 407 | width = 15 408 | label_size = 40 409 | lw =5 410 | clr = 'black' 411 | 412 | figure(figsize(length,width)) 413 | ax = gca() 414 | for label in ax.get_xticklabels() + ax.get_yticklabels(): 415 | label.set_fontsize(label_size) 416 | label.set_family('sans-serif') 417 | label.set_name('Arial') 418 | 419 | 420 | tx = ax.yaxis.get_offset_text() 421 | tx.set_fontsize(label_size) 422 | tx.set_family('sans-serif') 423 | tx.set_name('Arial') 424 | 425 | 426 | font = FontProperties() 427 | font.set_family('sans-serif') 428 | font.set_name('Arial') 429 | font.set_size(label_size + 10) 430 | 431 | xlabel('Number of cycles', fontproperties=font) 432 | if self.error is False: 433 | ylabel('Non-gravimetric capacitance $F$', fontproperties=font) 434 | else: 435 | ylabel('Capacitance $F g^{-1}$', fontproperties=font) 436 | 437 | plot(range(1, self.cycle_n-len(self.faulty_cycles)+1), self.cap_ls, color= clr , linewidth = lw) 438 | 439 | if save_fig is True: 440 | savefig(str(self.current)+'mA_cap_vs_cycles_'+'Date{0:%d%m}_Time{0:%I_%M}'.format(datetime.datetime.now())+'.png', transparent = True) 441 | else: 442 | pass 443 | 444 | #To get general info of the capacitance analysis 445 | def Get_info(self): 446 | """ 447 | Initialize from a :class:`.Supercap`. 448 | 449 | Notes 450 | ----- 451 | Printing the basic information of the Supercap class 452 | 453 | Parameter 454 | ---------- 455 | None 456 | 457 | Return 458 | ------ 459 | :class:`string`, optional 460 | The number of cycles, the average capacitance, the std of capacitance, the average ESR and its std, the ESR_method and cap_method used. 461 | 462 | """ 463 | 464 | print('The number of cycle(s) analysed is', self.cycle_n) 465 | print('The number of faulty cycle is', len(self.faulty_cycles)) 466 | print('The average capacitance is', round(mean(self.cap_ls),4), 'F g^(-1)') 467 | print('The standard deviation of the average is', round(std(self.cap_ls),4)) 468 | print('The average ESRs is', round(mean(self.esr_ls),4), 'Ohms') 469 | print('The standard deviation of the ESRs is', round(std(self.esr_ls),4)) 470 | if self.cap_method is 1: 471 | print('Lower half of the voltage range in the discharge curve was used for capacitance calculations') 472 | else: 473 | print('Upper half of the voltage range in the discharge curve was used for capacitance calculations') 474 | if self.esr_method[0] is True or self.esr_method[0]==2 or self.esr_method[0] == 202: 475 | print('Constant second derivative method was used for ESR calculations') 476 | else: 477 | print('Constant point method was used for ESR calculations') 478 | 479 | 480 | 481 | #To check whether the code is running correctly by visualising a small section of the analysis 482 | def Check_analysis(self, begin = False, end = False, set_fig = False, save_fig = False): 483 | """ 484 | Initialize from a :class:`.Supercap`. 485 | 486 | Notes 487 | ----- 488 | Plotting the charge/discharge curve and visualising how the data is analysed (indicate the slope fitting for capacitance and the voltage drop for ESR) 489 | 490 | Parameter 491 | ---------- 492 | begin: :class:`int`, optional 493 | The first cycle to be visualised 494 | 495 | end : :class:`int`, optional 496 | The last cycle to be visualised 497 | 498 | set_fig : :class:`bool`, optional 499 | Changing the setting of the figure 500 | 501 | save_fig : :class:`bool` or `str`, optional 502 | save_fig = False, the plot will not be saved 503 | save_fig = True, the plot will be saved as 'Check_analysis_[datetime].png' 504 | save_fig = class:`str` , the plot will be saved as 'the input string.png' 505 | 506 | 507 | Return 508 | ------ 509 | A plot of the charge/discharge curve with liniearly fitted slope and voltage drop 510 | 511 | """ 512 | 513 | if begin is False or end is False: 514 | print('Please enter the first cycle number for the check, the cycle number should be an interger between 1 and '+ str(self.cycle_n)) 515 | 516 | if begin is False: 517 | begin = int(input('Please enter the first cycle number for the check')) 518 | else: 519 | pass 520 | 521 | 522 | if end is False: 523 | end = int(input('Please enter the last cycle number for the check')) 524 | else: 525 | pass 526 | 527 | if set_fig ==True: 528 | length = float(input('Please input length for the figure:')) 529 | width = float(input('Please input width for the figure:')) 530 | label_size = float(input('Please input the font size for the figure:')) 531 | lw = float(input('Please input the line width for the figure:')) 532 | ms = float(input('Please input the marker size for the figure:')) 533 | mew = float(input('Please input the marker weight for the figure:')) 534 | degrees = float(input('Please input the rotation degrees for the x ticks:')) 535 | else: 536 | length = 10 537 | width = 7 538 | label_size = 30 539 | lw = 5 540 | ms = 25 541 | mew = 5 542 | degrees = 45 543 | 544 | 545 | figure(figsize(length, width)) 546 | ax = gca() 547 | for label in ax.get_xticklabels() + ax.get_yticklabels(): 548 | label.set_fontsize(label_size) 549 | label.set_family('sans-serif') 550 | label.set_name('Arial') 551 | 552 | tx = ax.xaxis.get_offset_text() 553 | tx.set_fontsize(label_size) 554 | tx.set_family('sans-serif') 555 | tx.set_name('Arial') 556 | 557 | if begin is 1: 558 | plot(self.t_ls[0:self.troughs[end-1]], self.V_ls[0:self.troughs[end-1]], label=str(self.current)+' mA', linewidth=lw, c='black') 559 | else: 560 | plot(self.t_ls[self.troughs[begin-2]:self.troughs[end-1]], self.V_ls[self.troughs[begin-2]:self.troughs[end-1]], label=str(self.current)+' mA', linewidth=lw, c='black') 561 | 562 | mid_ind = [Half_pt_ind(self.V_ls[self.peaks[i]:self.troughs[i]],(self.V_ls[self.peaks[i]]+ self.V_ls[self.troughs[i]])/2) for i in range(len(self.peaks))] 563 | 564 | for i in range(begin-1, end): 565 | if i+1 in self.faulty_cycles: 566 | print('Cycle '+str(i+1)+' was skipped for calculation due to errors') 567 | 568 | else: 569 | peaki = self.peaks[i] 570 | troughi = self.troughs[i] 571 | ipeakx = self.t_ls[peaki] 572 | itroughx = self.t_ls[troughi] 573 | 574 | if self.cap_method is 1: 575 | fit = polyfit(self.t_ls[peaki:troughi][mid_ind[i]:], self.V_ls[peaki:troughi][mid_ind[i]:],1, cov=True)[0] 576 | fitx = linspace(ipeakx*0.8+itroughx*0.2, itroughx, 20) 577 | fity = fitx*fit[0]+fit[1] 578 | 579 | plot(fitx, fity, linewidth=lw, linestyle='--', color='red') 580 | plot([ipeakx + 0.035*(itroughx-ipeakx)*(end-begin+1)]*100, linspace(self.V_ls[peaki], self.V_ls[peaki]-self.esr_ls[i]*2*self.current*10**(-3), 100), color='b', linewidth=lw, linestyle=':') 581 | plot(ipeakx, self.V_ls[peaki]-self.esr_ls[i]*2*self.current*10**(-3), linestyle='', marker=1, ms=ms, mew=mew, color='b') 582 | plot(ipeakx, self.V_ls[peaki], linestyle='', marker=1, ms=ms, mew=mew, color='b') 583 | plot(self.t_ls[peaki:troughi][mid_ind[i]], self.V_ls[peaki:troughi][mid_ind[i]], linestyle='', marker='+', ms=ms, mew=mew, color='r') 584 | plot(itroughx, self.V_ls[troughi], linestyle='', marker='+', ms=ms, mew=mew, color='r') 585 | 586 | else: 587 | fit = polyfit(self.t_ls[peaki:troughi][:mid_ind[i]], self.V_ls[peaki:troughi][:mid_ind[i]],1, cov=True)[0] 588 | fitx = linspace(1.4*ipeakx-0.4*itroughx, ipeakx*0.45 + itroughx*0.55, 20) 589 | fity = fitx*fit[0]+fit[1] 590 | 591 | plot(fitx, fity, linewidth=lw, linestyle='--', color='red') 592 | plot([ipeakx + 0.035*(itroughx-ipeakx)*(end-begin+1)]*100, linspace(self.V_ls[peaki], self.V_ls[peaki]-self.esr_ls[i]*2*self.current*10**(-3), 100), color='b', linewidth=lw, linestyle=':') 593 | plot(ipeakx, self.V_ls[peaki]-self.esr_ls[i]*2*self.current*10**(-3), linestyle='', marker=1, ms=ms, mew=mew, color='b') 594 | plot(ipeakx, self.V_ls[peaki], linestyle='', marker=1, ms=ms, mew=mew, color='b') 595 | plot(self.t_ls[peaki:troughi][mid_ind[i]], self.V_ls[peaki:troughi][mid_ind[i]], linestyle='', marker='+', ms=ms, mew=mew, color='r') 596 | plot(ipeakx, self.V_ls[peaki], linestyle='', marker='+', ms=ms, mew=mew, color='r') 597 | 598 | font = FontProperties() 599 | font.set_family('sans-serif') 600 | font.set_name('Arial') 601 | font.set_size(label_size + 5) 602 | 603 | xticks(rotation = degrees) 604 | xlabel('Time (s)', fontproperties = font) 605 | ylabel('Voltage (V)', fontproperties = font) 606 | font.set_size(label_size) 607 | legend(fontsize=label_size) 608 | 609 | if save_fig == True: 610 | savefig('Check_analysis_'+'Date{0:%d%m}_Time{0:%I_%M}_'.format(datetime.datetime.now())+'.png', transparent=True) 611 | elif save_fig == False: 612 | pass 613 | else: 614 | savefig(str(save_fig)+'.png', transparent=True) 615 | 616 | 617 | 618 | def Export(self, name, error = False, delimiter = False): 619 | """ 620 | Initialize from a :class:`.Supercap`. 621 | 622 | Notes 623 | ----- 624 | Exporting the electrochemical parameters as a txt file 625 | 626 | Parameter 627 | ---------- 628 | name: :class:`str` 629 | Name of the exported text file 630 | 631 | error : :class:`bool`, optional 632 | Whether a list of uncertainty of capacitance is included 633 | error = False (default, list of uncertainty will not be included) 634 | error = True (list of uncertainty will be included) 635 | 636 | delimiter : :class:`str`, optional 637 | String or character separating columns 638 | 639 | Return 640 | ------ 641 | A text file 'name.txt' including lists of capacitance, ESR and uncertainty of capacitance (optional) 642 | 643 | """ 644 | if error is False: 645 | final_data = column_stack((self.cap_ls, self.esr_ls)) 646 | if self.error is False: 647 | heading = 'Non-gravimetric Capacitance (F) ESR (Ohm) uncertainty' 648 | else: 649 | heading = 'Gravimetric Capacitance (F/g) ESR (Ohm)' 650 | 651 | else: 652 | final_data = column_stack((self.cap_ls, self.esr_ls, self.cap_ls*self.error)) 653 | if self.error is False: 654 | heading = 'Non-gravimetric Capacitance (F) ESR (Ohm) uncertainty' 655 | else: 656 | heading = 'Gravimetric Capacitance (F/g) ESR (Ohm)' 657 | 658 | header = '#{} \n{}'.format(self.__repr__()[1:-1], heading) 659 | 660 | if delimiter is False: 661 | delimiter = ' ' 662 | 663 | savetxt(fname = name+'.txt', X = final_data, delimiter = delimiter, header = header, comments = '') 664 | 665 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CC analysis 2 | 3 |

4 | Table of content 5 |

6 |
7 | 18 |
19 | 20 | ---- 21 |
22 |

23 | Introduction 24 |

25 |

26 | Welcome to Supycap! This is a Python library for analysis for the Constant Current (CC) curves as well as the Cyclic Voltammetry (CV) curves of two-electrode, symmetrical supercapacitors. It provides an easy and standardised way to quickly extract useful information from the CC and CV data, including the capacitance and the Equivalent Series Resistance(ESR) of the supercapacitor and how they evolve over cycles, with multiple options offered to suit the need of scientific investigations of supercapacitors. 27 | 28 |
29 |
30 | 31 | ### CC analysis 32 | For CC analysis, the capacitance is calculated via linear fitting the second half of the discharging slope in each charging/discharging cycle. For gravimetric capacitance, (): 33 | 34 |

35 | 36 |

37 | 38 | where is the mass of one of the two electrodes in the electrochemical cell and is the mass of the other, both in g; I is the current in A under which the CC anaysis is conducted; is the discharge slope, which is the change of voltage (V) with respect to time (s). 39 | 40 |
41 |
42 | 43 | 44 | For non-gravimetric capacitance (F): 45 | 46 |

47 | 48 |

49 | 50 | where I is the current in A and is the change of time (s) with respect to voltage (V). 51 | 52 |
53 |
54 | 55 | 56 | The ESR (Ω) is calculated using the voltage drop: 57 | 58 |

59 | 60 |

61 | 62 | where is the vertical drop in voltage in V at the beginning of the discharging curve as shown in the figure below; I is the current in A under which the CC analysis is conducted. 63 | 64 |
65 |
66 | 67 | 68 | Here is an illustration of how the CC data is analysed: 69 | 70 |

71 | CC analysis 72 |

73 | 74 |
75 |
76 |
77 | 78 | ### CV analysis 79 | For CV analysis, the capacitance is calculated via integration of the area enclosed by current as the voltage scanned across the potential window. For gravimetric capacitance (): 80 | 81 |

82 | 83 |

84 | 85 | where is the mass of one of the two electrodes in the electrochemical cell and is the mass of the other, both in g; is the CV scan rate in ; is the full discharge voltage in V; and are the voltages in V at the start of discharge and at the end of discharge, respectively. 86 | 87 |
88 |
89 | 90 | An illustration of how the CV data is analysed is shown below: 91 | 92 |

93 | CV analysis 94 |

95 | 96 | 97 | 98 |
99 | 100 | 101 | ---- 102 |
103 |

104 | Installation 105 |

106 |

107 | Method 1: Please follow the instruction under the 'code' tab. 108 |
109 |
110 | Method 2: Alternatively, the library can be directly downloaded from PyPI (https://pypi.org/project/Supycap/) using the following command in terminal: 111 | 112 | ```python 113 | pip install Supycap 114 | ``` 115 | 116 |

117 |
118 | 119 | ----- 120 | 121 |
122 |

123 | Documentations 124 |

125 |

126 | This python library offers means to analyse CC data and CV data in the format of text files or csv files, which can be directlt exported from electrochemistry software such as EC Labs. For CC analysis, the program recognises the first data coloumn as time (s) and the second coloumn as voltage (V) by default. For CV analysis, the program recognises the first data coloumn as voltage (V) and the second coloumn as current (mA) by default. However, the optional arguments, such as t_set, V_set, delimeter and row_skip for CC analysis and V_set, I_set, delimeter and row_skip for CV analysis, offers flexibility in dealing with more complex data files which do not meet the default format. For more information, please refer to the documentation for Load_capacitor and CV_analysis, respectively. The documentation includes two parts: CC analysis and CV analysis. CC analysis is further divided into Loading data, which are means for loading data into the Supercap class, and Supercap class, which are methods within the Superclass for extracting data from the analysis. 127 |

128 |
129 | 130 |
131 | 132 |
133 | 134 | ### CC analysis 135 | #### Loading data 136 | * __Load_capacitor__ 137 | * __Glob_analysis__ 138 | #### Supercap class 139 | * __init__ 140 | * __repr__ 141 | * __ESR_method_change__ 142 | * __Cap_method_change__ 143 | * __Show_dV2__ 144 | * __Cap_vs_cycles__ 145 | * __Get_info__ 146 | * __Check_analysis__ 147 | * __Export__ 148 | 149 | 150 | ### CV analysis 151 | * __CV_analysis__ 152 | 153 | 154 |
155 |
156 | 157 | 158 | --- 159 | --- 160 | 161 | 162 |
163 | 164 | ## Load_capacitor(pathway, t_set = False, V_set = False, delimiter = False, mass_ls = False, current = False, row_skip = False, ESR_method = True, setting = False, cap_method = False, cap_grav = True) 165 | This function loads the txt/csv file specified on the pathway into the Supercap class ,where capacitance and ESR analysis will be carried out. All relevant information can be extracted from the init function. 166 | 167 | 168 | ### Notes 169 | --- 170 | This function supports electrochemical data in either txt or csv format. In a txt file, it is by default that the first coloumn of the file is assumed to be time (s), and the second coloumn is assumed to be Voltage (V) for the CC analysis. The two coloumns are assumed to be seperated by space. However, the optional arguments, t_set, V_set, delimeter and row_skip, offers flexibility in dealing with more complex data files. 171 | 172 | 173 | 174 | ### Parameters 175 | --- 176 | 177 | #### Arguments 178 | 1. pathway : file, str, or pathlib.Path
179 | File, filename of the text file to read. Note that if the library is not allocated in the same directory as the file, the pathway to the file has to be given. For ``` current=False```, current will be directly read from the filename (i.e. the fielname has to include the current followed by '_mA' and seperated by '_', '/' or it is the first component of the filename). If current information cannot be obtained from the filename, the current has be specified via the current argument. For more details, refer to the Examples section. This function currently only supports data in the format of txt or csv. 180 | 181 | 182 | 2. t_set : int/str(csv files only), optional
183 | An integer specifying the coloumn index for time(s) data, with the first coloumn being coloumn 0 starting from left. If t_set = False, column 0 will be used as time(s); if t_set = False, there will be prompt asking for time coloumn index to be entered.For csv files, the coloumn index can also be the name of the coloumn (e.g. t_set = 'time(s)'). 184 | 185 | 186 | 3. V_set : int/str(csv files only), optional
187 | An integer specifying the coloumn index for voltage(V) data, with the first coloumn being coloumn 0 starting from left. If V_set = False, column 1 will be used as Voltage(V); if t_set = False, there will be prompt asking for voltage coloumn index to be entered. For csv files, the coloumn index can also be the name of the coloumn (e.g. V_set = 'voltage(V)'). 188 | 189 | 190 | 4. delimiter : str, optional
191 | A string which is used to seperate the data coloumns in the data file. If delimiter = False, the delimiter is assumed to be space ' '. 192 | 193 | 194 | 5. mass_ls : list, [[measurements of m1], [measurements of m2]], optional
195 | A list specifying the mass of each electrode in the format as shwon above. Multiple measurements for each electrode should be included for calculation of the uncertainty of the data. All masses should be recorded in mg. If mass_ls = False, a non-gravimetric capacitanc will be calculated and the function returns [[False, False], [False, False]] for the .masses method in the resulting Supercap entity (more details for extracting data from the Supercap class in Supercap class>>init 196 | 197 | 198 | 6. current : float, optional
199 | If current = False, the current value will be directly read from the filename given that it is supplied in the format as specified above in the pathway section. If the current is not included the filename, it should be specified in the form of current =specified_current. The current value should be recorded in mA. 200 | 201 | 202 | 7. row_skip : int, optional
203 | Number of the rows of headers to skip in the txt files. If row_skip = False, row_skip = 1; if row_skip = True, a prompt will ask for rows to skip for the file. Enter row_skip = 0 if no rows need to be skipped. 204 | 205 |
206 | 207 | 8. ESR_method : int, optional
208 | The method for ESR analysis. It is by default (ESR_method = True) that the ESR analysis will be carried out using method 2 (constant derivative). For all methods available please refer to the next session ESR_method table. ESR_setting = False will return .esr_ls as False in the Supercap class. Available ESR_methods are: ESR_methods = True, False, 1, 101, 2, 201. 209 | 210 | 211 | 9. setting : float, optional
212 | For ESR_methods = True, 1, or 2 , setting = False. For ESR_methods = 101 or 201 , setting is required as the number of points n/second derivative cut off point needed for the constant point method and the constant derivative method, respectively. If ESR_methods = 101 or 201 but setting = False, the function will promt the user to choose a specific value for the ESR analysis before proceeding. 213 | 214 |
215 | 216 | 10. cap_method : int, optional
217 | The method for capacitance analysis which determines whether the upper (cap_method = 2) or lower (cap_method = 1) half of the voltage range of the discharging curve will be used. By default cap_set = False and the program uses the lower half of the discharging curve. For detailed information please refer to the cap_method table below. 218 | 219 | 220 | 11. cap_grav : bool, optional
221 | It is by default that the gravimetric capacitance is calculated. By using cap_grav = False or mass_ls = False , a non-gravimetric capacitance will be calculated. 222 | 223 |
224 |
225 | 226 | #### ESR_method 227 | 228 | Method | Description | 229 | --- | --- | 230 | True | Default Method 2 | 231 | False | Returning ESR = False (no ESR calculation) | 232 | 1 | Default Method 1. dV is calculatied using the voltage difference between the peak voltage and the fourth data point taken after the peak voltage is reached | 233 | 101 | This method prompts the user to enter an interger n, where dV is determined between the peak voltage and the voltage of the nth points after the peak voltage | 234 | 2 | Default Method 2. dV is calculatied using the voltage difference between the peak voltage and the smallest data point where the second derivative greater than 0.01 (the second derivative decreases during teh discharging process) | 235 | 201 | This method prompts the user to enter a float x, where dV is determined between the peak voltage and the voltage of the smallest data point with second derivative over x | 236 | 237 | 238 |
239 |
240 | 241 | #### cap_method 242 | 243 | Method | Description | 244 | --- | --- | 245 | False/1 | Default Method. The lower half of the discharging curve is fitted for capacitance calculation. | 246 | 2 | The upper half of the discharging curve is fitted for capacitance calculation. | 247 | 248 | 249 | #### Returns 250 | out: Supercap 251 | 252 | >A Supercap entity generated from the text file 253 | 254 | 255 | ### Examples 256 | --- 257 | 258 | ```python 259 | >>>supercap1 = Load_capacitor('./CC/3.0_mA_1.0V_010120.txt', ESR_method = 2) 260 | Missing current argument. Please include the current argument in mA: 261 | >>>4 262 | Mass of electrodes absents. Non-gravimetric capacitance is returned 263 | Cycle 1387 has insufficient data points (40% less than average). Skipped for capacitance calculation 264 | >>>supercap1 265 | 266 | ``` 267 | 268 |
269 | 270 | ```python 271 | >>>supercap2 = Load_capacitor('./CC/3.0_1.0V_010120.txt', t_set = 0, V_set = 1, mass_ls = [[12,13,12.2], [11, 10.5, 11.6]], current = 4, ESR_method = 2) 272 | >>>supercap2 273 | 274 | ``` 275 | 276 |
277 | 278 |
279 |
280 | 281 | --- 282 | --- 283 | 284 |
285 | 286 | ## Glob_analysis(path, t_set = False, V_set = False, delimiter = False, mass_ls = False, row_skip = False, ESR_method = True, setting = False, cap_method = False, plot_set = False, plotting = True, save_plot = False) 287 | Loading all txt/csv files in the folder as specified in path. Good for analysing how capacitance changes with current density. 288 | 289 | 290 | ### Notes 291 | --- 292 | 1. Capacitance and ESR analysis for one supercapacitor under different currents. 293 | 2. Error bars are calculated from the mass errors of the electrodoes as other errors are insignificant compared to that caused by mass. 294 | 3. The masses in mass_ls is in mg. 295 | 4. It is assumed that all data files in the folder are measured from the same capacitor, hence they all have the same mass_ls. 296 | 5. The current has to be included in the file name in the current format as specified under Parameters >> path 297 | 298 | 299 | ### Parameters 300 | --- 301 | 302 | #### Arguments 303 | 304 |
305 | 306 | 1. path : file, str, or pathlib.Path
307 | File, filename of the text file to read. Note that if the library is not allocated in the same directory as the file, the pathway to the file has to be given. For ``` current=False```, current will be directly read from the filename (i.e. the fielname has to include the current followed by '_mA' and seperated by '_', '/' or it is the first component of the filename). Note that the current values must be recorded in mA.For more details, refer to the Examples section. 308 | 309 | 310 | 2. t_set : int/str(csv files only), optional
311 | An integer specifying the coloumn index for time(s) data, with the first coloumn being coloumn 0 starting from left. If t_set = False, column 0 will be used as time(s); if t_set = True, there will be prompt asking for time coloumn index to be entered.For csv files, the coloumn index can also be the name of the coloumn (e.g. t_set = 'time(s)'). 312 | 313 | 314 | 3. V_set : int/str(csv files only), optional
315 | An integer specifying the coloumn index for voltage(V) data, with the first coloumn being coloumn 0 starting from left. If V_set = False, column 1 will be used as Voltage(V); if t_set = True, there will be prompt asking for voltage coloumn index to be entered. For csv files, the coloumn index can also be the name of the coloumn (e.g. V_set = 'voltage(V)'). 316 | 317 | 318 | 4. delimiter : str, optional
319 | A string which is used to seperate the data coloumns in the data file. If delimiter = False, the delimiter is assumed to be space ' '. 320 | 321 | 322 | 5. mass_ls : list, [[measurements of m1], [measurements of m2]], optional
323 | A list specifying the mass of each electrode in the format as shwon above. Multiple measurements for each electrode should be included for calculation of the uncertainty of the data. All masses should be recorded in mg. If mass_ls = False, a non-gravimetric capacitanc will be calculated and the function returns [[False, False], [False, False]] for the .masses method in the resulting Supercap entity (more details for extracting data from the Supercap class in Supercap class >> init 324 | 325 | 326 | 6. row_skip : int, optional
327 | Number of the rows of headers to skip in the txt files. If row_skip = False, row_skip = 1; if row_skip = True, a prompt will ask for rows to skip for the file. Enter row_skip = 0 if no rows need to be skipped. 328 | 329 |
330 | 331 | 7. ESR_method : int, optional
332 | The method for ESR analysis. It is by default (ESR_method = True) that the ESR analysis will be carried out using method 2 (constant derivative). For all methods available please refer to the next session ESR_method. ESR_setting = False will return .esr_ls as False in the Supercap class. Available ESR_methods are: ESR_methods = True, False, 1, 101, 2, 201. 333 | 334 | 335 | 8. setting : float, optional
336 | For ESR_methods = True, 1, or 2 , setting = False. For ESR_methods = 101 or 201 , setting is required as the number of points n/second derivative cut off point needed for the constant point method and the constant derivative method, respectively. If ESR_methods = 101 or 201 but setting = False, the function will promt the user to choose a specific value for the ESR analysis before proceeding. 337 | 338 | 339 | 9. cap_method : bool, optional
340 | The method for capacitance analysis which determines whether the upper (cap_method = 2) or lower (cap_method = 1) half of the voltage range of the discharging curve will be used. By default cap_set = False and the program uses the lower half of the discharging curve. For detailed information please refer to the cap_method table below. 341 | 342 | 343 | 10. plot_set : bool, optional
344 | Figure parameters for plotting. If plot_set = False, the defualt settings will be used. If plot_set = True, there will be prompts to allow customised settings for plotting. 345 | 346 | 347 | 11. plotting : bool, optional
348 | This argument determines whether the capacitance vs. current density plot will be plotted. It is by default that plotting = True , and the figure will be plotted. If plotting = False , the figure will not be plotted. 349 | 350 | 351 | 12. save_plot : bool, optional
352 | This argument determines whether the capacitance vs. current density plot will be saved. It is by default that save_plot = True , and the figure will be saved as 'Gravimetric specific capacitance vs. current density [datetime].png'. If save_plot = False , the figure will not be saved. 353 | 354 | 355 |
356 |
357 | 358 | #### ESR_method 359 | 360 | Method | Description | 361 | --- | --- | 362 | True | Default Method 2 | 363 | False | Returning ESR = False (no ESR calculation) | 364 | 1 | Default Method 1. dV is calculatied using the voltage difference between the peak voltage and the fourth data point taken after the peak voltage is reached | 365 | 101 | This method prompts the user to enter an interger n, where dV is determined between the peak voltage and the voltage of the nth points after the peak voltage | 366 | 2 | Default Method 2. dV is calculatied using the voltage difference between the peak voltage and the smallest data point where the second derivative greater than 0.01 (the second derivative decreases during teh discharging process) | 367 | 201 | This method prompts the user to enter a float x, where dV is determined between the peak voltage and the voltage of the smallest data point with second derivative over x | 368 | 369 | 370 | #### Returns 371 | out: list 372 | 373 | >[[list of current density],[list of Supercap objects]] 374 | 375 | 376 | ### Examples 377 | --- 378 | 379 | ```python 380 | >>>CC_glob = Glob_analysis('./various_mA_folder/*.txt', mass_ls=[[10.7, 10.5, 11.0], [11.2, 11.2, 11.5 ]], ESR_method = 2, plotting=False) 381 | >>>CC_glob 382 | ([0.0034039334341906206, 383 | 0.011346444780635402, 384 | 0.022692889561270805], 385 | [, 386 | , 387 | ]) 388 | ``` 389 | 390 |
391 | 392 | 393 |
394 |
395 | 396 | --- 397 | --- 398 | 399 |
400 | 401 | ## __init__(self, current, t_V_ls, masses, cap_ls, esr_ls, extrema, cycle_n, m_error, ESR_method, cap_method, faulty_cycles) 402 | Initialize a :class:`.Supercap`. 403 | 404 | ### Notes 405 | --- 406 | Stores all relevant information for the capacitance/ESR analysis of the supercapacitor. All current values are in mA and mass values are in mg. 407 | 408 | Available parameters that can be extracted include: 409 | 410 | ```python 411 | 1. .current 412 | 2. .masses 413 | 3. .t_ls 414 | 4. .V_ls 415 | 5. .cap_ls 416 | 6. .esr_ls 417 | 7. .cycle_n 418 | 8. .error 419 | 9. .peaks 420 | 10. .troughs 421 | 11. .esr_method 422 | 12. .cap_method 423 | 13. .faulty_cycles 424 | ``` 425 | The above method follows the name of the Supercap variable. More details in the example section. 426 | 427 | 428 | ### Parameters 429 | --- 430 | 431 | #### Arguments 432 | 433 |
434 | 435 | 1. current : float
436 | Current at which the CC analysis is undertaken. The current is in mA. 437 | 438 | 439 | 2. t_V_ls : list, [[list of time readings], [list of voltage readings]]
440 | The raw data of the CC analysis. 441 | 442 | 443 | 3. masses : list, [[average mass of m1, std of m1], [average mass of m2, std of m2]]
444 | The mass measurements for the two electrodes. The mass is in mg. 445 | 446 | 447 | 4. cap_ls : list, [list of calculated capacitance for each cycle]
448 | The calculated capacitance for each cycle. 449 | 450 | 451 | 5. esr_ls : list, [list of calculated ESR value for each cycle]
452 | The calculated ESR values for each cycle. 453 | 454 | 455 | 6. extrema : list, [[peak indices], [trough indices]]
456 | The indices for the peaks and troughs of the voltage readings. 457 | 458 | 459 | 7. cycle_n : int
460 | The indices for the peaks and troughs of the voltage readings. 461 | 462 | 463 | 8. m_error : list, [list of uncertainties]
464 | The uncertainty for each calculated capacitance value. 465 | 466 | 467 | 9. ESR_method : int
468 | The method for ESR analysis. 469 | ESR_method = 1/102/2/202 470 | 471 | 472 | 9. cap_method : int
473 | The method for capacitance analysis. 474 | cap_method = 1/2 475 | 476 | 477 | 11. faulty_cycles : list, [list of faulty cycle numbers]
478 | A list of cycle numbers (cycle number starting from 1) for the faulty cycles. The faulty cycle could be due to: 479 | 1. The discharge slope of a CC cycle has significantly more or less data points compared to the neighbouring cycles (more than 50% difference). 480 | 2. The discharge slope fails to perform linear fitting. 481 | 482 | 483 | ### Examples 484 | --- 485 | 486 | ```python 487 | >>>supercap1.current #supercap1 is a Supercap class variable. 488 | 4.0 489 | >>>supercap1.masses 490 | [[10.2, 0.0912], [12.1, 0.0853]] 491 | ``` 492 | 493 |
494 | 495 | 496 |
497 | 498 | ## __repr__(self) 499 | Initialize a :class:`.Supercap`. 500 | 501 | 502 | ### Returns 503 | --- 504 | Returns a string which state the current, maximum voltage and number of cycle analysed in the Supercap class. 505 | 506 | 507 | ### Examples 508 | --- 509 | ```python 510 | >>>Supercap2 #variable as saved in the previous example in Load_capacitor 511 | 512 | ``` 513 | 514 |
515 | 516 | 517 |
518 |
519 | 520 | --- 521 | --- 522 | 523 |
524 | 525 | ## ESR_method_change(self, ESR_method = True, setting = False) 526 | Initialize from a :class:`.Supercap`. 527 | 528 | 529 | ### Notes 530 | --- 531 | Changing the ESR analysis method used for calculating esr_ls. 532 | 533 | 534 | ### Parameters 535 | --- 536 | 537 | #### Arguments 538 | 539 | 1. ESR_method : int, optional
540 | The method for ESR analysis. For all methods available please refer to the next session ESR_method. ESR_setting = True will change the ESR analysis method to default, which is the constant second derivative method with a cut-off second derivative of 0.01. ESR_setting = False will turn off the ESR calculation. Available ESR_methods are: ESR_methods = True, False, 1, 101, 2, 201. 541 | 542 | 543 | 2. setting : float, optional
544 | For ESR_methods = True, 1, or 2 , setting = False. For ESR_methods = 101 or 201 , setting is required as the number of points n/second derivative cut off point needed for the constant point method and the constant derivative method, respectively. If ESR_methods = 101 or 201 but setting = False, the function will promt the user to choose a specific value for the ESR analysis before proceeding. 545 | 546 | 547 |
548 |
549 | 550 | #### ESR_method 551 | 552 | Method | Description | 553 | --- | --- | 554 | True | Default Method 2 | 555 | False | Returning ESR = False (no ESR calculation) | 556 | 1 | Default Method 1. dV is calculatied using the voltage difference between the peak voltage and the fourth data point taken after the peak voltage is reached | 557 | 101 | This method prompts the user to enter an interger n, where dV is determined between the peak voltage and the voltage of the nth points after the peak voltage | 558 | 2 | Default Method 2. dV is calculatied using the voltage difference between the peak voltage and the smallest data point where the second derivative greater than 0.01 (the second derivative decreases during teh discharging process) | 559 | 201 | This method prompts the user to enter a float x, where dV is determined between the peak voltage and the voltage of the smallest data point with second derivative over x | 560 | 561 | 562 | #### Returns 563 | out: :class:`.Supercap` 564 | >self.esr_ls 565 | 566 | 567 | ### Examples 568 | --- 569 | 570 | ```python 571 | >>>Supercap2 572 | 573 | >>>Supercap2.ESR_method_change(ESR_method = 201, setting =1) 574 | The original ESR method is 2 , and the setting is 0.01 575 | array([20.66931875, 20.762845 , 20.72346125, ..., 20.536415 , 576 | 20.5659475 , 20.570865 ]) 577 | >>>Supercap2 578 | 579 | ``` 580 | 581 |
582 | 583 |
584 |
585 | 586 | --- 587 | --- 588 | 589 |
590 | 591 | ## Cap_method_change(self, cap_method = False, cap_grav = True, m1 = False, m2 = False) 592 | Initialize from a :class:`.Supercap`. 593 | 594 | 595 | ### Notes 596 | --- 597 | Changing the cap analysis method used for calculating capacitance. 598 | 599 | 600 | ### Parameters 601 | --- 602 | 603 | #### Arguments 604 | 605 | 1. cap_method : int
606 | The method for capacitance analysis into which is changed. For cap_method = 1 or False), discharge slope of the lower half of the voltage range will be analysed. For cap_method = 2), discharge slope of the upper voltage range will be analysed. 607 | 608 | 609 | 2. cap_grav : bool, optional
610 | It is by default that the gravimetric capacitance is calculated. By using cap_grav = False or mass_ls = False , a non-gravimetric capacitance will be calculated. 611 | 612 | 613 | 3. m1 : float, optional
614 | The mass of electrode 1 of the supercapacitor. The mass is in mg. 615 | 616 | 617 | 4. m2 : float, optional
618 | The mass of electrode 2 of the supercapacitor. The mass is in mg. 619 | 620 | 621 | #### Returns 622 | out: :class:`.Supercap` 623 | >self.cap_ls 624 | 625 | 626 | ### Examples 627 | --- 628 | 629 | ```python 630 | >>>Supercap2 631 | 632 | >>>Supercap2.cap_method_change(cap_method = 2, cap_grav = True) 633 | The original cap_method is 1 634 | The cap_method is changed to 2 635 | Gravimetric capacitance (F g^-1) is being calculated. 636 | Electrode masses are taken as specified previously. 637 | Cycle 1387 has insufficient data points (50% less than average). Skipped for capacitance calculation 638 | 639 | array([49.3082373 , 49.37786468, 49.34835958, ..., 51.12061108, 640 | 51.13964009, 51.11665995]) 641 | 642 | >>>Supercap2.Check_analysis(start = 1387, end = 1389) 643 | Cycle 1387 was skipped for calculation due to errors 644 | ``` 645 | ![cap_method 2, upper voltage range](https://user-images.githubusercontent.com/70351473/103543708-e04aee00-4e96-11eb-98ea-afa38a100d44.png 'cap_method 2, upper voltage range') 646 | 647 | 648 | ``` 649 | >>>Supercap2 650 | 651 | ``` 652 | 653 |
654 | 655 |
656 |
657 | 658 | --- 659 | --- 660 | 661 |
662 | 663 | ## Show_dV2(self, cycle_check = False) 664 | Initialize from a :class:`.Supercap`. 665 | 666 | ### Notes 667 | --- 668 | Visualising the second derivative and the charge/discharge curve of a specified cycle with the option of changing the ESR analysis method used for calculating esr_ls. It is assumed that ESR_method = 201 is used in this function. 669 | 670 | ### Parameters 671 | --- 672 | 673 | #### Arguments 674 | 1. Cycle_check : int, optional
675 | The method for ESR analysis. Specify the cycle of the charge/discharge curve and the second derivative to be plotted on the same axes.If Cycle_check = False, the user will be prompted to select a cycle on the CD curve to view as the reference for adjusting the cut off point. (Note: the cycle number starts from 1) 676 | 677 | 678 | #### Returns 679 | 1. A plot of charge discharge curve and the corresponding second derivative
680 | 2. :class:`.Supercap`, optional 681 | >self.esr_ls 682 | 683 | 684 | ### Examples 685 | --- 686 | ```python 687 | >>>Supercap2 688 | 689 | >>>Supercap1.Show_dV2() 690 | Of which cycle would you like to see the second derivative? enter a number between 1 and 2704 691 | >>>0 692 | The cut off second derivative currently being used is 1 693 | ``` 694 | ![.Show_dV2() example](https://user-images.githubusercontent.com/70351473/91521198-095ae100-e8ef-11ea-94f5-1381dd325cbb.png '.Show_dV2() example 1') 695 | ```python 696 | Are you happy with the cut off point? (yes/no) 697 | >>>no 698 | Please input the value of desired cut off second derivative. 699 | >>>0.01 700 | ``` 701 | ![.Show_dV2() example](https://user-images.githubusercontent.com/70351473/91521234-22639200-e8ef-11ea-9cfc-accae0456220.png '.Show_dV2() example 2') 702 | ```python 703 | The cut off second derivative currently being used is 0.01 704 | Are you happy with the cut off point? (yes/no) 705 | >>>yes 706 | Do you wish to change the cut off point to the current value? (setting =0.01)[yes/no] 707 | >>>yes 708 | The original ESR method is 201 , and the setting is 1 709 | >>>Supercap2 710 | 711 | ``` 712 | 713 |
714 | 715 | 716 |
717 |
718 | 719 | --- 720 | --- 721 | 722 |
723 | 724 | ## Cap_vs_cycles(self, set_fig=False, save_fig=False) 725 | Initialize from a :class:`.Supercap`. 726 | 727 | ### Notes 728 | --- 729 | Plotting capacitance against cycle and saving it as 'current mA_cap_vs_cycles_datetime.png' 730 | 731 | ### Parameters 732 | --- 733 | 734 | #### Arguments 735 | 1. set_fig : bool, optional
736 | If set_fig = True, the user will be prompted to change the setting of the figure. 737 | 738 | 739 | 2. save_fig : bool, optional
740 | If save_fig = True, the figure will be saved under the name '[current] mA_cap_vs_cycles_Date[d/m]_Time[h/m].png' 741 | 742 | 743 | #### Returns 744 | A figure of capacitance over cycle number 745 | 746 | 747 | ### Examples 748 | --- 749 | ```python 750 | >>>Supercap1.Cap_vs_cycles(set_fig = True) 751 | Please input length for the figure: 752 | >>>30 753 | Please input width for the figure: 754 | >>>20 755 | Please input the font size for the figure: 756 | >>>45 757 | Please input the line width for the figure: 758 | >>>7 759 | Please input the line colour for the figure: 760 | >>>'black' 761 | ``` 762 | ![.Cap_vs_cycles() example](https://user-images.githubusercontent.com/70351473/91521000-9f423c00-e8ee-11ea-84f8-264f85f4d3c4.png '.Cap_vs_cycles() example') 763 | 764 |
765 | 766 | 767 |
768 |
769 | 770 | --- 771 | --- 772 | 773 |
774 | 775 | ## Get_info(self) 776 | Initialize from a :class:`.Supercap`. 777 | 778 | ### Notes 779 | --- 780 | Printing the basic information of the Supercap class 781 | 782 | ### Parameters 783 | --- 784 | 785 | #### Arguments 786 | None 787 | 788 | 789 | #### Returns 790 | out::class:`string`, optional 791 | >The number of cycles, the average capacitance, the std of capacitance, the average ESR and its std, the ESR_method and cap_method used. 792 | 793 | 794 | ### Examples 795 | --- 796 | ```python 797 | >>>Supercap2.Get_info() 798 | The number of cycle(s) analysed is 2704 799 | The number of faulty cycle is 1 800 | The average capacitance is 60.9025 F g^(-1) 801 | The standard deviation of the average is 0.0101 802 | The average ESRs is 14.3174 Ohms 803 | The standard deviation of the ESRs is 0.4699 804 | Lower half of the voltage range in the discharge curve was used for capacitance calculations 805 | Constant second derivative method was used for ESR calculations 806 | ``` 807 | 808 |
809 | 810 |
811 |
812 | 813 | --- 814 | --- 815 | 816 | 817 |
818 | 819 | ## Check_analysis(self, begin = False, end = False, set_fig = False, save_fig = False) 820 | Initialize from a :class:`.Supercap`. 821 | 822 | 823 | 824 | ### Notes 825 | --- 826 | 827 | Plotting the charge/discharge curve and visualising how the data is analysed (indicate the slope fitting for capacitance and the voltage drop for ESR). 828 | 829 | 830 | 831 | ### Parameters 832 | --- 833 | 834 | 835 | 836 | #### Arguments 837 | 838 | 1. begin : int, optional
839 | 840 | The first cycle to be visualised. For begin = False , the user will be prompted to choose the first cycle to be visualised. Please note that the cycle number starts from 1. 841 | 842 | 843 | 844 | 845 | 846 | 2. end : int, optional
847 | 848 | The last cycle to be visualised. For end = False , the user will be prompted to choose the last cycle to be visualised. 849 | 850 | 851 | 852 | 853 | 854 | 3. set_fig : bool, optional
855 | If set_fig = True, the user will be prompted to change the setting of the figure. 856 | 857 | 858 | 859 | 860 | 861 | 4. save_fig : string, optional
862 | 863 | For save_fig=False, the plot will not be saved. 864 | 865 | For save_fig=True, the plot will be saved as 'Check_analysis_[datetime].png'. 866 | 867 | 868 | 869 | 870 | 871 | #### Returns 872 | 873 | A plot of the charge/discharge curve with liniearly fitted slope and voltage drop. 874 | 875 | 876 | ### Examples 877 | ```python 878 | >>>Supercap1.Check_analysis(begin = 0, end = 4, save_fig = False) 879 | ``` 880 | ![.Check_analysis() example](https://user-images.githubusercontent.com/70351473/102226302-220ff680-3ee0-11eb-849b-743320186013.png '.Check_analysis() example') 881 | 882 |
883 | 884 | 885 |
886 |
887 | 888 | --- 889 | --- 890 | 891 |
892 | 893 | ## Export(self, name, error = False, delimiter = False) 894 | Initialize a :class:`.Supercap`. 895 | 896 | 897 | 898 | ### Notes 899 | --- 900 | 901 | Exporting the electrochemical parameters as a txt file 902 | 903 | 904 | 905 | ### Parameters 906 | --- 907 | 908 | 909 | 910 | #### Arguments 911 | 912 | 1. name : str
913 | Name of the exported text file. 914 | 915 | 916 | 1. error : bool, optional
917 | Whether a list of uncertainty of capacitance is included. If error = False, which is the default setting, a list of uncertainty will not be included; if error = True, a list of uncertainty will be included. 918 | 919 | 920 | 1. delimiter : str, optional
921 | String or character separating columns. 922 | 923 | 924 | 925 | #### Returns 926 | 927 | Returns a text file 'name.txt' including lists of capacitance, ESR and uncertainty of capacitance (optional). 928 | 929 | 930 |
931 | 932 | 933 |
934 |
935 | 936 | --- 937 | --- 938 | 939 |
940 | 941 | ## CV_analysis(pathway, m1, m2, scan_r = False, row_skip = False, x_name = False, y_name = False, delimiter = False, int_method = False) 942 | This function loads the txt/csv file specified on the pathway, where capacitance analysis on the Cyclic Voltammetry will be carried out. The function returns a list of capacitance calculated from each CV cycle. 943 | 944 | 945 | ### Notes 946 | --- 947 | This function supports electrochemical data in either txt or csv format. In a txt file, it is by default that the first coloumn of the file is assumed to be voltage (V), and the second coloumn is assumed to be current (mA) for the CC analysis. The two coloumns are assumed to be seperated by space. However, the optional arguments, x_name, y_name, delimeter and row_skip, offers flexibility in dealing with more complex data files. 948 | 949 | 950 | 951 | ### Parameters 952 | --- 953 | 954 | #### Arguments 955 | 1. pathway : file, str, or pathlib.Path
956 | File, filename of the text file to read. Note that if the library is not allocated in the same directory as the file, the pathway to the file has to be given. For ``` scan_r=False```, current will be directly read from the filename (i.e. the fielname has to include the current followed by '_mvs' and seperated by '_', '/' or it is the first component of the filename). If scan rate information cannot be obtained from the filename, the scan rate has to be specified via the current argument. For more details, refer to the Examples section. This function currently only supports data in the format of txt or csv. 957 | 958 | 959 | 2. m1 : float, optional
960 | The mass of electrode 1 of the supercapacitor. The mass is in mg. 961 | 962 | 963 | 3. m2 : float, optional
964 | The mass of electrode 2 of the supercapacitor. The mass is in mg. 965 | 966 | 967 | 4. scan_r : float, optional
968 | If scan_r = False, the scan rate value in mV/s will be directly read from the filename given that it is supplied in the format as specified above in the pathway section. If the current is not included the filename, it should be specified in the form of scan_r =specified_scan_rate 969 | 970 | 971 | 5. row_skip : int, optional
972 | Number of the rows of headers to skip in the txt files. If row_skip = False, row_skip = 1; if row_skip = True, a prompt will ask for rows to skip for the file. Enter row_skip = 0 if no rows need to be skipped. 973 | 974 | 975 | 6. V_set : int/str(csv files only), optional
976 | An integer specifying the coloumn index for voltage in V, with the first coloumn being coloumn 0 starting from left. If x_name = False, column 0 will be used as voltage(V); if x_name = True, there will be prompt asking for scan rate coloumn index to be entered.For csv files, the coloumn index can also be the name of the coloumn (e.g. x_name = 'voltage(V)'). 977 | 978 | 979 | 7. I_set : int/str(csv files only), optional
980 | An integer specifying the coloumn index for voltage(V) data, with the first coloumn being coloumn 0 starting from left. If y_name = False, column 1 will be used as current in mA; if y_name = True, there will be prompt asking for current coloumn index to be entered. For csv files, the coloumn index can also be the name of the coloumn (e.g. I_set = 'current(mA)'). 981 | 982 | 983 | 8. delimiter : str, optional
984 | A string which is used to seperate the data coloumns in the data file. If delimiter = False, the delimiter is assumed to be space ' '. 985 | 986 |
987 | 988 | 9. int_method : int, optional
989 | The method for integration of the enclosed area. It is by default (int_method = False) that the area under the curve will be calculated using the Simpson's rule. For all methods available please refer to the next session int_method table. 990 | 991 | 10. calc_method : int, optional
992 | The method which determines whether capacitance or capacity (enclosed area divided by mass) is being calculated. If calc_method = 1 , capacitance is calculated; if calc_method = 2, capacity is calculated by dividng the enclosed area by the mass of the electrodes. 993 | 994 | 995 |
996 | 997 |
998 |
999 | 1000 | #### int_method 1001 | 1002 | Method | Description | 1003 | --- | --- | 1004 | False or 1 | Default method. Integration using the Simpson's rule and integrates over discharging curve only. | 1005 | 101 | Integration using the Simpson's rule and integrates over both the charging and discharging curves. | 1006 | 2 | Integration using the trapezoidal rule and integrates over discharging curve only. | 1007 | 202 | Integration using the trapezoidal rule and integrates over both the charging and discharging curves. | 1008 | 1009 | 1010 | #### Returns 1011 | out: [list of calculated gravimetric capacitance] 1012 | 1013 | 1014 | ### Examples 1015 | --- 1016 | 1017 | ```python 1018 | >>>CV_analysis('../cell1_CV/1.2V_CA2.csv', m1=10, m2=9, scan_r=1, x_name = 'voltage', y_name ='current',delimeter=',', int_method=1) 1019 | 4 CV cycles are being analysed using integration method 1 1020 | [86.30233646681373, 88.433682993075, 89.45296144982, 90.0191569583757] 1021 | ``` 1022 | 1023 |
1024 | --------------------------------------------------------------------------------