Prawo Gausa dla pola elektrycznego¶
In [15]:
# ...existing code...
import sympy as sp
import numpy as np
import plotly as plt
import plotly.graph_objects as go
from IPython.display import display
plt.io.renderers.default = "notebook_connected" # musi być jeżeli chcemy do html-a
# Symbole symboliczne
x, y, z = sp.symbols('x y z')
epsilon_0_sym, Q_sym = sp.symbols('epsilon_0 Q')
# Wyrażenia symboliczne (Gauss, pole punktowego ładunku)
Phi_E_sym = Q_sym / epsilon_0_sym
r_expr = sp.sqrt(x**2 + y**2 + z**2)
E_sym = Q_sym / (4 * sp.pi * epsilon_0_sym * r_expr**2)
Ex_sym = Q_sym / (4 * sp.pi * epsilon_0_sym) * x / r_expr**3
Ey_sym = Q_sym / (4 * sp.pi * epsilon_0_sym) * y / r_expr**3
Ez_sym = Q_sym / (4 * sp.pi * epsilon_0_sym) * z / r_expr**3
# Wyświetl wyrażenia symboliczne
display(sp.Eq(sp.symbols('Phi_E'), Phi_E_sym))
display(sp.Eq(sp.symbols('E'), E_sym))
display(sp.Eq(sp.symbols('E_x'), Ex_sym))
# Zamiana na funkcje numeryczne (NumPy) za pomocą lambdify
Ex_num = sp.lambdify((x, y, z, Q_sym, epsilon_0_sym), Ex_sym, 'numpy')
Ey_num = sp.lambdify((x, y, z, Q_sym, epsilon_0_sym), Ey_sym, 'numpy')
Ez_num = sp.lambdify((x, y, z, Q_sym, epsilon_0_sym), Ez_sym, 'numpy')
# Wartość numeryczna przenikalności próżni (do obliczeń numerycznych)
epsilon_0 = 8.854187817e-12 # F/m
def plot_electric_field(Q_value=10.0, extent=1.0, n=5, min_r=0.5):
"""
Rysuje pole elektryczne punktowego ładunku używając wyrażeń SymPy -> lambdify.
"""
# Q_value - wartość ładunku punktowego
# n - liczba punktów w każdej osi
# extent - zakres osi od -extent do +extent
# min_r - minimalny promień od ładunku (unikamy singularności)
# Siatka punktów
x_grid = np.linspace(-extent, extent, n)
y_grid = np.linspace(-extent, extent, n)
z_grid = np.linspace(-extent, extent, n)
X, Y, Z = np.meshgrid(x_grid, y_grid, z_grid)
R = np.sqrt(X**2 + Y**2 + Z**2)
# Wybieramy tylko punkty poza minimalnym promieniem (unikamy singularności w środku)
mask = (R.flatten() >= min_r)
x_flat = X.flatten()[mask]
y_flat = Y.flatten()[mask]
z_flat = Z.flatten()[mask]
# Obliczenia numeryczne z użyciem funkcji utworzonych przez lambdify
u = Ex_num(x_flat, y_flat, z_flat, Q_value, epsilon_0)
v = Ey_num(x_flat, y_flat, z_flat, Q_value, epsilon_0)
w = Ez_num(x_flat, y_flat, z_flat, Q_value, epsilon_0)
# Przygotowanie rozmiaru stożków (Plotly używa sizeref, nie 'size')
E_mag = np.sqrt(u**2 + v**2 + w**2)
maxE = np.max(E_mag) if E_mag.size > 0 else 0.0
sizeref = 0.5 * maxE if maxE > 0 else 0.1
#sizeref = sizeref * 4 # Skalowanie dla lepszej widoczności
fig = go.Figure(data=go.Cone(
x=x_flat, y=y_flat, z=z_flat,
u=u, v=v, w=w,
sizemode='absolute', sizeref=sizeref, anchor='tail',
colorscale='Viridis', showscale=True,
colorbar=dict(title='|E| [jedn.]'),
name=f'Pole E (Q={Q_value})',
showlegend=True
))
fig.update_layout(
scene=dict(
xaxis_title='X [jedn.]',
yaxis_title='Y [jedn.]',
zaxis_title='Z [jedn.]',
aspectmode='cube'
),
title=f'Pole elektryczne punktowego ładunku Q={Q_value}',
legend=dict(title=dict(text='Legenda'), x=0.02, y=0.98)
)
fig.add_annotation(
dict(
text="Legenda: wektory = kierunek i zwrot pola; pasek kolorów = wartość |E|",
xref="paper", yref="paper",
x=0.01, y=0.01, showarrow=False, align="left",
font=dict(size=10)
)
)
fig.show()
# Przykładowe wywołanie
plot_electric_field()
# ...existing code...
$\displaystyle \Phi_{E} = \frac{Q}{\epsilon_{0}}$
$\displaystyle E = \frac{Q}{4 \pi \epsilon_{0} \left(x^{2} + y^{2} + z^{2}\right)}$
$\displaystyle E_{x} = \frac{Q x}{4 \pi \epsilon_{0} \left(x^{2} + y^{2} + z^{2}\right)^{\frac{3}{2}}}$
Prawo Gausa dla pola magnetycznego¶
In [16]:
# Gauss's Law for Magnetic Fields
import sympy as sp
import numpy as np
import plotly.graph_objects as go
from IPython.display import display
# -----------------------
# Symboliczne wyrażenia
# -----------------------
x, y, z = sp.symbols('x y z')
mu_0_sym, I_sym = sp.symbols('mu_0 I')
# Wyrażenia symboliczne (Gauss, pole magnetyczne)
Phi_B_sym = mu_0_sym * I_sym / (2 * sp.pi * sp.sqrt(x**2 + y**2))
B_sym = mu_0_sym * I_sym / (2 * sp.pi * (x**2 + y**2))
# Wyświetl wyrażenia symboliczne
display(sp.Eq(sp.symbols('Phi_B'), Phi_B_sym))
display(sp.Eq(sp.symbols('B'), B_sym))
# Zamiana na funkcje numeryczne (NumPy) za pomocą lambdify
B_num = sp.lambdify((x, y, I_sym, mu_0_sym), B_sym, 'numpy')
# Wartość numeryczna przenikalności próżni (do obliczeń numerycznych)
mu_0 = 4 * np.pi * 1e-7 # H/m
# ...existing code...
def plot_magnetic_field(I_value=100.0, extent=2.0, n=6, min_r=0.5,
wire_radius=0.1, wire_length=0.1, show_wire=True):
"""
Rysuje pole magnetyczne wokół przewodnika prostoliniowego z prądem I_value.
Dodatkowo rysuje przewód jako cylinder o zadanym promieniu i długości.
"""
#extent - zasięg osi (m)
#wire_radius - promień przewodu (m)
# Siatka punktów w płaszczyźnie (r,theta)
theta = np.linspace(0, 2 * np.pi, n)
r = np.linspace(min_r, extent, n)
R, Theta = np.meshgrid(r, theta)
X = R * np.cos(Theta)
Y = R * np.sin(Theta)
# Obliczenia numeryczne z użyciem funkcji utworzonej przez lambdify
B_magnitude = B_num(X, Y, I_value, mu_0)
# Przygotowanie wektorów pola magnetycznego (kierunek tangencjalny wokół przewodu)
B_x = -B_magnitude * np.sin(Theta)
B_y = B_magnitude * np.cos(Theta)
B_w = np.zeros_like(B_x)
# konwersja do wektorów spłaszczonych dla stożków
x_cones = X.flatten()
y_cones = Y.flatten()
z_cones = np.zeros_like(x_cones) # płaszczyzna z=0
u = B_x.flatten()
v = B_y.flatten()
w = B_w.flatten()
# wybór sizeref (można dopasować)
E_mag = np.sqrt(u**2 + v**2 + w**2)
maxE = np.max(E_mag) if E_mag.size > 0 else 0.0
#sizeref = 0.5 * maxE if maxE > 0 else 0.1
sizeref = 1 * maxE if maxE > 0 else 0.2
# dopasuj rozmiar stożków względem rozmiaru przewodu
sizeref = min(sizeref, wire_radius * 1.0)
fig = go.Figure()
# stożki pola B
fig.add_trace(go.Cone(
x=x_cones, y=y_cones, z=z_cones,
u=u, v=v, w=w,
sizemode='absolute', sizeref=sizeref, anchor='tail',
colorscale='Viridis', showscale=True,
colorbar=dict(title='|B| [T]'),
name=f'Pole B (I={I_value})', showlegend=True
))
# cylinder - przewód z prądem (opcjonalnie)
if show_wire:
theta2 = np.linspace(0, 2*np.pi, 80)
z2 = np.linspace(-wire_length/2, wire_length/2, 20)
Theta2, Z2 = np.meshgrid(theta2, z2)
Xc = wire_radius * np.cos(Theta2)
Yc = wire_radius * np.sin(Theta2)
Zc = Z2
fig.add_trace(go.Surface(
x=Xc, y=Yc, z=Zc,
showscale=False,
colorscale=[[0, '#b0b0b0'], [1, '#505050']],
opacity=0.8,
name='Przewód'
))
# dodaj ślad osi przewodu (opcjonalnie)
fig.add_trace(go.Scatter3d(
x=[0,0], y=[0,0], z=[-wire_length/2, wire_length/2],
mode='lines', line=dict(color='black', width=4), name='Oś przewodu'
))
fig.update_layout(
scene=dict(
xaxis_title='X [m]',
yaxis_title='Y [m]',
zaxis_title='Z [m]',
aspectmode='cube'
),
title=f'Pole magnetyczne wokół przewodnika z prądem I={I_value}',
legend=dict(title=dict(text='Legenda'), x=0.02, y=0.98)
)
fig.show()
# ...existing code...
# Przykładowe wywołanie
plot_magnetic_field()
$\displaystyle \Phi_{B} = \frac{I \mu_{0}}{2 \pi \sqrt{x^{2} + y^{2}}}$
$\displaystyle B = \frac{I \mu_{0}}{2 \pi \left(x^{2} + y^{2}\right)}$
Próby przedstawienia lini pola magnetycznego dipola - pomiedzy dwoma biegunami¶
Pracuje nad tym, coś mi się tu nie podoba, linie chyba powinny przebiegać przez dwa bieguny.
In [17]:
# ...existing code...
import sympy as sp
import numpy as np
import plotly.graph_objects as go
from IPython.display import display
# Symboliczne wyrażenie pola magnetycznego dipola w punkcie r (wektorowo)
x, y, z = sp.symbols('x y z')
mx, my, mz = sp.symbols('mx my mz') # składowe momentu dipolowego m
x0, y0, z0 = sp.symbols('x0 y0 z0') # pozycja dipola
mu0_sym = sp.symbols('mu0')
# wektor r = r - r0
rx = x - x0
ry = y - y0
rz = z - z0
r_vec = sp.Matrix([rx, ry, rz])
r = sp.sqrt(rx**2 + ry**2 + rz**2)
m_vec = sp.Matrix([mx, my, mz])
# pole magnetyczne dipola: B = mu0/(4π) * (3 r (m·r)/r^5 - m/r^3)
m_dot_r = (m_vec.dot(r_vec))
B_vec = mu0_sym/(4*sp.pi) * (3 * r_vec * m_dot_r / r**5 - m_vec / r**3)
# składowe symboliczne
Bx_sym = sp.simplify(B_vec[0])
By_sym = sp.simplify(B_vec[1])
Bz_sym = sp.simplify(B_vec[2])
# zamiana na funkcje numeryczne
Bx_num = sp.lambdify((x, y, z, mx, my, mz, x0, y0, z0, mu0_sym), Bx_sym, 'numpy')
By_num = sp.lambdify((x, y, z, mx, my, mz, x0, y0, z0, mu0_sym), By_sym, 'numpy')
Bz_num = sp.lambdify((x, y, z, mx, my, mz, x0, y0, z0, mu0_sym), Bz_sym, 'numpy')
# stała
mu0 = 4 * np.pi * 1e-7 # H/m
def plot_magnetic_between_poles(m1_pos=(0,0,-0.5), m1_moment=(0,0,1.0),
m2_pos=(0,0,0.5), m2_moment=(0,0,-1.0),
extent=1.0, n=14, min_r=0.15):
"""
Rysuje pole magnetyczne dwóch dipoli (przybliżenie dwóch biegunów).
m1_pos, m2_pos: pozycje (x,y,z)
m1_moment, m2_moment: wektory momentów dipolowych (mx,my,mz)
extent: zasięg osi ([-extent,extent])
n: liczba punktów na wymiar
min_r: maska wykluczająca punkty blisko dipoli
"""
xg = np.linspace(-extent, extent, n)
yg = xg
zg = xg
X, Y, Z = np.meshgrid(xg, yg, zg, indexing='ij')
R = np.sqrt((X - m1_pos[0])**2 + (Y - m1_pos[1])**2 + (Z - m1_pos[2])**2)
R2 = np.sqrt((X - m2_pos[0])**2 + (Y - m2_pos[1])**2 + (Z - m2_pos[2])**2)
# oblicz B od obu dipoli i zsumuj
Bx1 = Bx_num(X, Y, Z, *m1_moment, *m1_pos, mu0)
By1 = By_num(X, Y, Z, *m1_moment, *m1_pos, mu0)
Bz1 = Bz_num(X, Y, Z, *m1_moment, *m1_pos, mu0)
Bx2 = Bx_num(X, Y, Z, *m2_moment, *m2_pos, mu0)
By2 = By_num(X, Y, Z, *m2_moment, *m2_pos, mu0)
Bz2 = Bz_num(X, Y, Z, *m2_moment, *m2_pos, mu0)
Bx = (Bx1 + Bx2).flatten()
By = (By1 + By2).flatten()
Bz = (Bz1 + Bz2).flatten()
Xf = X.flatten()
Yf = Y.flatten()
Zf = Z.flatten()
# maska - unikamy osobliwości blisko dipoli
mask = (np.sqrt((Xf - m1_pos[0])**2 + (Yf - m1_pos[1])**2 + (Zf - m1_pos[2])**2) >= min_r) & \
(np.sqrt((Xf - m2_pos[0])**2 + (Yf - m2_pos[1])**2 + (Zf - m2_pos[2])**2) >= min_r)
x_flat = Xf[mask]
y_flat = Yf[mask]
z_flat = Zf[mask]
u = Bx[mask]
v = By[mask]
w = Bz[mask]
Bmag = np.sqrt(u**2 + v**2 + w**2)
maxB = np.max(Bmag) if Bmag.size > 0 else 0.0
sizeref = 0.5 * maxB if maxB > 0 else 1e-9
fig = go.Figure(data=go.Cone(
x=x_flat, y=y_flat, z=z_flat,
u=u, v=v, w=w,
sizemode='absolute', sizeref=sizeref, anchor='tail',
colorscale='Plasma', showscale=True,
colorbar=dict(title='|B| [T]'),
name='Pole magnetyczne', showlegend=True
))
# zaznacz pozycje biegunów
fig.add_trace(go.Scatter3d(x=[m1_pos[0]], y=[m1_pos[1]], z=[m1_pos[2]],
mode='markers+text', marker=dict(size=6, color='red'),
text=['Biegun N'], textposition='top center', name='Biegun N'))
fig.add_trace(go.Scatter3d(x=[m2_pos[0]], y=[m2_pos[1]], z=[m2_pos[2]],
mode='markers+text', marker=dict(size=6, color='blue'),
text=['Biegun S'], textposition='top center', name='Biegun S'))
fig.update_layout(
scene=dict(xaxis_title='X [m]', yaxis_title='Y [m]', zaxis_title='Z [m]', aspectmode='cube'),
title='Pole magnetyczne między dwoma biegunami (model dipoli)',
legend=dict(title=dict(text='Legenda'), x=0.02, y=0.98)
)
fig.show()
# Przykład: dwa bieguny na osi z, momenty przeciwne -> pole między biegunami
plot_magnetic_between_poles(m1_pos=(0,0,-0.4), m1_moment=(0,0,1.0),
m2_pos=(0,0,0.4), m2_moment=(0,0,-1.0),
extent=1.0, n=18, min_r=0.12)
# ...existing code...
In [18]:
import matplotlib.pyplot as plt
import numpy as np
def plot_magnetic_field_lines_3planes(m1_pos=(0,0,-0.4), m1_moment=(0,0,1.0),
m2_pos=(0,0,0.4), m2_moment=(0,0,-1.0),
extent=1.0, grid_n=64, min_r=0.08):
"""
Rysuje linie pola magnetycznego w trzech płaszczyznach (x-z, y-z, x-y).
Bierze pod uwagę wszystkie składowe pola.
"""
x_arr = np.linspace(-extent, extent, grid_n)
y_arr = np.linspace(-extent, extent, grid_n)
z_arr = np.linspace(-extent, extent, grid_n)
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
# --- Płaszczyzna x-z (y=0) ---
X, Z = np.meshgrid(x_arr, z_arr)
Y = np.zeros_like(X)
Bx1 = Bx_num(X, Y, Z, *m1_moment, *m1_pos, mu0)
Bz1 = Bz_num(X, Y, Z, *m1_moment, *m1_pos, mu0)
Bx2 = Bx_num(X, Y, Z, *m2_moment, *m2_pos, mu0)
Bz2 = Bz_num(X, Y, Z, *m2_moment, *m2_pos, mu0)
Bx = Bx1 + Bx2
Bz = Bz1 + Bz2
R1 = np.sqrt((X - m1_pos[0])**2 + (Y - m1_pos[1])**2 + (Z - m1_pos[2])**2)
R2 = np.sqrt((X - m2_pos[0])**2 + (Y - m2_pos[1])**2 + (Z - m2_pos[2])**2)
near = (R1 < min_r) | (R2 < min_r)
Bx[near] = 0.0
Bz[near] = 0.0
Bmag = np.sqrt(Bx**2 + Bz**2)
Bmag[Bmag == 0] = 1e-12
stream = axes[0].streamplot(X, Z, Bx, Bz, color=np.log10(Bmag),
cmap='plasma', density=1.5, linewidth=1.0, arrowsize=1.5)
axes[0].plot(m1_pos[0], m1_pos[2], 'r*', markersize=20, label='Biegun N')
axes[0].plot(m2_pos[0], m2_pos[2], 'b*', markersize=20, label='Biegun S')
axes[0].set_xlabel('X [m]', fontsize=11)
axes[0].set_ylabel('Z [m]', fontsize=11)
axes[0].set_title('Płaszczyzna x-z (y=0)', fontsize=12)
axes[0].set_aspect('equal')
axes[0].grid(True, alpha=0.3)
axes[0].legend()
plt.colorbar(stream.lines, ax=axes[0], label='log₁₀(|B|)')
# --- Płaszczyzna y-z (x=0) ---
Y, Z = np.meshgrid(y_arr, z_arr)
X = np.zeros_like(Y)
By1 = By_num(X, Y, Z, *m1_moment, *m1_pos, mu0)
Bz1 = Bz_num(X, Y, Z, *m1_moment, *m1_pos, mu0)
By2 = By_num(X, Y, Z, *m2_moment, *m2_pos, mu0)
Bz2 = Bz_num(X, Y, Z, *m2_moment, *m2_pos, mu0)
By = By1 + By2
Bz = Bz1 + Bz2
R1 = np.sqrt((X - m1_pos[0])**2 + (Y - m1_pos[1])**2 + (Z - m1_pos[2])**2)
R2 = np.sqrt((X - m2_pos[0])**2 + (Y - m2_pos[1])**2 + (Z - m2_pos[2])**2)
near = (R1 < min_r) | (R2 < min_r)
By[near] = 0.0
Bz[near] = 0.0
Bmag = np.sqrt(By**2 + Bz**2)
Bmag[Bmag == 0] = 1e-12
stream = axes[1].streamplot(Y, Z, By, Bz, color=np.log10(Bmag),
cmap='plasma', density=1.5, linewidth=1.0, arrowsize=1.5)
axes[1].plot(m1_pos[1], m1_pos[2], 'r*', markersize=20, label='Biegun N')
axes[1].plot(m2_pos[1], m2_pos[2], 'b*', markersize=20, label='Biegun S')
axes[1].set_xlabel('Y [m]', fontsize=11)
axes[1].set_ylabel('Z [m]', fontsize=11)
axes[1].set_title('Płaszczyzna y-z (x=0)', fontsize=12)
axes[1].set_aspect('equal')
axes[1].grid(True, alpha=0.3)
axes[1].legend()
plt.colorbar(stream.lines, ax=axes[1], label='log₁₀(|B|)')
# --- Płaszczyzna x-y (z=0) ---
X, Y = np.meshgrid(x_arr, y_arr)
Z = np.zeros_like(X)
Bx1 = Bx_num(X, Y, Z, *m1_moment, *m1_pos, mu0)
By1 = By_num(X, Y, Z, *m1_moment, *m1_pos, mu0)
Bx2 = Bx_num(X, Y, Z, *m2_moment, *m2_pos, mu0)
By2 = By_num(X, Y, Z, *m2_moment, *m2_pos, mu0)
Bx = Bx1 + Bx2
By = By1 + By2
R1 = np.sqrt((X - m1_pos[0])**2 + (Y - m1_pos[1])**2 + (Z - m1_pos[2])**2)
R2 = np.sqrt((X - m2_pos[0])**2 + (Y - m2_pos[1])**2 + (Z - m2_pos[2])**2)
near = (R1 < min_r) | (R2 < min_r)
Bx[near] = 0.0
By[near] = 0.0
Bmag = np.sqrt(Bx**2 + By**2)
Bmag[Bmag == 0] = 1e-12
stream = axes[2].streamplot(X, Y, Bx, By, color=np.log10(Bmag),
cmap='plasma', density=1.5, linewidth=1.0, arrowsize=1.5)
axes[2].plot(m1_pos[0], m1_pos[1], 'r*', markersize=20, label='Biegun N')
axes[2].plot(m2_pos[0], m2_pos[1], 'b*', markersize=20, label='Biegun S')
axes[2].set_xlabel('X [m]', fontsize=11)
axes[2].set_ylabel('Y [m]', fontsize=11)
axes[2].set_title('Płaszczyzna x-y (z=0)', fontsize=12)
axes[2].set_aspect('equal')
axes[2].grid(True, alpha=0.3)
axes[2].legend()
plt.colorbar(stream.lines, ax=axes[2], label='log₁₀(|B|)')
fig.suptitle('Linie pola magnetycznego między dwoma biegunami (wszystkie składowe)', fontsize=14, y=1.02)
plt.tight_layout()
plt.show()
# Wywołanie
plot_magnetic_field_lines_3planes(m1_pos=(0,0,-0.4), m1_moment=(0,0,1.0),
m2_pos=(0,0,0.4), m2_moment=(0,0,-1.0),
extent=1.0, grid_n=64, min_r=0.08)