"""
铁塔计算模块 (Tower Calculation Module)
依据《架空输电线路杆塔结构设计技术规定》(DL/T 5154-2012)
和《建筑结构荷载规范》(GB 50009-2012) 进行铁塔结构计算。
"""
import math
MATERIAL_PROPS = {
"Q235": {"fy": 235, "f": 215, "E": 206000, "name": "Q235碳素结构钢"},
"Q345": {"fy": 345, "f": 310, "E": 206000, "name": "Q345低合金高强度钢"},
"Q390": {"fy": 390, "f": 350, "E": 206000, "name": "Q390低合金高强度钢"},
"Q420": {"fy": 420, "f": 375, "E": 206000, "name": "Q420低合金高强度钢"},
}
WIND_LEVEL_TABLE = {
8: 20.7, 9: 24.4, 10: 28.3, 11: 32.6,
12: 37.0, 13: 41.4, 14: 46.1, 15: 50.9,
16: 56.0, 17: 61.2,
}
VOLTAGE_PARAMS = {
"10kV": {"typical_height": 12, "base_width_ratio": 0.12, "top_width": 0.6},
"35kV": {"typical_height": 18, "base_width_ratio": 0.13, "top_width": 0.8},
"110kV": {"typical_height": 30, "base_width_ratio": 0.18, "top_width": 1.2},
"220kV": {"typical_height": 45, "base_width_ratio": 0.20, "top_width": 1.8},
"500kV": {"typical_height": 60, "base_width_ratio": 0.22, "top_width": 2.5},
}
WIRE_TABLE = {
"LGJ-120/20": {"area": 134.85, "weight": 466.8, "diameter": 15.07},
"LGJ-185/25": {"area": 211.29, "weight": 706.0, "diameter": 18.90},
"LGJ-240/30": {"area": 275.96, "weight": 921.0, "diameter": 21.60},
"LGJ-300/25": {"area": 325.21, "weight": 1058.0, "diameter": 23.40},
"LGJ-400/35": {"area": 425.24, "weight": 1349.0, "diameter": 26.82},
"LGJ-500/45": {"area": 531.68, "weight": 1688.0, "diameter": 30.00},
}
class TowerCalculator:
"""铁塔计算器主类"""
def __init__(self, wind_level, tower_height, tower_type, material,
voltage="110kV", wire_type="LGJ-240/30", wire_count=3,
terrain_type="B", safety_level=2):
self.wind_level = wind_level
self.tower_height = tower_height
self.tower_type = tower_type
self.material = material
self.voltage = voltage
self.wire_type = wire_type
self.wire_count = wire_count
self.terrain_type = terrain_type
self.safety_level = safety_level
self.gamma_0 = {1: 1.1, 2: 1.0, 3: 0.9}.get(safety_level, 1.0)
self.mat = MATERIAL_PROPS.get(material, MATERIAL_PROPS["Q345"])
self.wire = WIRE_TABLE.get(wire_type, WIRE_TABLE["LGJ-240/30"])
self.volt_params = VOLTAGE_PARAMS.get(voltage, VOLTAGE_PARAMS["110kV"])
self.results = {}
def calc_basic_wind_pressure(self):
"""基本风压 w0 = v^2 / 1600 (kN/m2)"""
v = WIND_LEVEL_TABLE.get(self.wind_level, 28.3)
w0 = v ** 2 / 1600.0
self.results["设计风速"] = v
self.results["基本风压_w0"] = w0
return w0
def calc_wind_pressure_variation(self, z):
"""风压高度变化系数"""
terrain_coeffs = {
"A": {"alpha": 0.12, "k": 1.28},
"B": {"alpha": 0.15, "k": 1.00},
"C": {"alpha": 0.22, "k": 0.54},
"D": {"alpha": 0.30, "k": 0.16},
}
tc = terrain_coeffs.get(self.terrain_type, terrain_coeffs["B"])
z = max(z, 1.0)
mu_z = tc["k"] * (z / 10.0) ** (2 * tc["alpha"])
return mu_z
def calc_wind_load_tower(self):
"""计算塔身分段风荷载"""
w0 = self.calc_basic_wind_pressure()
n_segments = 10
dz = self.tower_height / n_segments
mu_s = {"自立塔": 1.3, "拉线塔": 1.2, "单杆塔": 0.8}.get(self.tower_type, 1.3)
beta_z = 1.0 + 0.05 * math.sqrt(self.tower_height)
segments = []
total_force = 0.0
total_moment = 0.0
base_width = self.tower_height * self.volt_params["base_width_ratio"]
top_width = self.volt_params["top_width"]
for i in range(n_segments):
z_bottom = i * dz
z_top = (i + 1) * dz
z_mid = (z_bottom + z_top) / 2.0
mu_z = self.calc_wind_pressure_variation(z_mid)
width = top_width + (base_width - top_width) * (1 - z_mid / self.tower_height)
q = beta_z * mu_s * mu_z * w0 * width
F = q * dz
M = F * z_mid
segments.append({"z_bottom": z_bottom, "z_top": z_top, "z_mid": z_mid,
"mu_z": mu_z, "width": width, "q_wind": q, "F_wind": F, "M_base": M})
total_force += F
total_moment += M
self.results["塔身分段"] = segments
self.results["塔身总风荷载"] = total_force
self.results["塔身风荷载弯矩"] = total_moment
self.results["风振系数"] = beta_z
self.results["体型系数"] = mu_s
self.results["塔底宽度"] = base_width
self.results["塔顶宽度"] = top_width
return segments
def calc_wind_load_wire(self):
"""计算导线、地线风荷载"""
w0 = self.results.get("基本风压_w0", self.calc_basic_wind_pressure())
d_wire = self.wire["diameter"] / 1000.0
mu_s_wire = 1.2
mu_z_wire = self.calc_wind_pressure_variation(self.tower_height * 0.9)
span = {"10kV": 80, "35kV": 150, "110kV": 250, "220kV": 350, "500kV": 450}.get(self.voltage, 250)
alpha_wire = 0.85
W_wire = alpha_wire * mu_s_wire * mu_z_wire * d_wire * span * w0
W_wire_total = W_wire * self.wire_count
d_ground = 0.009
W_ground = alpha_wire * mu_s_wire * mu_z_wire * d_ground * span * w0
z_wire = self.tower_height * 0.92
z_ground = self.tower_height * 0.98
M_wire = W_wire_total * z_wire
M_ground = W_ground * z_ground
self.results["导线风荷载"] = W_wire_total
self.results["地线风荷载"] = W_ground
self.results["导线风荷载弯矩"] = M_wire
self.results["地线风荷载弯矩"] = M_ground
self.results["计算挡距"] = span
self.results["导线高度"] = z_wire
self.results["地线高度"] = z_ground
return W_wire_total, W_ground
def calc_internal_forces(self):
"""计算塔身内力(弯矩、剪力、轴力)"""
span = self.results.get("计算挡距", 250)
q_wire_weight = self.wire["weight"] * 9.81 / 1e6
G_wire = q_wire_weight * span * self.wire_count * 2
G_ground = 3.14159 * (0.009/2)**2 * 7850 * 9.81 * span * 2 / 1000
if self.tower_type == "自立塔":
q_tower_weight = 1.5 + 0.08 * self.tower_height
elif self.tower_type == "拉线塔":
q_tower_weight = 0.5 + 0.03 * self.tower_height
else:
q_tower_weight = 0.8 + 0.04 * self.tower_height
tower_segments = self.results.get("塔身分段", [])
n_points = 11
dz = self.tower_height / (n_points - 1)
internal_forces = []
for i in range(n_points):
z = i * dz
M = 0.0
V = 0.0
for seg in tower_segments:
if seg["z_mid"] >= z:
M += seg["F_wind"] * (seg["z_mid"] - z)
V += seg["F_wind"]
z_wire = self.tower_height * 0.92
z_ground = self.tower_height * 0.98
if z_wire >= z:
M += self.results.get("导线风荷载", 0) * (z_wire - z)
V += self.results.get("导线风荷载", 0)
if z_ground >= z:
M += self.results.get("地线风荷载", 0) * (z_ground - z)
V += self.results.get("地线风荷载", 0)
N = q_tower_weight * (self.tower_height - z)
if z <= z_wire:
N += G_wire + G_ground
elif z <= z_ground:
N += G_ground
internal_forces.append({"z": z, "M": M, "V": V, "N": N})
base_force = internal_forces[0]
self.results["内力分段"] = internal_forces
self.results["基底弯矩"] = base_force["M"]
self.results["基底剪力"] = base_force["V"]
self.results["基底轴力"] = base_force["N"]
self.results["塔身单位自重"] = q_tower_weight
self.results["导线重力"] = G_wire
self.results["地线重力"] = G_ground
return internal_forces
def calc_main_member(self):
"""主材截面选择与应力验算"""
M_max = self.results["基底弯矩"]
N_max = self.results["基底轴力"]
base_width = self.results["塔底宽度"]
N_main = M_max / base_width + N_max / 4.0
angle_steel = [
{"name": "L80x8", "area": 12.30, "i": 2.44},
{"name": "L90x8", "area": 13.94, "i": 2.76},
{"name": "L100x10", "area": 19.26, "i": 3.05},
{"name": "L110x10", "area": 21.26, "i": 3.38},
{"name": "L125x12", "area": 28.91, "i": 3.83},
{"name": "L140x14", "area": 37.57, "i": 4.30},
{"name": "L160x16", "area": 49.07, "i": 4.89},
{"name": "L180x18", "area": 61.86, "i": 5.52},
{"name": "L200x20", "area": 76.54, "i": 6.14},
]
l0 = self.tower_height / 10.0 * 0.8 * 100
f = self.mat["f"]
E = self.mat["E"]
selected = None
for angle in angle_steel:
A = angle["area"]
i = angle["i"]
lam = l0 / i
if lam <= 100:
phi = 1.0 / (1.0 + 0.43 * (lam / 100.0) ** 2)
else:
phi = 100.0 / (lam * (1.0 + 0.16 * (lam / 100.0) ** 2))
sigma = N_main * 1000.0 / (A * 100 * phi)
sigma_strength = N_main * 1000.0 / (A * 100)
if sigma <= f and sigma_strength <= f:
selected = {**angle, "lambda": lam, "phi": phi,
"sigma_stability": sigma, "sigma_strength": sigma_strength,
"stress_ratio": sigma / f}
break
if selected is None:
selected = {**angle_steel[-1], "lambda": l0 / angle_steel[-1]["i"],
"phi": 0.3, "sigma_stability": N_main * 1000.0 / (angle_steel[-1]["area"] * 100 * 0.3),
"sigma_strength": N_main * 1000.0 / (angle_steel[-1]["area"] * 100),
"stress_ratio": 1.5}
self.results["主材轴力"] = N_main
self.results["主材规格"] = selected["name"]
self.results["主材面积"] = selected["area"]
self.results["长细比"] = selected["lambda"]
self.results["稳定系数"] = selected["phi"]
self.results["稳定应力"] = selected["sigma_stability"]
self.results["强度应力"] = selected["sigma_strength"]
self.results["应力比"] = selected["stress_ratio"]
self.results["主材验算通过"] = selected["stress_ratio"] <= 1.0
return selected
def calc_foundation(self):
"""基础底面积计算"""
N = self.results["基底轴力"]
M = self.results["基底弯矩"]
V = self.results["基底剪力"]
fa = 200
gamma_m = 20.0
d = 2.0
fa_mod = fa + gamma_m * d * (1.0 - 0.5)
h_f = 2.0
b = math.sqrt(N / fa_mod)
for _ in range(200):
A_req = b * b
W = b ** 3 / 6.0
p_max = N / A_req + M / W
G_foundation = 25.0 * b * b * h_f
M_resist = (N + G_foundation) * b / 2.0 + 0.5 * gamma_m * b * h_f * d * b / 3.0
k_ot = M_resist / M if M > 0 else 99.0
if p_max <= fa_mod and k_ot >= 1.6:
break
b += 0.05
p_min = N / A_req - M / W
k_overturn = k_ot
self.results["地基承载力"] = fa
self.results["修正承载力"] = fa_mod
self.results["基础底面积"] = A_req
self.results["基础边长"] = b
self.results["基础埋深"] = d
self.results["基底最大应力"] = p_max
self.results["基底最小应力"] = p_min
self.results["抗倾覆安全系数"] = k_overturn
self.results["基础验算通过"] = p_max <= fa_mod and k_overturn >= 1.6
return {"b": b, "A": A_req, "p_max": p_max, "p_min": p_min, "k": k_overturn}
def calc_stability(self):
"""整体稳定验算"""
M = self.results["基底弯矩"]
N = self.results["基底轴力"]
V = self.results["基底剪力"]
base_width = self.results["塔底宽度"]
M_resist = (N + 25.0 * base_width * base_width * 2.0) * base_width / 2.0 + 80.0 * base_width
k_overturn = M_resist / M if M > 0 else 99.0
mu_f = 0.4
F_resist = mu_f * (N + 25.0 * base_width * base_width * 2.0)
k_sliding = F_resist / V if V > 0 else 99.0
self.results["整体抗倾覆系数"] = k_overturn
self.results["整体抗滑移系数"] = k_sliding
self.results["整体稳定验算通过"] = k_overturn >= 1.5 and k_sliding >= 1.3
return {"k_overturn": k_overturn, "k_sliding": k_sliding}
def run_all(self):
"""执行全部计算"""
self.calc_wind_load_tower()
self.calc_wind_load_wire()
self.calc_internal_forces()
self.calc_main_member()
self.calc_foundation()
self.calc_stability()
return self.results