Last active
April 2, 2021 21:32
-
-
Save dermesser/58ffad3ebfc0b08ea71927b82e32eb4b to your computer and use it in GitHub Desktop.
Simulation of a Scanning Tunneling Microscope's control algorithm (Pluto notebook)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ### A Pluto.jl notebook ### | |
| # v0.12.21 | |
| # (c) 2021 Lewin Bormann | |
| using Markdown | |
| using InteractiveUtils | |
| # This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). | |
| macro bind(def, element) | |
| quote | |
| local el = $(esc(element)) | |
| global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing | |
| el | |
| end | |
| end | |
| # ╔═╡ 3ca61268-8a5d-11eb-34ab-9b0c7ce9c19a | |
| begin | |
| using Plots | |
| using Statistics | |
| import Random | |
| gr() | |
| end | |
| # ╔═╡ 662c9a8a-8a5d-11eb-1ca0-972e75cce9de | |
| md""" | |
| ## PID-Regelung Rastertunnelmikroskop | |
| Wir haben | |
| * ein Stromsignal $I(t)$, | |
| * ein Fehlersignal $E(t) = I(t) - S$ (Abweichung von Sollstrom $S$), und | |
| * die Stellgröße $Y(t)$, die bestimmt, wie die Stellung der Spitze verändert wird. | |
| """ | |
| # ╔═╡ 81b5f22c-8a6e-11eb-3c82-7d8a54b309cb | |
| random_seed = 12349 | |
| # ╔═╡ 81616ba0-8a71-11eb-1f0f-d3bdd3e0fe00 | |
| md""" | |
| ### Oberfläche generieren. | |
| Hier generieren wir durch Random Walking eine Oberfläche, die wir später abschreiten wollen. | |
| """ | |
| # ╔═╡ b9c9a60c-8a6e-11eb-2977-d7c1e06bd7ef | |
| function generate_step_surface( | |
| ; len::Int64=250, stepwidth::Int64=25, | |
| stepheight::Float64=3.)::Vector{Float64} | |
| rng = Random.MersenneTwister(random_seed) | |
| current = 0 | |
| thresh = 1.1 | |
| factor = 1. | |
| function mapstep(x::Float64) | |
| if x > thresh | |
| current += stepheight * (x-thresh) * factor | |
| elseif x < -thresh | |
| current += stepheight * (x+thresh) * factor | |
| end | |
| return current | |
| end | |
| dst = Random.randn(rng, len) | |
| for i = 1:length(dst) | |
| dst[i] = mapstep(dst[i]) | |
| end | |
| return dst | |
| end | |
| # ╔═╡ b1960dd8-8a6e-11eb-3abc-99286e3e8f1c | |
| plot(generate_step_surface(len=500000)) | |
| # ╔═╡ ac96c664-8a6f-11eb-360c-27599ba4d5ce | |
| md""" | |
| ### Hauptalgorithmus: Oberflächenverfolgung. | |
| Unabhängig vom Reglermechanismus wird hier eine Oberfläche verfolgt. | |
| """ | |
| # ╔═╡ 03ac3e04-8a73-11eb-3d45-15c63bf21540 | |
| # Returns the current as function of distance. | |
| function current_func(dist::Real; current_factor=1)::Float64 | |
| return exp(-current_factor*dist) | |
| end | |
| # ╔═╡ 8e6f403a-8a74-11eb-0045-5318bd996f47 | |
| function antilinear_func(dist::Real; current_factor=1)::Real | |
| return -dist*current_factor | |
| end | |
| # ╔═╡ 94773e40-8a76-11eb-0ff7-250b0d6c5200 | |
| md""" | |
| ### Regleralgorithmen. | |
| Hier sind die eigentlichen Regelalgorithmen definiert, die die Einstellung der Spitze kontrollieren. | |
| """ | |
| # ╔═╡ ba835830-8a76-11eb-14c9-e58c34a1227f | |
| md""" | |
| `proportional` gibt einen Wert zurück, der mit größerem Fehlersignal `E` stärker abfällt: | |
| """ | |
| # ╔═╡ 76f0ff18-8a72-11eb-3393-8585070a479f | |
| function proportional(E::Real, state=nothing; g=0., h=nothing, j=nothing) | |
| return g*E, nothing | |
| end | |
| # ╔═╡ 4cb63808-8a72-11eb-1766-23047364c971 | |
| # surface: the trackable surface | |
| # pos0: starting position | |
| # target_S: Target current | |
| # current: Function calculating the current from distance | |
| # algo, algoargs: algorithm for tracking | |
| function track_surface(surface::Vector{Float64}, target_S=.4; | |
| pos0=1, g::Real=.5, h::Real=.1, j::Real=.1, | |
| current=current_func, | |
| algo=proportional, algoargs=[])::Vector{Float64} | |
| pos = pos0 | |
| state = nothing | |
| function maptrack(x) | |
| # Almost perfect tracking! -- use relative difference | |
| # E = (current(pos - x) / current(target_S)) -1 | |
| # Imperfect tracking -- use absolute difference, not good for very small currents | |
| E = current(pos - x) - current(target_S) | |
| Y, state = algo(E, state; g=g, h=h, j=j) | |
| pos += Y | |
| end | |
| return collect(map(maptrack, surface)) | |
| end | |
| # ╔═╡ 905587a2-8bb0-11eb-17e9-590c36dabc97 | |
| @bind rtimespan html"Ti: <input type=range>" | |
| # ╔═╡ f263dcac-8a76-11eb-3116-4396a196a240 | |
| begin | |
| timespan = 4*rtimespan | |
| function integrated(E::Real, state::Union{Nothing, Vector{Float64}}; | |
| g=0., h=0., j=nothing, timespan=timespan) | |
| if state == nothing | |
| state = ones(timespan) .* E | |
| end | |
| integrated = sum(state)/timespan | |
| state = [state[2:end]; E] | |
| return proportional(E, nothing; g=g)[1] + h * integrated, state | |
| end | |
| end | |
| # ╔═╡ 9eedb29a-8a86-11eb-1a1e-496d57b9ffdb | |
| function differentiated(E::Real, | |
| state::Union{Nothing, Tuple{Float64, Vector{Float64}}}; | |
| g=0., h=0., j=0., timespan=rtimespan) | |
| if state == nothing | |
| last, hist = 0, nothing | |
| else | |
| (last, hist) = state | |
| end | |
| int, hist_ = integrated(E, hist; g=g, h=h, timespan=timespan) | |
| dEdx = (E - last) | |
| return int+j*dEdx, (hist_[end], hist_) | |
| end | |
| # ╔═╡ afc29c12-8a76-11eb-3b46-b504dff087de | |
| md""" | |
| ### Visualisierung | |
| """ | |
| # ╔═╡ f20ae626-8baf-11eb-3ed1-9901416098b2 | |
| @bind rdist html"Abstand: <input type=range>" | |
| # ╔═╡ 02355084-8bb0-11eb-3305-8746fa5e5fe5 | |
| @bind rg html"g: <input type=range>" | |
| # ╔═╡ 1d6b897e-8bb0-11eb-06fb-8dd988c72eb4 | |
| @bind rh html"h: <input type=range>" | |
| # ╔═╡ ea82dbfc-8bb2-11eb-2252-61479b144fd1 | |
| @bind rj html"j: <input type=range>" | |
| # ╔═╡ ade0d464-8a73-11eb-3677-7b5eaf669d81 | |
| begin | |
| # Distance between tip and surface | |
| dist = rdist | |
| # Weighting of correction factor (pos' = pos - g) | |
| g = round(rg/3, digits=1) | |
| # Weighting of current by distance (exp(-cf * dist)) | |
| cf = .1 | |
| # Which algorithm to use. | |
| algo = differentiated | |
| h = rh/5 | |
| j = rj/3 | |
| surf = generate_step_surface(len=1000) | |
| track = track_surface(surf, rdist; pos0=dist, g=g, h=h, j=j, | |
| current=(x) -> current_func(x; current_factor=cf), | |
| algo=algo) | |
| xs = range(1, length(surf), step=1) | |
| plot(xs, surf, label="Surface", title="z = $dist, g = $g, h = $h, j = $j") | |
| plot!(xs, track, label="Tip") | |
| p = plot!(xs, track-surf, label="Distance") | |
| p | |
| end | |
| # ╔═╡ fe045072-8eee-11eb-3751-53072b09f657 | |
| #savefig(p, "../img/simulation_d$(dist)_g$(g)_h$(h)_j$(j).pdf") | |
| # ╔═╡ 13f27f32-9061-11eb-2fc4-c5965a95ba6e | |
| rtimespan | |
| # ╔═╡ 29534788-8a8c-11eb-1d2d-c51484c76caf | |
| md""" | |
| ### Konstanthöhenmodus | |
| """ | |
| # ╔═╡ a1066da2-8af3-11eb-2209-b170613f9d8b | |
| begin | |
| current_factor = .09 | |
| ch_dist = rdist | |
| ch_surf = generate_step_surface(len=1500) | |
| ch_scale = maximum(ch_surf) | |
| scalefunc = identity | |
| currents = map(x -> ch_scale*scalefunc(current_func(ch_dist-x, current_factor=current_factor)), | |
| ch_surf) | |
| ch_xs = range(1, length(ch_surf), step=1) | |
| plot(ch_xs, ch_surf, label="Surface", title="z = $ch_dist") | |
| chp = plot!(ch_xs, currents, label="I", scale=:identity) | |
| end | |
| # ╔═╡ 93a44ae8-9062-11eb-0e77-8b28863fb6e1 | |
| #savefig(chp, "../img/simulation_current_d$(dist).pdf") | |
| # ╔═╡ Cell order: | |
| # ╠═3ca61268-8a5d-11eb-34ab-9b0c7ce9c19a | |
| # ╠═662c9a8a-8a5d-11eb-1ca0-972e75cce9de | |
| # ╠═81b5f22c-8a6e-11eb-3c82-7d8a54b309cb | |
| # ╠═81616ba0-8a71-11eb-1f0f-d3bdd3e0fe00 | |
| # ╠═b9c9a60c-8a6e-11eb-2977-d7c1e06bd7ef | |
| # ╠═b1960dd8-8a6e-11eb-3abc-99286e3e8f1c | |
| # ╠═ac96c664-8a6f-11eb-360c-27599ba4d5ce | |
| # ╠═03ac3e04-8a73-11eb-3d45-15c63bf21540 | |
| # ╠═8e6f403a-8a74-11eb-0045-5318bd996f47 | |
| # ╠═4cb63808-8a72-11eb-1766-23047364c971 | |
| # ╠═94773e40-8a76-11eb-0ff7-250b0d6c5200 | |
| # ╠═ba835830-8a76-11eb-14c9-e58c34a1227f | |
| # ╠═76f0ff18-8a72-11eb-3393-8585070a479f | |
| # ╠═905587a2-8bb0-11eb-17e9-590c36dabc97 | |
| # ╠═f263dcac-8a76-11eb-3116-4396a196a240 | |
| # ╠═9eedb29a-8a86-11eb-1a1e-496d57b9ffdb | |
| # ╠═afc29c12-8a76-11eb-3b46-b504dff087de | |
| # ╠═f20ae626-8baf-11eb-3ed1-9901416098b2 | |
| # ╠═02355084-8bb0-11eb-3305-8746fa5e5fe5 | |
| # ╠═1d6b897e-8bb0-11eb-06fb-8dd988c72eb4 | |
| # ╠═ea82dbfc-8bb2-11eb-2252-61479b144fd1 | |
| # ╠═ade0d464-8a73-11eb-3677-7b5eaf669d81 | |
| # ╠═fe045072-8eee-11eb-3751-53072b09f657 | |
| # ╠═13f27f32-9061-11eb-2fc4-c5965a95ba6e | |
| # ╠═29534788-8a8c-11eb-1d2d-c51484c76caf | |
| # ╠═a1066da2-8af3-11eb-2209-b170613f9d8b | |
| # ╠═93a44ae8-9062-11eb-0e77-8b28863fb6e1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment