Simulácia ako jednoducho odstrániť mikro plasty z vody: https://hrubos.tech/simulacie/olej_voda_nacl_simulacia.mp4
Obrázok: https://hrubos.tech/blogy/content/images/20260903153534-elektro_olej_cistenie_mikroplastov.jpg
Pred odsolením rozhýbeme vodivú vrstvu soľou, aby sme mali mega Brownov pohyb častíc á olej prichádzajúci prídavkom vždy odspodu zachytí mikro plasty. Je to nezávadné Voda, Soľ, Slnečnicový olej á následné odsolenie po zbere mikroplastov. Díkes profesóres, sme team. Prečo je hore mínus elektróda, lebo oleje sú nepolárne zlúčeniny a ako z gymnázia vieme, voda je polárne rozpúšťadlo. Čiže filter sa nám nekazí.
# olej_voda_nacl_simulacia_mp4.jl
#
# Julia + GLMakie + FFMPEG
#
# OLEJ + VODA + NaCl + ŠPINA + ELEKTRICKÉ POLE
#
# Priamo renderuje MP4:
# olej_voda_nacl_simulacia.mp4
#
# 1920 × 1080
# 60 FPS
# 30 sekúnd
#
# Spustenie:
# julia olej_voda_nacl_simulacia_mp4.jl
using GLMakie
using Random
using Printf
Random.seed!(11)
# ============================================================
# VIDEO
# ============================================================
const VIDEO_WIDTH = 1920
const VIDEO_HEIGHT = 1080
const FPS = 60
const VIDEO_SECONDS = 30
const N_FRAMES = VIDEO_SECONDS * FPS
const OUTPUT_FILE = "olej_voda_nacl_simulacia.mp4"
# ============================================================
# PARAMETRE SIMULÁCIE
# ============================================================
const W = 10.0
const H = 16.0
const DT = 0.018
const WATER_LEVEL = 11.2
const OIL_LEVEL = 14.1
const OIL_TOP = 14.9
const EFIELD = 0.65
# Ióny
const N_IONS = 170
const ION_MOBILITY = 0.045
const ION_DIFFUSION = 0.12
# Olejové kvapky
const N_DROPS = 22
const DROP_R = 0.16
const DROP_BUOYANCY = 0.18
const DROP_DRAG = 0.055
const DROP_BROWNIAN = 0.020
# Nečistoty
const N_DIRT = 115
const DIRT_R = 0.055
const DIRT_SETTLING = 0.030
const DIRT_DIFFUSION = 0.045
const DIRT_DRAG = 0.80
# Zachytávanie špiny olejom
const CAPTURE_RADIUS = 0.24
const CAPTURE_PROB = 0.055
const CARRY_DRAG = 0.92
# ============================================================
# STAV ČASTÍC
# ============================================================
drop_x = rand(N_DROPS) .* (W - 1.0) .+ 0.5
drop_y = rand(N_DROPS) .* 2.2 .+ 0.5
drop_vy = zeros(Float64, N_DROPS)
ion_x = rand(N_IONS) .* (W - 0.4) .+ 0.2
ion_y = rand(N_IONS) .* (H - 0.4) .+ 0.2
ion_charge = [
isodd(i) ? 1.0 : -1.0
for i in 1:N_IONS
]
dirt_x = rand(N_DIRT) .* (W - 0.5) .+ 0.25
dirt_y = rand(N_DIRT) .* (H - 5.0) .+ 0.3
dirt_vx = zeros(Float64, N_DIRT)
dirt_vy = zeros(Float64, N_DIRT)
captured = falses(N_DIRT)
captured_by = zeros(Int, N_DIRT)
# ============================================================
# OBSERVABLES
# ============================================================
simtime = Observable(0.0)
n_captured = Observable(0)
n_positive = Observable(0)
n_negative = Observable(0)
drop_pts = Observable(Point2f.(drop_x, drop_y))
ion_pts = Observable(Point2f.(ion_x, ion_y))
dirt_pts = Observable(Point2f.(dirt_x, dirt_y))
status = Observable("Spúšťam simuláciu…")
# Pravý graf:
# vektor Point2f zabezpečí, že čas aj hodnota ostanú synchronizované
stat_cap_pts = Observable(Point2f[])
stat_pos_pts = Observable(Point2f[])
stat_neg_pts = Observable(Point2f[])
# ============================================================
# STENY
# ============================================================
function reflect_wall!(x, y, vx, vy, r)
if x < r
x = r
vx = abs(vx) * 0.35
elseif x > W - r
x = W - r
vx = -abs(vx) * 0.35
end
if y < r
y = r
vy = abs(vy) * 0.15
elseif y > H - r
y = H - r
vy = -abs(vy) * 0.15
end
return x, y, vx, vy
end
# ============================================================
# OLEJOVÉ KVAPKY
# ============================================================
function update_drops!()
for i in 1:N_DROPS
buoy = DROP_BUOYANCY
vx = (rand() - 0.5) * 0.035
drop_vy[i] += DT * (
buoy -
DROP_DRAG * drop_vy[i]
)
drop_vy[i] += sqrt(DT) * DROP_BROWNIAN * randn()
drop_x[i] += DT * vx
drop_y[i] += DT * drop_vy[i]
# Olejová vrstva
if drop_y[i] > OIL_TOP
drop_y[i] = OIL_TOP
drop_vy[i] *= -0.10
end
drop_x[i],
drop_y[i],
_,
drop_vy[i] = reflect_wall!(
drop_x[i],
drop_y[i],
vx,
drop_vy[i],
DROP_R
)
end
end
# ============================================================
# ŠPINA
# ============================================================
function update_dirt!()
for j in 1:N_DIRT
# ----------------------------------------------------
# ZACHYTENÁ ŠPINA
# ----------------------------------------------------
if captured[j]
i = captured_by[j]
if i < 1 || i > N_DROPS
captured[j] = false
captured_by[j] = 0
continue
end
dirt_x[j] += CARRY_DRAG * (drop_x[i] - dirt_x[j])
dirt_y[j] += CARRY_DRAG * (drop_y[i] - dirt_y[j])
# Po dosiahnutí olejovej vrstvy sa špina uvoľní
if dirt_y[j] > OIL_TOP - 0.7
captured[j] = false
captured_by[j] = 0
dirt_y[j] = 14.1 + 0.25 * rand()
dirt_x[j] = clamp(
dirt_x[j] + 0.12 * randn(),
0.3,
W - 0.3
)
end
continue
end
# ----------------------------------------------------
# SEDIMENTÁCIA
# ----------------------------------------------------
dirt_vy[j] += DT * (
-DIRT_SETTLING -
DIRT_DRAG * dirt_vy[j]
)
dirt_vy[j] += sqrt(DT) * DIRT_DIFFUSION * randn()
dirt_x[j] += sqrt(DT) * 0.035 * randn()
dirt_y[j] += DT * dirt_vy[j]
# Bočné steny
if dirt_x[j] < DIRT_R
dirt_x[j] = DIRT_R
dirt_vx[j] = abs(dirt_vx[j]) * 0.25
elseif dirt_x[j] > W - DIRT_R
dirt_x[j] = W - DIRT_R
dirt_vx[j] = -abs(dirt_vx[j]) * 0.25
end
# Dno
if dirt_y[j] < DIRT_R
dirt_y[j] = DIRT_R
dirt_vy[j] *= -0.10
end
# ----------------------------------------------------
# INTERAKCIA OLEJ – ŠPINA
# ----------------------------------------------------
for i in 1:N_DROPS
dx = dirt_x[j] - drop_x[i]
dy = dirt_y[j] - drop_y[i]
d2 = dx * dx + dy * dy
if d2 < CAPTURE_RADIUS^2 &&
rand() < CAPTURE_PROB
captured[j] = true
captured_by[j] = i
break
end
end
end
n_captured[] = count(captured)
end
# ============================================================
# IÓNY
# ============================================================
function update_ions!()
np = 0
nn = 0
for i in 1:N_IONS
q = ion_charge[i]
drift = ION_MOBILITY * q * EFIELD
ion_y[i] += (
DT * drift +
sqrt(DT * 2.0 * ION_DIFFUSION) * randn()
)
ion_x[i] += (
sqrt(DT * 2.0 * ION_DIFFUSION) * randn()
)
# Bočné steny
if ion_x[i] < 0.2
ion_x[i] = 0.2
elseif ion_x[i] > W - 0.2
ion_x[i] = W - 0.2
end
# Horná a dolná stena
if ion_y[i] < 0.2
ion_y[i] = 0.2
elseif ion_y[i] > H - 0.2
ion_y[i] = H - 0.2
end
if q > 0
np += 1
else
nn += 1
end
end
n_positive[] = np
n_negative[] = nn
end
# ============================================================
# GRAFIKA
# ============================================================
fig = Figure(
size = (VIDEO_WIDTH, VIDEO_HEIGHT),
fontsize = 16
)
# ============================================================
# HLAVNÝ GRAF
# ============================================================
ax = Axis(
fig[1, 1],
title = "VODA + OLEJ + NaCl + ŠPINA + ELEKTRICKÉ POLE",
xlabel = "šírka nádoby",
ylabel = "výška",
limits = (0, W, 0, H)
)
# Voda
water_poly = Point2f[
Point2f(0, 0),
Point2f(W, 0),
Point2f(W, WATER_LEVEL),
Point2f(0, WATER_LEVEL)
]
poly!(
ax,
water_poly,
color = (:deepskyblue, 0.18),
strokewidth = 0
)
# Olejová vrstva
oil_poly = Point2f[
Point2f(0, OIL_LEVEL),
Point2f(W, OIL_LEVEL),
Point2f(W, H),
Point2f(0, H)
]
poly!(
ax,
oil_poly,
color = (:gold, 0.18),
strokewidth = 0
)
# Rozhranie voda – olej
lines!(
ax,
[0, W],
[WATER_LEVEL, WATER_LEVEL],
linewidth = 3,
color = :steelblue
)
# Olejové kvapky
scatter!(
ax,
drop_pts,
markersize = 25,
color = (:orange, 0.85),
strokewidth = 1,
strokecolor = :darkorange
)
# Ióny
ion_colors = [
ion_charge[i] > 0 ? :crimson : :dodgerblue
for i in 1:N_IONS
]
scatter!(
ax,
ion_pts,
markersize = 9,
color = ion_colors
)
# Špina
scatter!(
ax,
dirt_pts,
markersize = 7,
color = :black
)
# Elektrické pole
for x in 1.0:1.0:9.0
for y in 2.0:2.0:10.0
arrows!(
ax,
[x],
[y],
[0.0],
[0.65],
arrowsize = 8,
lengthscale = 0.45,
linewidth = 1.3,
color = (:purple, 0.30)
)
end
end
# Elektródy
lines!(
ax,
[0.5, 9.5],
[0.15, 0.15],
linewidth = 8,
color = :gray20
)
lines!(
ax,
[0.5, 9.5],
[15.85, 15.85],
linewidth = 8,
color = :gray20
)
text!(
ax,
5.0,
15.45,
text = "− HORNÁ ELEKTRÓDA",
align = (:center, :center),
color = :gray20
)
text!(
ax,
5.0,
0.55,
text = "+ DOLNÁ ELEKTRÓDA",
align = (:center, :center),
color = :gray20
)
# Popisy
text!(
ax,
0.6,
12.0,
text = "VODA",
color = :steelblue,
fontsize = 20
)
text!(
ax,
0.6,
14.65,
text = "OLEJOVÁ VRSTVA",
color = :darkorange,
fontsize = 20
)
text!(
ax,
0.6,
10.8,
text = "rozhranie",
color = :gray30,
fontsize = 12
)
# ============================================================
# PRAVÝ GRAF – ŠTATISTIKY
# ============================================================
ax2 = Axis(
fig[1, 2],
title = "ŠTATISTIKY",
xlabel = "čas [s]",
ylabel = "počet",
limits = (
0,
VIDEO_SECONDS + 1,
0,
max(N_IONS + 5, 120)
)
)
lines!(
ax2,
stat_cap_pts,
linewidth = 3,
color = :black,
label = "zachytená špina"
)
lines!(
ax2,
stat_pos_pts,
linewidth = 2,
color = :crimson,
label = "Na⁺"
)
lines!(
ax2,
stat_neg_pts,
linewidth = 2,
color = :dodgerblue,
label = "Cl⁻"
)
axislegend(
ax2,
position = :lt
)
# Stavový riadok
Label(
fig[2, 1:2],
status,
tellwidth = false,
fontsize = 18
)
# ============================================================
# JEDEN SIMULAČNÝ KROK
# ============================================================
function simulation_step!()
update_drops!()
update_dirt!()
update_ions!()
t = simtime[] + DT
simtime[] = t
# Pridanie nových bodov do pravého grafu
push!(
stat_cap_pts[],
Point2f(t, n_captured[])
)
push!(
stat_pos_pts[],
Point2f(t, n_positive[])
)
push!(
stat_neg_pts[],
Point2f(t, n_negative[])
)
# Dôležité: push! mení obsah vektora priamo
notify(stat_cap_pts)
notify(stat_pos_pts)
notify(stat_neg_pts)
# Aktualizácia pozícií častíc
drop_pts[] = Point2f.(drop_x, drop_y)
dirt_pts[] = Point2f.(dirt_x, dirt_y)
ion_pts[] = Point2f.(ion_x, ion_y)
# Aktualizácia textu
status[] = @sprintf(
"t = %.2f s olejové kvapky = %d zachytená špina = %d Na⁺ = %d Cl⁻ = %d",
t,
N_DROPS,
n_captured[],
n_positive[],
n_negative[]
)
end
# ============================================================
# MP4 RENDER
# ============================================================
println()
println("================================================")
println(" OLEJ + VODA + NaCl — MP4 RENDER")
println("================================================")
println("Výstup: ", OUTPUT_FILE)
println("Rozlíšenie: ", VIDEO_WIDTH, " × ", VIDEO_HEIGHT)
println("FPS: ", FPS)
println("Dĺžka: ", VIDEO_SECONDS, " s")
println("Snímky: ", N_FRAMES)
println("================================================")
println()
record(
fig,
OUTPUT_FILE,
1:N_FRAMES;
framerate = FPS
) do frame
simulation_step!()
if frame % FPS == 0
seconds_done = frame ÷ FPS
@printf(
"Render: %3d / %3d s\n",
seconds_done,
VIDEO_SECONDS
)
end
end
println()
println("================================================")
println(" HOTOVO")
println("================================================")
println("MP4 súbor:")
println(abspath(OUTPUT_FILE))
println("================================================")
Za simuláciu ako vždy vďaka GPT, perplexity AI podľa mojich príkazov v Julia Lang ^^^

Comments “Dnes vodný olej so soľou á milá študentka á čistíme mikroplasty: https://hrubos.tech/simulacie/olej_voda_nacl_simulacia.mp4”