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)
No description has been provided for this image