File size: 7,160 Bytes
b060cbb
 
 
 
 
888a9bd
b060cbb
 
 
888a9bd
 
b060cbb
888a9bd
b060cbb
 
888a9bd
b060cbb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
888a9bd
 
b060cbb
 
 
 
 
 
888a9bd
b060cbb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
888a9bd
 
 
 
b060cbb
 
 
 
 
 
888a9bd
b060cbb
 
 
 
 
888a9bd
b060cbb
888a9bd
 
 
f78204f
 
888a9bd
 
 
 
b060cbb
888a9bd
 
b060cbb
888a9bd
b060cbb
 
 
888a9bd
b060cbb
 
888a9bd
 
 
b060cbb
 
 
 
 
 
 
 
888a9bd
 
 
 
b060cbb
888a9bd
 
 
 
b060cbb
 
888a9bd
 
b060cbb
 
 
 
 
 
 
 
 
888a9bd
 
b060cbb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
888a9bd
b060cbb
 
 
 
 
 
 
 
 
888a9bd
 
 
 
 
 
 
b060cbb
 
 
 
 
888a9bd
b060cbb
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
import gradio as gr
import math
import itertools
import ezdxf
import os
import groq
from ezdxf import zoom
from ezdxf.enums import TextEntityAlignment

# Initialize Groq client
client = groq.Client(api_key=os.getenv("GROQ_API_KEY"))

# Available Capacitor Units (kVAR)
available_capacitors = [25, 20, 15, 10, 5, 2.5, 1.5, 1]

# Prompt Groq for explanation (optional)
def ask_groq(prompt):
    try:
        response = client.chat.completions.create(
            model="llama3-8b-8192",
            messages=[{"role": "user", "content": prompt}]
        )
        return response.choices[0].message.content
    except Exception as e:
        return f"Groq Error: {str(e)}"

def calculate_power_parameters(voltage, current, power_factor):
    if voltage > 0 and current > 0:
        apparent_power = math.sqrt(3) * voltage * current
        real_power = apparent_power * power_factor / 1000
        try:
            reactive_power = math.sqrt((apparent_power / 1000) ** 2 - real_power ** 2)
        except ValueError:
            reactive_power = 0.0
        calculated_pf = real_power * 1000 / apparent_power if apparent_power > 0 else 0
        return {
            "apparent_power": round(apparent_power, 2),
            "real_power": round(real_power, 2),
            "reactive_power": round(reactive_power, 2),
            "calculated_pf": round(calculated_pf, 2)
        }
    else:
        return None

def design_capacitor_bank(reactive_power, num_caps):
    if reactive_power > 0 and num_caps > 0:
        best_combo = None
        min_error = float('inf')

        # Allow repetition freely to match reactive power
        combos = itertools.combinations_with_replacement(available_capacitors, num_caps)
        for combo in combos:
            total = sum(combo)
            error = abs(total - reactive_power)
            if error < min_error:
                min_error = error
                best_combo = combo
            if error == 0:
                break

        if best_combo:
            suggested_capacitors = [f"{cap} kVAR" for cap in best_combo]
            total_kvar = sum(best_combo)
            message = f"Total Compensation: {round(total_kvar, 2)} kVAR"
            return {
                "suggested_capacitors": suggested_capacitors,
                "total_kvar": round(total_kvar, 2),
                "message": message,
                "combo": best_combo
            }
        else:
            return {"message": "Could not find a suitable combination."}
    else:
        return None

def create_dxf_capacitor_bank(capacitors):
    doc = ezdxf.new()
    msp = doc.modelspace()
    x = 0
    y = 0
    row_width = 15  # Distance between capacitors in a row
    row_height = 20
    max_in_row = 5
    
    for idx, cap in enumerate(capacitors):
        label = f"{cap} kVAR"
        # Draw rectangle for capacitor
        points = [(x, y), (x + 10, y), (x + 10, y + 10), (x, y + 10), (x, y)]
        msp.add_lwpolyline(points, close=True, dxfattribs={'color': 3})  # Color 3 = Green
        
        # Add Text with more control
        text = msp.add_text(label, dxfattribs={
            'height': 2.5,
            'color': 4, # color Cyan
            'style': 'STANDARD',  # You can define text styles in DXF
            'halign': TextEntityAlignment.CENTER,  # Horizontal alignment
            'valign': TextEntityAlignment.BOTTOM if hasattr(TextEntityAlignment, 'BOTTOM') else 2,
        })
        text.dxf.insert = (x + 5, y + 5)  # Position at center of rectangle
        
        x += row_width
        if (idx + 1) % max_in_row == 0:  # Move to the next row
            x = 0
            y += row_height

    # Add a title
    title_text = msp.add_text("Capacitor Bank Layout", dxfattribs={'height': 5, 'color': 1})
    title_text.dxf.insert = (0, y + 30)
    
    # Zoom to extents
    zoom.extents(msp, factor=1.1)  # Add a small padding
    
    output_path = "capacitor_bank_layout.dxf"
    doc.saveas(output_path)
    return output_path

def reactive_power_first(voltage, current, power_factor):
    power_results = calculate_power_parameters(voltage, current, power_factor)
    if power_results:
        apparent_power_out = f"Apparent Power: **{power_results['apparent_power']} VA**"
        real_power_out = f"Real Power: **{power_results['real_power']} kW**"
        reactive_power_out = f"Reactive Power: **{power_results['reactive_power']} kVAR**"
        calculated_pf_out = f"Calculated Power Factor: **{power_results['calculated_pf']}**"
        return (
            apparent_power_out,
            real_power_out,
            reactive_power_out,
            calculated_pf_out,
            power_results['reactive_power']
        )
    else:
        return ("⚠️ Please enter valid Voltage and Current!", "", "", "", 0)

def finalize_capacitor_bank(reactive_power, num_caps):
    cap_bank_design = design_capacitor_bank(reactive_power, num_caps)
    if cap_bank_design and cap_bank_design.get("suggested_capacitors"):
        suggested_capacitors_text = "<br>".join(
            [f"🔹 Capacitor {idx + 1}: **{cap}**" for idx, cap in enumerate(cap_bank_design['suggested_capacitors'])]
        )
        dxf_path = create_dxf_capacitor_bank(cap_bank_design["combo"])
        return suggested_capacitors_text, cap_bank_design['message'], dxf_path
    else:
        return "Could not find a suitable combination.", "", None

with gr.Blocks() as iface:
    gr.Markdown("# ⚡ Three-Phase Power Calculator - Reactive Power Compensation")
    gr.Markdown("""
    Step 1: Enter system parameters to calculate apparent and reactive power.<br>
    Step 2: Input number of capacitors to compute optimal configuration.<br>
    Step 3: Download AutoCAD (.dxf) layout.
    """)

    with gr.Row():
        voltage = gr.Number(label="Enter Voltage (V)", value=415)
        current = gr.Number(label="Enter Current (A)", value=250)
        power_factor = gr.Slider(label="Power Factor", minimum=0.0, maximum=1.0, value=0.85, step=0.01)
        frequency = gr.Radio(label="Select Frequency", choices=[50, 60], value=50)

    calc_btn = gr.Button("🔍 Calculate Power Parameters")

    apparent_power_out = gr.HTML()
    real_power_out = gr.HTML()
    reactive_power_out = gr.HTML()
    calculated_pf_out = gr.HTML()
    reactive_value = gr.Number(visible=False)

    calc_btn.click(
        fn=reactive_power_first,
        inputs=[voltage, current, power_factor],
        outputs=[
            apparent_power_out,
            real_power_out,
            reactive_power_out,
            calculated_pf_out,
            reactive_value
        ]
    )

    gr.Markdown("### ➕ Enter number of capacitors to compensate reactive power:")
    num_caps_input = gr.Number(label="Number of Capacitors", precision=0)
    finalize_btn = gr.Button("⚙️ Generate Capacitor Bank")

    capacitor_out = gr.HTML()
    total_comp_out = gr.HTML()
    dxf_file = gr.File(label="📥 Download AutoCAD File")

    finalize_btn.click(
        fn=finalize_capacitor_bank,
        inputs=[reactive_value, num_caps_input],
        outputs=[capacitor_out, total_comp_out, dxf_file]
    )

if __name__ == "__main__":
    iface.launch()