physics-simulation / pages /basic-circuit-analysis.py
shikharyashmaurya's picture
Added new folder
dfc428f
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Circle, FancyArrowPatch
st.set_page_config(page_title="Circuit Analysis Simulator", layout="wide")
st.title("Interactive Circuit Analysis Simulator")
st.write("Explore basic circuit concepts including Ohm's Law, series and parallel circuits.")
# Sidebar for navigation
page = st.sidebar.radio("Choose a Simulation",
["Ohm's Law", "Series Circuit", "Parallel Circuit"])
if page == "Ohm's Law":
st.header("Ohm's Law: V = I × R")
st.write("""
Ohm's Law describes the relationship between voltage (V), current (I), and resistance (R).
Adjust the sliders to see how changing one parameter affects the others.
""")
col1, col2 = st.columns(2)
with col1:
# Let user control two of the variables and calculate the third
calculation_mode = st.radio(
"What do you want to calculate?",
["Voltage", "Current", "Resistance"]
)
if calculation_mode == "Voltage":
current = st.slider("Current (A)", 0.1, 10.0, 1.0, 0.1)
resistance = st.slider("Resistance (Ω)", 1.0, 100.0, 10.0, 1.0)
voltage = current * resistance
st.success(f"Calculated Voltage: {voltage:.2f} V")
elif calculation_mode == "Current":
voltage = st.slider("Voltage (V)", 1.0, 220.0, 12.0, 1.0)
resistance = st.slider("Resistance (Ω)", 1.0, 100.0, 10.0, 1.0)
current = voltage / resistance if resistance != 0 else float('inf')
st.success(f"Calculated Current: {current:.2f} A")
else: # Resistance
voltage = st.slider("Voltage (V)", 1.0, 220.0, 12.0, 1.0)
current = st.slider("Current (A)", 0.1, 10.0, 1.0, 0.1)
resistance = voltage / current if current != 0 else float('inf')
st.success(f"Calculated Resistance: {resistance:.2f} Ω")
with col2:
# Create visualization
fig, ax = plt.subplots(figsize=(8, 6))
# Draw battery
battery_height = 1.5
battery_x = 1
battery_y = 3
# Long line
ax.plot([battery_x, battery_x + 6], [battery_y + battery_height, battery_y + battery_height], 'k-', lw=2)
# Bottom line
ax.plot([battery_x, battery_x + 6], [battery_y, battery_y], 'k-', lw=2)
# Battery
ax.plot([battery_x, battery_x], [battery_y, battery_y + battery_height], 'k-', lw=2)
ax.plot([battery_x + 0.2, battery_x + 0.2], [battery_y + 0.25, battery_y + battery_height - 0.25], 'k-', lw=4)
ax.plot([battery_x + 0.5, battery_x + 0.5], [battery_y + 0.5, battery_y + battery_height - 0.5], 'k-', lw=2)
# Resistor (zigzag)
res_x = battery_x + 3
res_y = battery_y + battery_height
zigzag_width = 1.5
zigzag_height = 0.5
zigzag_pts = 7
x_pts = np.linspace(res_x, res_x + zigzag_width, zigzag_pts)
y_pts = np.array([0, 1, 0, 1, 0, 1, 0]) * zigzag_height + res_y
ax.plot(x_pts, y_pts, 'k-', lw=2)
# Add current direction arrow
if calculation_mode == "Current" or calculation_mode == "Resistance":
current_value = current
else:
current_value = current
# Scale arrow size based on current
arrow_scale = min(1, current_value / 5)
arrow_width = 0.15 * (0.5 + arrow_scale)
arrow = FancyArrowPatch((battery_x + 4.5, battery_y + 0.5),
(battery_x + 3, battery_y + 0.5),
arrowstyle='->',
color='blue',
lw=2,
mutation_scale=20)
ax.add_patch(arrow)
ax.text(battery_x + 3.8, battery_y + 0.3, f"{current:.1f} A", color='blue')
# Add voltage label
if calculation_mode == "Voltage" or calculation_mode == "Resistance":
voltage_value = voltage
else:
voltage_value = voltage
ax.text(battery_x + 0.7, battery_y + 0.75, f"{voltage:.1f} V", color='red')
# Add resistance label
if calculation_mode == "Resistance" or calculation_mode == "Voltage":
resistance_value = resistance
else:
resistance_value = resistance
ax.text(res_x + 0.2, res_y + 0.75, f"{resistance:.1f} Ω", color='green')
ax.set_xlim(0, 8)
ax.set_ylim(1, 6)
ax.axis('equal')
ax.axis('off')
st.pyplot(fig)
# Show the formula and calculation
st.write("### Ohm's Law Formula")
if calculation_mode == "Voltage":
st.latex(r"V = I \times R")
st.latex(f"V = {current:.2f} \, A \times {resistance:.2f} \, \Omega = {voltage:.2f} \, V")
elif calculation_mode == "Current":
st.latex(r"I = \frac{V}{R}")
st.latex(f"I = \\frac{{{voltage:.2f} \, V}}{{{resistance:.2f} \, \Omega}} = {current:.2f} \, A")
else: # Resistance
st.latex(r"R = \frac{V}{I}")
st.latex(f"R = \\frac{{{voltage:.2f} \, V}}{{{current:.2f} \, A}} = {resistance:.2f} \, \Omega")
elif page == "Series Circuit":
st.header("Series Circuit Analysis")
st.write("""
In a series circuit, the same current flows through each component, and the total voltage is the sum of the voltages across each component.
""")
col1, col2 = st.columns(2)
with col1:
# User inputs
voltage_source = st.slider("Voltage Source (V)", 1.0, 24.0, 12.0, 0.1)
st.subheader("Resistors in Series")
num_resistors = st.slider("Number of Resistors", 1, 5, 3)
resistances = []
for i in range(num_resistors):
r = st.slider(f"R{i+1} (Ω)", 1.0, 100.0, 10.0 * (i+1), 1.0, key=f"series_r{i}")
resistances.append(r)
# Calculations
total_resistance = sum(resistances)
current = voltage_source / total_resistance if total_resistance > 0 else 0
voltage_drops = [current * r for r in resistances]
power_dissipations = [current**2 * r for r in resistances]
st.subheader("Circuit Analysis Results")
st.write(f"Total Resistance: {total_resistance:.2f} Ω")
st.write(f"Current: {current:.2f} A")
# Display voltage drops and power for each resistor
for i in range(num_resistors):
st.write(f"R{i+1}: Voltage Drop = {voltage_drops[i]:.2f} V, Power = {power_dissipations[i]:.2f} W")
with col2:
# Create visualization of series circuit
fig, ax = plt.subplots(figsize=(8, 6))
# Draw circuit
start_x, start_y = 1, 5
# Draw battery
battery_height = 1.5
battery_x = start_x
battery_y = start_y - battery_height/2
# Battery
ax.plot([battery_x, battery_x], [battery_y, battery_y + battery_height], 'k-', lw=2)
ax.plot([battery_x + 0.2, battery_x + 0.2], [battery_y + 0.25, battery_y + battery_height - 0.25], 'k-', lw=4)
ax.plot([battery_x + 0.5, battery_x + 0.5], [battery_y + 0.5, battery_y + battery_height - 0.5], 'k-', lw=2)
# Label voltage source
ax.text(battery_x + 0.7, battery_y + 0.75, f"{voltage_source:.1f} V", color='red')
# Draw wires and resistors in series
line_length = 10 / (num_resistors + 1)
# Top line from battery to first resistor
ax.plot([battery_x + 0.5, battery_x + line_length], [battery_y + battery_height - 0.5, battery_y + battery_height - 0.5], 'k-', lw=2)
# Draw resistors in series
for i in range(num_resistors):
res_x = battery_x + line_length * (i + 1)
res_y = battery_y + battery_height - 0.5
# Draw resistor (zigzag)
zigzag_width = 1.0
zigzag_height = 0.5
zigzag_pts = 7
x_pts = np.linspace(res_x, res_x + zigzag_width, zigzag_pts)
y_pts = np.array([0, 1, 0, 1, 0, 1, 0]) * zigzag_height + res_y
ax.plot(x_pts, y_pts, 'k-', lw=2)
# Label resistor
ax.text(res_x + 0.2, res_y + 0.8, f"R{i+1}\n{resistances[i]:.1f}Ω\n{voltage_drops[i]:.1f}V", fontsize=8)
# Connect to next resistor if not the last one
if i < num_resistors - 1:
ax.plot([res_x + zigzag_width, res_x + line_length], [res_y, res_y], 'k-', lw=2)
# Bottom line back to battery
ax.plot([battery_x + line_length * (num_resistors + 1) - line_length + zigzag_width, battery_x + 0.5],
[res_y, battery_y + 0.5], 'k-', lw=2)
# Add current direction arrow
arrow = FancyArrowPatch((battery_x + 0.5, battery_y + 0.5),
(battery_x + line_length/2, battery_y + 0.5),
arrowstyle='->',
color='blue',
lw=2,
mutation_scale=15)
ax.add_patch(arrow)
ax.text(battery_x + line_length/4, battery_y + 0.2, f"{current:.1f}A", color='blue', fontsize=9)
ax.set_xlim(0, 12)
ax.set_ylim(2, 8)
ax.axis('equal')
ax.axis('off')
st.pyplot(fig)
# Show formulas
st.write("### Series Circuit Formulas")
st.latex(r"R_{total} = R_1 + R_2 + ... + R_n")
st.latex(f"R_{{total}} = {' + '.join([f'{r:.1f}' for r in resistances])} = {total_resistance:.2f} \, \Omega")
st.latex(r"I = \frac{V_{source}}{R_{total}}")
st.latex(f"I = \\frac{{{voltage_source:.2f}}}{{{total_resistance:.2f}}} = {current:.2f} \, A")
st.latex(r"V_n = I \times R_n")
elif page == "Parallel Circuit":
st.header("Parallel Circuit Analysis")
st.write("""
In a parallel circuit, each component has the same voltage across it, and the total current is the sum of the currents through each path.
""")
col1, col2 = st.columns(2)
with col1:
# User inputs
voltage_source = st.slider("Voltage Source (V)", 1.0, 24.0, 12.0, 0.1)
st.subheader("Resistors in Parallel")
num_resistors = st.slider("Number of Resistors", 1, 5, 3)
resistances = []
for i in range(num_resistors):
r = st.slider(f"R{i+1} (Ω)", 1.0, 100.0, float(10.0 * (i+1)), 1.0, key=f"parallel_r{i}")
resistances.append(r)
# Calculations
inverse_resistance_sum = sum(1/r for r in resistances) if resistances else 0
total_resistance = 1/inverse_resistance_sum if inverse_resistance_sum > 0 else float('inf')
branch_currents = [voltage_source / r for r in resistances]
total_current = sum(branch_currents)
power_dissipations = [(voltage_source ** 2) / r for r in resistances]
total_power = voltage_source * total_current
st.subheader("Circuit Analysis Results")
st.write(f"Total Resistance: {total_resistance:.2f} Ω")
st.write(f"Total Current: {total_current:.2f} A")
# Display current and power for each resistor
for i in range(num_resistors):
st.write(f"R{i+1}: Current = {branch_currents[i]:.2f} A, Power = {power_dissipations[i]:.2f} W")
with col2:
# Create visualization of parallel circuit
fig, ax = plt.subplots(figsize=(8, 6))
# Draw circuit
start_x, start_y = 1, 5
end_x = 9
# Draw battery
battery_height = 1.5
battery_x = start_x
battery_y = start_y - battery_height/2
# Battery
ax.plot([battery_x, battery_x], [battery_y, battery_y + battery_height], 'k-', lw=2)
ax.plot([battery_x + 0.2, battery_x + 0.2], [battery_y + 0.25, battery_y + battery_height - 0.25], 'k-', lw=4)
ax.plot([battery_x + 0.5, battery_x + 0.5], [battery_y + 0.5, battery_y + battery_height - 0.5], 'k-', lw=2)
# Label voltage source
ax.text(battery_x + 0.7, battery_y + 0.75, f"{voltage_source:.1f} V", color='red')
# Top horizontal line
ax.plot([battery_x + 0.5, end_x], [battery_y + battery_height - 0.5, battery_y + battery_height - 0.5], 'k-', lw=2)
# Bottom horizontal line
ax.plot([battery_x + 0.5, end_x], [battery_y + 0.5, battery_y + 0.5], 'k-', lw=2)
# Add main current arrow
arrow = FancyArrowPatch((battery_x + 1.5, battery_y + battery_height - 0.5),
(battery_x + 2.5, battery_y + battery_height - 0.5),
arrowstyle='->',
color='blue',
lw=2,
mutation_scale=15)
ax.add_patch(arrow)
ax.text(battery_x + 1.5, battery_y + battery_height - 0.8, f"{total_current:.1f}A", color='blue')
# Draw resistors in parallel
spacing = 5.0 / (num_resistors + 1)
for i in range(num_resistors):
res_x = battery_x + 2.5 + i * spacing
res_y_top = battery_y + battery_height - 0.5
res_y_bottom = battery_y + 0.5
# Vertical lines to resistor
ax.plot([res_x, res_x], [res_y_top, res_y_top - 1], 'k-', lw=2)
ax.plot([res_x, res_x], [res_y_bottom, res_y_bottom + 1], 'k-', lw=2)
# Draw resistor (zigzag horizontal)
zigzag_height = 1.0
zigzag_width = 0.5
zigzag_pts = 7
y_pts = np.linspace(res_y_top - 1, res_y_bottom + 1, zigzag_pts)
x_pts = np.array([0, 1, 0, 1, 0, 1, 0]) * zigzag_width + res_x
ax.plot(x_pts, y_pts, 'k-', lw=2)
# Branch current arrow
branch_arrow = FancyArrowPatch((res_x - 0.3, res_y_top - 0.5),
(res_x - 0.3, res_y_top - 1.5),
arrowstyle='->',
color='blue',
lw=2,
mutation_scale=15)
ax.add_patch(branch_arrow)
# Label resistor and current
ax.text(res_x + 0.6, res_y_top - 1.5, f"R{i+1}\n{resistances[i]:.1f}Ω\n{branch_currents[i]:.2f}A", fontsize=8)
ax.set_xlim(0, 12)
ax.set_ylim(2, 8)
ax.axis('equal')
ax.axis('off')
st.pyplot(fig)
# Show formulas
st.write("### Parallel Circuit Formulas")
st.latex(r"\frac{1}{R_{total}} = \frac{1}{R_1} + \frac{1}{R_2} + ... + \frac{1}{R_n}")
# Create the fractions part without f-strings
fractions_parts = []
for r in resistances:
fractions_parts.append(r"\frac{1}{" + f"{r:.1f}" + "}")
fractions_text = " + ".join(fractions_parts)
st.latex(r"\frac{1}{R_{total}} = " + fractions_text + f" = {inverse_resistance_sum:.4f}")
st.latex(r"R_{total} = \frac{1}{" + f"{inverse_resistance_sum:.4f}" + r"} = " + f"{total_resistance:.2f} \, \Omega")
st.latex(r"I_{total} = I_1 + I_2 + ... + I_n")
st.latex(f"I_{{total}} = {' + '.join([f'{i:.2f}' for i in branch_currents])} = {total_current:.2f} \, A")
st.latex(r"I_n = \frac{V}{R_n}")
st.sidebar.markdown('''File "D:\projects\physics-simulations\pages\basic-circuit-analysis.py", line 359
fractions_parts.append(r""\frac{1}{""" + f"{r:.1f}" + r""}""")
^
SyntaxError: unexpected character after line continuation character
### Basic Circuit Concepts
**Ohm's Law:** V = IR
- V: Voltage (Volts)
- I: Current (Amperes)
- R: Resistance (Ohms)
**Series Circuit Properties:**
- Same current through all components
- Rtotal = R1 + R2 + ... + Rn
- Vtotal = V1 + V2 + ... + Vn
**Parallel Circuit Properties:**
- Same voltage across all components
- 1/Rtotal = 1/R1 + 1/R2 + ... + 1/Rn
- Itotal = I1 + I2 + ... + In
''')