Updated the conduit sizing, feels close, but still off.

This commit is contained in:
Jeff MacKinnon 2026-01-05 18:28:19 -04:00
parent 9c8521763c
commit 3597d841c4
2 changed files with 269 additions and 70 deletions

View file

@ -122,6 +122,177 @@ cec24table4 = [
['2000', 470, 560, 630] ['2000', 470, 560, 630]
] ]
# Table 6A Dimensions of single Class B R90XLPE, RW75XLPE, RW90XLPE and RPV90 unjacketed 600V insulated conductors for calculating conduit and tubing fill
# Only using the conductor characteristics columns, the area will be calculated in the functions. Only stranded.
cec24table6A = [
['size', 'diameter'],
['14', 3.36],
['12', 3.84],
['10', 4.47],
['8', 5.99],
['6', 6.95],
['4', 8.17],
['3', 8.88],
['2', 9.7],
['1', 11.23],
['1/0', 12.27],
['2/0', 13.44],
['3/0', 14.74],
['4/0', 16.21],
['250', 17.9],
['300', 19.3],
['350', 20.53],
['400', 21.79],
['450', 22.91],
['500', 23.95],
['600', 26.74],
['700', 28.55],
['750', 29.41],
['800', 30.25],
['900', 31.85],
['1000', 33.32],
['1250', 37.56],
['1500', 40.68],
['1750', 43.58],
['2000', 46.27]
]
# Table 6B Dimensions of single Class B R90XLPE, RW75XLPE, RW90XLPE and RPV90 unjacketed 1000V insulated conductors for calculating conduit and tubing fill
# Only using the conductor characteristics columns, the area will be calculated in the functions. Only stranded.
cec24table6B = [
['size', 'diameter'],
['14', 4.12],
['12', 4.6],
['10', 5.23],
['8', 5.99], # This is the same as the 600V in Table 6A
['6', 7.71],
['4', 8.93],
['3', 9.64],
['2', 10.46],
['1', 12.49],
['1/0', 13.53],
['2/0', 14.7],
['3/0', 16],
['4/0', 17.47],
['250', 19.17],
['300', 20.56],
['350', 21.79],
['400', 23.05],
['450', 24.17],
['500', 25.21],
['600', 27.24],
['700', 29.05],
['750', 29.91],
['800', 30.75],
['900', 32.35],
['1000', 33.82],
['1250', 38.32],
['1500', 41.44],
['1750', 44.34],
['2000', 47.03]
]
# Table 6C Dimensions of single Class B R90XLPE, RW75XLPE, R90EP, RW90XLPE, RW90EP, and RPV90 jacketed 600V insulated conductors for calculating conduit and tubing fill
# Only using the conductor characteristics columns, the area will be calculated in the functions. Only stranded.
cec24table6C = [
['size', 'diameter'],
['14', 4.12],
['12', 4.6],
['10', 5.23],
['8', 6.75],
['6', 8.47],
['4', 9.69],
['3', 10.4],
['2', 11.22],
['1', 13.51],
['1/0', 14.55],
['2/0', 15.72],
['3/0', 17.02],
['4/0', 18.49],
['250', 21.21],
['300', 22.6],
['350', 23.83],
['400', 25.09],
['450', 26.21],
['500', 27.25],
['600', 30.04],
['700', 31.85],
['750', 32.71],
['800', 33.55],
['900', 35.15],
['1000', 36.62],
['1250', 42.38],
['1500', 45.5],
['1750', 48.4],
['2000', 51.09]
]
# TODO - Add tables 6D thru 6K
# Table 9A/B Internal diameter and cross-sectional areas of various trade conduit and tubing
# Only using the internal diameter (ID) for each of these conduits, along with the trade size. This will be used to calculate the area and fill for the various limits per Table 8
'''
rmc = rigid metal conduit
fmc = flexible metal conduit
rpvc = rigid PVC
db2 = rigid Type EB1 PVC and rigid type DB2/ES2 PVC conduit
mlt = metallic liquid tight, flexible conduit
nmlt = non-metallic liquid tight conduit
emt = electrical metallic tubing
ent = electrical non-metallic tubing
rtrcips = rigid RTRC conduit marked IPS
rtrcid = rigid RTRC conduit marked ID
sch40 = HDPE conduit schedule 40
sch80 = HDPE conduit schedule 80
dr9 = HDPE DR9 conduit
dr11 = HDPE DR11 conduit
dr13 = HDPE DR13.5 conduit
dr15 = HDPE DR15.5 conduit
'''
cec24table9AB = [
['size','RMC', 'FMC', 'RPVC', 'DB2', 'LTMC', 'LTNMC','EMT', 'ENT', 'RTRCIPS', 'RTRCID', 'SCH40', 'SCH80', 'DR9','DR11', 'DR13', 'DR15'],
['16', 16.05, 15.88, 14.57, None, 15.8, 15.49, 15.4, 14.58, 17.27, 11.94, 14.67, 12.75, 15.47, 16.3, 17.02, 17.43],
['21', 21.23, 20.62, 19.77, None, 20.83, 20.45, 20.5, 19.66, 22.61, 18.29, 19.78, 17.7, 19.65, 20.73, 21.63, 22.14],
['27', 27.0, 25.4, 25.4, None, 26.44, 25.91, 26.2, 25.37, 29.34, 24.64, 25.4, 23.06, 24.86, 26.21, 27.33, 27.97],
['35', 35.41, 31.75, 31.75, None, 35.05, 34.54, 34.6, 33.73, 38.1, 30.99, 33.82, 31.1, 31.51, 33.31, 34.73, 35.54],
['41', 41.25, 38.1, 38.1, None, 40.01, 40.01, 40.5, 39.57, 44.2, 37.34, 39.63, 36.63, 36.1, 38.27, 39.93, 40.85],
['53', 52.91, 50.8, 50.8, 50.8, 51.31, 51.69, 52.1, 51.18, 56.26, 50.29, 51.18, 47.82, 45.19, 47.91, 50.18, 51.4],
['63', 63.22, 63.5, 61.3, None, 62.99, None, 69.4, None, 69.6, 63, 61.13, 56.97, 54.63, 57.92, 60.68, 62.24],
['78', 78.49, 76.2, 76.2, 76.2, 77.98, None, 85.2, None, 84.84, 75.69, 76.14, 71.38, 66.56, 70.6, 73.95, 75.85],
['91', 90.68, 88.9, 88.4, 88.4, 88.9, None, 97.4, None, None, 88.39, None, None, None, None, None, None],
['103', 102.87, 101.6, 100.1, 100.1, 101.6, None, 110, None, 109.72, 101.09, 100.26, 94.56, 85.36, 90.52, 94.83, 97.29],
['129', 128.85, None, 125.85, 126.35, None, None, 128.9, None, 136.14, 126.24, 125.91, 119.25, 105.54, 111.93, 117.25, 120.29],
['155', 154.76, None, 149.75, 149.75, None, None, 154.8, None, 162.05, None, 151.5, 142.86, 125.63, 133.22, 139.57, 143.19],
['200', None, None, 199.39, None, None, None, None, None, None, None, 199.64, None, 163.58, 173.49, 181.74, 186.43],
]
# Table 10D Dimensions of DLO cable for calculating conduit and tubing fill
cec24table10D = [
['size', 'diameter'],
['14', 5.59],
['12', 6.1],
['10', 6.86],
['8', 8.38],
['6', 10.41],
['4', 11.68],
['3', 12.45],
['2', 13.21],
['1', 16.51],
['1/0', 17.53],
['2/0', 18.29],
['3/0', 20.57],
['4/0', 22.10],
['262', 25.4],
['313', 26.92],
['373', 27.94],
['444', 31.24],
['535', 34.04],
['646', 36.83],
['777', 38.1],
['929', 40.89],
['1111', 44.45]
]
# Appendix Tables # Appendix Tables
cec24tableD3 = [ cec24tableD3 = [

View file

@ -309,14 +309,37 @@ def conductor_ampacity(conductor, temp = 75, material = 'cu', code = 'CEC', race
## This doesn't work yet, but its getting ## This doesn't work yet, but its getting
def conduit_size(num_cc,cc_con,bond,material='SCH80'): def conduit_size(num_cc,cc_con,bond,insulation="RW90", voltage = 1000, jacketed = False,material='SCH80', code = 'CEC'):
'''
Calculated the necessary conduit size for the circuit using code tables.
num_cc = The number of current carrying conductors, including neutral.
cc_con = The current carrying conductor size
bond = The bond size
insulation = The insulation class of the conductors.
voltage = The voltage rating of the insulation, typically 600 or 1000 [V].
jacketed = Whether or not the conductor is jacketed, typically this is false.
material = The material of the conduit. The default is SCH80 as it is the "worse case" in most configurations as it has a high difference from trade size to inner diameter.
code = CEC or NEC, although NEC is lagging in the development front at the moment, so stick with CEC.
# Calculate fill requirements based on Table 8 The calculation is completed in the following steps:
1. Check to make sure the variables are valid.
2. Determine the percent fill limitation based on the number of current carrying conductors.
3. Look up the outer diameter of the conductors and bond. Calculate the total area.
4. Look up the trade size conduit, of the correct material, that meets the requirements.
5. Return the trade size, inner diameter and "result name".
'''
valid_insulation = ['R90',
'RW90',
'RPV90',
'RW75'
]
valid_voltage = [600,1000]
valid_material = ['RMC', # Rigid Metal Conduit valid_material = ['RMC', # Rigid Metal Conduit
'FMC', # Flexible Metal Conduit 'FMC', # Flexible Metal Conduit
'RPVC', # Rigid PVC 'RPVC', # Rigid PVC
'EB1', # Type EB1
'DB2', # Type DB2 'DB2', # Type DB2
'LTMC', # Liquid Tight Metal Conduit 'LTMC', # Liquid Tight Metal Conduit
'LTNMC', # Liquid Tight non-metallic conduit 'LTNMC', # Liquid Tight non-metallic conduit
@ -324,20 +347,35 @@ def conduit_size(num_cc,cc_con,bond,material='SCH80'):
'ENT', # electrical non-metallic tubing 'ENT', # electrical non-metallic tubing
'SCH40', # HDPE Schedule 40 'SCH40', # HDPE Schedule 40
'SCH80', # HDPE Schedule 80 'SCH80', # HDPE Schedule 80
#'DR9', # HDPE DR9 'DR9', # HDPE DR9
#'DR11', # HDPE DR11 'DR11', # HDPE DR11
#'DR135', # HDPE DR13.5 'DR13', # HDPE DR13.5
#'DR155' # HDPE DR15.5 'DR15' # HDPE DR15.5
] ]
valid_code = ['CEC',
# 'NEC' - NEC isn't completed yet.
]
if insulation not in valid_insulation:
return print(insulation + " is not valid.")
if voltage not in valid_voltage:
return print(voltage + " is not valid.")
if material not in valid_material: if material not in valid_material:
return print(material + " is not a valid material. I should be 'al' or 'cu'.") return print(material + " is not a valid material. It should be in " + valid_material)
if code not in valid_code:
return print(code + " is not valid.")
cc_con = str(cc_con)
bond = str(bond)
#
# Determine the maximum conduit fill
#
import numpy as np import numpy as np
x = np.array(valid_material)
db_result_index = np.where(x == material)[0][0]
if num_cc == 1: if num_cc == 1:
percent_fill = 0.53 percent_fill = 0.53
@ -346,79 +384,69 @@ def conduit_size(num_cc,cc_con,bond,material='SCH80'):
else: else:
percent_fill = 0.4 percent_fill = 0.4
# Wire Size and diameter #
# Find the conductor area
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) # This will be modified/added to when all the Table 6's are added. Currently there are only A-C,
row = np.where(x == cc_con)[0][0] if jacketed == True:
current_carrying_conductor_area = wire_size[row][1] table6 = cec24table6C
cc_area = current_carrying_conductor_area * num_cc elif voltage == 600:
table6 = cec24table6A
elif voltage == 1000:
table6 = cec24table6B
else:
return print("error")
# Bond Area table6headers = table6[0]
table6rows = table6[1:]
conductor_diameter = pd.DataFrame(table6rows,columns= table6headers)
#print(conductor_diameter)
row = np.where(x == bond)[0][0] cc_dia = conductor_diameter.loc[(conductor_diameter['size'] == cc_con) ]['diameter'].iloc[0]
bond_area = wire_size[row][1] print(cc_dia)
bond_dia = conductor_diameter.loc[(conductor_diameter['size'] == bond) ]['diameter'].iloc[0]
print(bond_dia)
cc_area = math.pi * (cc_dia/2) ** 2
print(cc_area)
bond_area = math.pi * (bond_dia/2) ** 2
print(bond_area)
# Total conductor area # Total conductor area
area_conductors = cc_area + bond_area area_conductors = num_cc * cc_area + bond_area
#print(area_conductors) print(area_conductors)
min_trade_area = area_conductors / percent_fill # The minimum area of the conduit min_trade_area = area_conductors / percent_fill # The minimum area of the conduit
#print(min_trade_area) print(min_trade_area)
trade_inner_dia = math.sqrt(min_trade_area/math.pi) * 2
print(trade_inner_dia)
parameter = ' WHERE ' + material + ' > ' + str(min_trade_area)
try: #
with sqlite3.connect("jepl-cec21.db") as con: # Select the conduit trade size
cur = con.cursor() #
cur.execute('SELECT "Trade Size" from "Table9"'+ parameter )
table = cur.fetchone()
conduit = table
except sqlite3.OperationalError as e: conduit_table = pd.DataFrame(cec24table9AB[1:], columns=cec24table9AB[0])
print(e) #print(conduit_table)
# Calculate the absolute difference for all values and find the index of the minimum difference
sectioned_df = conduit_table.loc[conduit_table[material] >= trade_inner_dia,material]
result_raw = conduit[0] closest_index = sectioned_df.idxmin()
result_name = str(conduit[0]) + 'mm ' + material
# Retrieve the nearest value using the found index
result_raw = conduit_table['size'].iloc[closest_index]
result_name = result_raw + 'mm ' + material
result_inner_dia = conduit_table[material].iloc[closest_index]
return result_raw,result_name return result_raw,result_name,result_inner_dia