windamir123 commited on
Commit
fe5061b
·
verified ·
1 Parent(s): 1fb92ed

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +173 -0
app.py CHANGED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ # Busbar sizing Gradio app
3
+ # Run locally: pip install -r requirements.txt ; python app.py
4
+ # To deploy on Hugging Face Spaces: push this file + requirements.txt to your space repo.
5
+
6
+ import math
7
+ import gradio as gr
8
+ import pandas as pd
9
+
10
+ # Material properties and default current densities (A/mm^2)
11
+ # These are conservative engineering defaults — adjust per your standards/practice.
12
+ MATERIALS = {
13
+ "Copper": {
14
+ "resistivity": 1.724e-8, # ohm·m at 20°C
15
+ "J_natural": 1.6, # A/mm^2 (natural convection)
16
+ "J_forced": 2.5, # A/mm^2 (forced air / ventilated)
17
+ },
18
+ "Aluminium": {
19
+ "resistivity": 2.82e-8, # ohm·m at 20°C
20
+ "J_natural": 0.9,
21
+ "J_forced": 1.4,
22
+ }
23
+ }
24
+
25
+ # Common commercial thicknesses (mm) and widths (mm) to propose (you can extend)
26
+ COMMON_THICKNESSES = [3, 5, 6, 8, 10, 12, 15] # mm
27
+ COMMON_WIDTHS = [10, 12, 15, 20, 25, 30, 40, 50, 60, 80, 100, 120, 150, 200] # mm
28
+
29
+ def nearest_busbar_size(required_area_mm2, thicknesss=COMMON_THICKNESSES, widths=COMMON_WIDTHS):
30
+ """
31
+ Find the smallest commercial thickness x width combination whose area >= required_area_mm2.
32
+ Returns a list of candidate dicts sorted ascending by area.
33
+ """
34
+ candidates = []
35
+ for t in thicknesss:
36
+ for w in widths:
37
+ area = t * w # mm^2 for rectangular busbar
38
+ if area >= required_area_mm2:
39
+ candidates.append({
40
+ "thickness_mm": t,
41
+ "width_mm": w,
42
+ "area_mm2": area
43
+ })
44
+ # if none found (very large current), return a few top oversized combos
45
+ if not candidates:
46
+ # create a fallback by scaling up widths
47
+ scale = 2
48
+ for t in thicknesss:
49
+ w = widths[-1] * scale
50
+ candidates.append({"thickness_mm": t, "width_mm": w, "area_mm2": t * w})
51
+ candidates.sort(key=lambda x: x["area_mm2"])
52
+ return candidates[:6]
53
+ candidates.sort(key=lambda x: (x["area_mm2"], x["thickness_mm"], x["width_mm"]))
54
+ return candidates[:6] # top 6 suggestions
55
+
56
+ def size_busbar(current_A: float,
57
+ material: str = "Copper",
58
+ cooling: str = "Natural (no forced ventilation)",
59
+ select_thickness: int = None,
60
+ prefer_forced: bool = False,
61
+ voltage_V: float = 415.0):
62
+ """
63
+ Main calculation function for busbar sizing.
64
+ """
65
+ # Input validation / fixups
66
+ if current_A <= 0:
67
+ return "Current must be positive.", None, None
68
+
69
+ mat = MATERIALS.get(material)
70
+ if mat is None:
71
+ return f"Unknown material: {material}", None, None
72
+
73
+ # Choose current density J (A/mm^2)
74
+ if "forced" in cooling.lower() or prefer_forced:
75
+ J = mat["J_forced"]
76
+ cooling_label = "Forced ventilation"
77
+ else:
78
+ J = mat["J_natural"]
79
+ cooling_label = "Natural convection"
80
+
81
+ required_area_mm2 = current_A / J # mm^2
82
+
83
+ # If user selected a thickness, compute required width
84
+ suggestions = []
85
+ if select_thickness in COMMON_THICKNESSES:
86
+ t = select_thickness
87
+ required_width = math.ceil(required_area_mm2 / t)
88
+ # round up to nearest standard width
89
+ std_width = next((w for w in COMMON_WIDTHS if w >= required_width), required_width)
90
+ area_actual = t * std_width
91
+ suggestions.append({
92
+ "thickness_mm": t,
93
+ "width_mm": std_width,
94
+ "area_mm2": area_actual
95
+ })
96
+ else:
97
+ suggestions = nearest_busbar_size(required_area_mm2)
98
+
99
+ # pick the best suggestion (smallest area)
100
+ best = suggestions[0]
101
+
102
+ # Resistance per meter (DC approximation)
103
+ area_m2 = best["area_mm2"] * 1e-6 # mm2 -> m2
104
+ resistivity = mat["resistivity"]
105
+ R_per_m = resistivity / area_m2 # ohm per meter
106
+ voltage_drop_per_m_V = R_per_m * current_A
107
+ percent_drop_per_m = (voltage_drop_per_m_V / voltage_V) * 100
108
+
109
+ # Build outputs
110
+ summary = (
111
+ f"Design current: {current_A:.1f} A\n"
112
+ f"Material: {material}\n"
113
+ f"Cooling: {cooling_label}\n"
114
+ f"Design current density used: {J:.2f} A/mm²\n"
115
+ f"Required cross-sectional area (ideal): {required_area_mm2:.2f} mm²\n\n"
116
+ f"Recommended busbar (best match): {best['thickness_mm']} mm thick × {best['width_mm']} mm wide\n"
117
+ f" -> Cross-sectional area: {best['area_mm2']:.1f} mm²\n\n"
118
+ f"Estimated DC resistance: {R_per_m:.6f} Ω/m\n"
119
+ f"Voltage drop at {current_A:.1f} A: {voltage_drop_per_m_V:.3f} V/m ({percent_drop_per_m:.4f}% of {voltage_V} V per meter)\n\n"
120
+ "Note: This is a simplified design aid. Verify with thermal/mechanical checks, short-circuit stability, standards (IEC/NEC/IEC 61439 etc.), and local practice."
121
+ )
122
+
123
+ # Prepare a DataFrame of the suggestions for display
124
+ df = pd.DataFrame(suggestions)
125
+ df = df[["thickness_mm", "width_mm", "area_mm2"]]
126
+ df.columns = ["Thickness (mm)", "Width (mm)", "Area (mm²)"]
127
+
128
+ return summary, df, {
129
+ "required_area_mm2": round(required_area_mm2, 2),
130
+ "chosen_thickness_mm": best["thickness_mm"],
131
+ "chosen_width_mm": best["width_mm"],
132
+ "chosen_area_mm2": best["area_mm2"],
133
+ "resistance_ohm_per_m": R_per_m,
134
+ "voltage_drop_V_per_m": voltage_drop_per_m_V
135
+ }
136
+
137
+
138
+ # ---- Gradio UI ----
139
+ with gr.Blocks(title="Busbar sizing calculator") as demo:
140
+ gr.Markdown("# Busbar sizing — Gradio app\nEnter design current and choices; app suggests rectangular busbar sizes.")
141
+ with gr.Row():
142
+ with gr.Column():
143
+ current_in = gr.Number(label="Design current (A)", value=400, precision=1)
144
+ material_in = gr.Radio(choices=list(MATERIALS.keys()), value="Copper", label="Material")
145
+ cooling_in = gr.Radio(choices=["Natural (no forced ventilation)", "Forced ventilation"], value="Natural (no forced ventilation)", label="Cooling")
146
+ prefer_forced = gr.Checkbox(label="Prefer forced-ventilation values (override cooling)", value=False)
147
+ thickness_in = gr.Dropdown(choices=["Auto (choose best)"] + [str(t) for t in COMMON_THICKNESSES], value="Auto (choose best)", label="Prefer thickness (mm) - optional")
148
+ voltage_in = gr.Number(label="Nominal system voltage (V) — for % drop calc", value=415)
149
+
150
+ run_btn = gr.Button("Calculate")
151
+ with gr.Column():
152
+ output_text = gr.Textbox(label="Summary", interactive=False, lines=10)
153
+ output_table = gr.Dataframe(label="Suggested commercial sizes", interactive=False)
154
+ output_json = gr.JSON(label="Raw results (for engineering use)")
155
+
156
+ def on_calculate(current, material, cooling, prefer_forced, thickness_choice, voltage):
157
+ sel_thickness = None
158
+ if thickness_choice and thickness_choice != "Auto (choose best)":
159
+ try:
160
+ sel_thickness = int(thickness_choice)
161
+ except:
162
+ sel_thickness = None
163
+ summary, df, raw = size_busbar(current, material, cooling, sel_thickness, prefer_forced, voltage)
164
+ return summary, df, raw
165
+
166
+ run_btn.click(
167
+ on_calculate,
168
+ inputs=[current_in, material_in, cooling_in, prefer_forced, thickness_in, voltage_in],
169
+ outputs=[output_text, output_table, output_json]
170
+ )
171
+
172
+ if __name__ == "__main__":
173
+ demo.launch(server_name="0.0.0.0", server_port=7860)