''' JMK Engineering Inc. Python Library for design and such. by: Jeff MacKinnon email: jeff@jmkengineering.com Circuit Design Functions ''' import pandas as pd import numpy as np import math import sqlite3 import bisect def vd(current,length,resistance,runs=1): ''' Calculates the voltage drop across the conductor length. If there are parallel runs we assume that they are approximately the same length. Therefore from the general equation of: 1/Req = 1/R1 + 1/R2 ... and all R1-Rn are the same. Req = R/n or in the equation below r = resistance / runs. ''' r = (length*resistance/1000) / runs vd=round(2*current*r,8) return vd def percentvd(vd,nominal): percent = (vd/nominal)*100 return percent def voltage_drop(nominal_voltage, current, conductor_size, length,material ='cu', num_runs = 1, code = 'CEC'): ''' This function will return the drop in voltage and in percent of the supply. nominal_voltage = int current = float conductor_size = string Voltage drop equation is: Vdrop = 2 * I * L * R/1000 I = load current L = circuit length in meters R = Resistance in ohms/km ''' # Check to see if the db we need exists import os import sys if os.path.isfile('jepl-cable.db') == False: return (print("Run init. \nCopy jeplinit.py to the same folder as this file and add \n%run jeplinit.py jepl/folder/location/\nto the notebook. Make sure there is a trailing slash.")) if (material == 'al'): try: with sqlite3.connect("jepl-cable.db") as con: cur = con.cursor() cur.execute('SELECT "AC Resistance" FROM "SW-Spec 25051" WHERE "Conductor Number" = 3 AND "Conductor Size"=?', (conductor_size,)) resistance = cur.fetchone()[0] #print(resistance) except sqlite3.OperationalError as e: print(e) elif (material == 'cu'): try: with sqlite3.connect("jepl-cable.db") as con: cur = con.cursor() cur.execute('SELECT "AC Resistance" FROM "SW-Spec 25055" WHERE "Conductor Number" = 3 AND "Conductor Size"=?', (conductor_size,)) resistance = cur.fetchone()[0] except sqlite3.OperationalError as e: print(e) else: return (print("error, choose material as cu or al")) voltage = vd(current,length,resistance,num_runs) percent = percentvd(voltage,nominal_voltage) return [voltage, percent] # # voltage_drop_conductors is wrong # # def voltage_drop_conductors(voltage,current,distance,v_drop_percent = 0.03,runs = 1,material='cu'): ''' Calculates the minimum conductor size to accomodate for voltage drop based on: voltage -> system nominal voltage current -> the peak/design load for the circuit distance -> meters v_drop_percent -> The design voltage drop (default 0.03 or 3%) runs -> number of parallel runs (default 1) material -> the conductor material, either 'al' or 'cu'. (default 'cu') First we calculate the necessary resistivity: resistivity = ohms/km but the distance is 2x (there and back) resistivity = ohms/[(2 * distance)/1000] {ohms/km} ohms = v/I or (v_drop/voltage)/current v_drop = v_drop_percent * voltage resistivity = (v_drop/current)/[(2 * distance)/1000] This works for 1 run, but for parallel runs Rtot = R/n where n is the number of runs. in this equation we are looking for R, not Rtot, so we multiply the top by the number of runs. therefore: resistivity = [(v_drop/current)*runs]/[(2 * distance)/1000] ''' # Determine the resistivity needed in ohms/km v_drop = v_drop_percent * voltage resistivity = ((v_drop/current)*runs)/((2 * distance)/1000) if resistivity < 0.1214: print("add parallel runs") import os import sys if os.path.isfile('jepl-cable.db') == False: return (print("Run init. \nCopy jeplinit.py to the same folder as this file and add \n%run jeplinit.py jepl/folder/location/\nto the notebook. Make sure there is a trailing slash.")) # Lookup the conductor size that meets this resistivity. if (material == 'al'): try: with sqlite3.connect("jepl-cable.db") as con: cur = con.cursor() cur.execute('SELECT "Conductor Size" FROM "SW-Spec 25055" WHERE "Conductor Number" = 3 AND "AC Resistance"= current,column] closest_index = sectioned_df.idxmin() # Retrieve the nearest value using the found index conductor_size = df['size'].iloc[closest_index] return [conductor_size,num_parallel] def conductor_ampacity(conductor, temp = 75, material = 'cu', code = 'CEC', raceway = True, ambient = 30): ''' Calculates the ampacity of a conductor size and material using code tables. ''' material = material.upper() code = code.upper() valid_temp = [60,75,90] valid_temp_str = [str(x) for x in valid_temp] valid_code = ['CEC', ] valid_material = ['CU', 'AL', ] if temp == 90: column = '90C' elif temp == 75: column = '75C' else: column = '60C' if (code == 'CEC') & (material == 'CU') & (raceway == False): # CEC Table 1 df = pd.DataFrame(cec21tables.table1, columns=['size', '60C', '75C', '90C']) elif (code == 'CEC') & (material == 'CU') & (raceway == True): # CEC Table 2 df = pd.DataFrame(cec21tables.table2, columns=['size', '60C', '75C', '90C']) elif (code =='CEC') & (material =='AL') & (raceway == False): # CEC Table 3 df = pd.DataFrame(cec21tables.table3, columns=['size', '60C', '75C', '90C']) elif (code =='NEC') & (material =='CU'): return (' I haven\'t created this table yet') elif (code =='NEC') & (material =='AL'): return (' I haven\'t created this table yet') else: return ('The variables were\'t right, but I\'m a loss to why.') # Determine the ampacity of the conductor size result_df = df.loc[df['size'] == conductor,column] conductor_ampacity = result_df.item() #print(conductor_ampacity) return conductor_ampacity def bonding_conductor(conductor_ampacity,bus=False,material='cu',code = 'CEC'): ''' This function ''' material = material.upper() code = code.upper() valid_code = ['CEC', ] valid_material = ['CU', 'AL', ] if (material == 'CU') & (bus == False): db_index = 1 elif (material == 'AL') & (bus == False): db_index = 3 elif (material == 'CU') & (bus == True): db_index = 2 elif (material == 'AL') & (bus == True): db_index = 4 else: return ('The variables were\'t right, but I\'m a loss to why.') if (code == 'CEC'): try: with sqlite3.connect("jepl-cec21.db") as con: cur = con.cursor() cur.execute('SELECT * FROM "Table16" WHERE "current" >= ? ', (conductor_ampacity,)) bond_result = cur.fetchone() bond_size = bond_result[db_index] except sqlite3.OperationalError as e: print(e) else: return ('The variables were\'t right, but I\'m a loss to why.') return bond_size ## This doesn't work yet, but its getting def conduit_size(num_cc,cc_con,bond,material='SCH80'): # Calculate fill requirements based on Table 8 valid_material = ['RMC', # Rigid Metal Conduit 'FMC', # Flexible Metal Conduit 'RPVC', # Rigid PVC 'EB1', # Type EB1 'DB2', # Type DB2 'LTMC', # Liquid Tight Metal Conduit 'LTNMC', # Liquid Tight non-metallic conduit 'EMT', # electrical metallic tubing 'ENT', # electrical non-metallic tubing 'SCH40', # HDPE Schedule 40 'SCH80', # HDPE Schedule 80 #'DR9', # HDPE DR9 #'DR11', # HDPE DR11 #'DR135', # HDPE DR13.5 #'DR155' # HDPE DR15.5 ] if material not in valid_material: return print(material + " is not a valid material. I should be 'al' or 'cu'.") import numpy as np x = np.array(valid_material) db_result_index = np.where(x == material)[0][0] if num_cc == 1: percent_fill = 0.53 elif num_cc == 2: percent_fill = 0.31 else: percent_fill = 0.4 # Wire Size and diameter wire_size = [ # ['tradesize',area mm^2] ['14',2.08], ['12',3.31], ['10',5.26], ['8',8.37], ['6',13.3], ['4',21.2], ['3',26.7], ['2',33.6], ['1',42.4], ['1/0',53.5], ['2/0',67.4], ['3/0',85], ['4/0',107], ['250',127], ['300',152], ['350',177], ['400',203], ['500',253], ['600',304], ['700',355], ['800',405], ['900',456], ['1000',507], ['1250',633], ['1500',760], ['1750',887], ['2000',1010] ] # Calculate the area of current carrying conductors x = np.array(wire_size) row = np.where(x == cc_con)[0][0] current_carrying_conductor_area = wire_size[row][1] cc_area = current_carrying_conductor_area * num_cc # Bond Area row = np.where(x == bond)[0][0] bond_area = wire_size[row][1] # Total conductor area area_conductors = cc_area + bond_area #print(area_conductors) min_trade_area = area_conductors / percent_fill # The minimum area of the conduit #print(min_trade_area) parameter = ' WHERE ' + material + ' > ' + str(min_trade_area) try: with sqlite3.connect("jepl-cec21.db") as con: cur = con.cursor() cur.execute('SELECT "Trade Size" from "Table9"'+ parameter ) table = cur.fetchone() conduit = table except sqlite3.OperationalError as e: print(e) result_raw = conduit[0] result_name = str(conduit[0]) + 'mm ' + material return result_raw,result_name def cable_schedule_naming(conductor_size,conductors,runs = 1,bond='BOND'): ''' Converts the conductor size from the above functions to something that can be added to a database/schedule. ''' if conductor_size == '1/0' or conductor_size == '2/0' or conductor_size == '3/0' or conductor_size == '4/0': unit = "AWG" elif int(conductor_size) > 24: unit = 'kcmil' else: unit = 'AWG' if bond == 'BOND': bondtext = bond elif int(bond) > 24: bondtext = '#' + str(bond) + 'kcmil' else: bondtext = '#' + str(bond) + 'AWG' if runs > 1: cable_text = str(runs) + "x " + str(conductors) + "C #" + str(conductor_size) + unit + " + " + bondtext else: cable_text = str(conductors) + "C #" + str(conductor_size) + unit + " + " + bondtext return cable_text