def analyze(I, U_b, i): B = (ureg.mu_0 * (8 / 125**.5) * (N / R) * I).to('µT') D = list(range(len(I))) # „Linien-Index“ auf dem Leuchtschirm D *= ureg.inch / 4 # …umgerechnet in die Ablenkung ding = D / (L**2 + D**2) a, b = tools.linregress(B, ding) print(f"a = {a.to('1/m/T'):.1f}") e_div_m = 8 * U_b * a**2 print( tools.fmt_compare_to_ref(e_div_m, e_div_m_theo, unit='C/kg', name='e/m')) plt_vals, = plt.plot(B, ding.to('1/m'), 'x', color=f"C{i}") plt_regress, = plt.plot(B, (tools.nominal_value(a) * B + tools.nominal_value(b)).to('1/m'), '-', color=f"C{i}") return ((plt_vals, plt_regress), (U_b, a, e_div_m))
print(f"- T_plus_rechts={tools.ufloat_from_list(T_plus_rechts)}") # print(f"- T_std_rechts={np.std(T_plus_rechts)}") T_diff_lr = abs( tools.ufloat_from_list(T_plus_links) - tools.ufloat_from_list(T_plus_rechts)) T_diff_lr_tolerance = min(np.std(T_plus_links), np.std(T_plus_rechts)) print(f"Differenz der Schwingungsdauern links/rechts: {T_diff_lr}") # „Überprüfen Sie, daß die Schwingungsdauern T₁ und T₂ im Rahmen der Meßgenauigkeit übereinstimmen.“ print( f"Toleranzgrenze dieser Differenz: {T_diff_lr_tolerance} (→ {'PASS' if T_diff_lr < T_diff_lr_tolerance else 'FAIL'})" ) ω_plus_theo = ((ureg.gravity / l)**.5).to('rad/s') ω_plus_avg = (2 * np.pi * ureg.rad) / T_plus_avg print(tools.fmt_compare_to_ref(ω_plus_avg, ω_plus_theo, name='ω_plus')) print("\n→ Gegensinnige Schwingung") T_minus = get_T(i, 'gegensinnig') / 5 # 5 Perioden gemessen… Unschön… T_minus_avg = tools.ufloat_from_list(T_minus) * ureg('s') print(f"{T_minus_avg=}") # Kopplungskonstante K = (T_plus_avg**2 - T_minus_avg**2) / (T_plus_avg**2 + T_minus_avg**2) K *= ureg('m/s²') # !? print(f"{K=}") ω_minus_theo = ((ureg.gravity / l + 2 * K / l)**.5).to('rad/s') ω_minus_avg = (2 * np.pi * ureg.rad) / T_minus_avg print(tools.fmt_compare_to_ref(ω_minus_avg, ω_minus_theo, name='ω_minus'))
ureg.setup_matplotlib() import tools α1, α2 = np.genfromtxt(f'data/Reflexionsgesetz.csv', comments='#', unpack=True, delimiter=',') α1 *= ureg.deg # Einfallswinkel α2 *= ureg.deg # Reflexionswinkel Δα = abs(α1 - α2) print(f"Δα = {Δα}") print(f"Mittelwert Δα: {np.mean(Δα):.3f}") a, b = tools.linregress(α1, α2) print(f"{a, b=}") print(tools.fmt_compare_to_ref(a, 1, name='Geradensteigung a')) plt.plot(α1, α2, 'x', zorder=5, label='Messwerte') plt.plot(α1, tools.nominal_values(a * α1 + b), label='Regressionsgerade') plt.plot(α1, α1, color='black', label=r'$\alpha_1 = \alpha_2$') plt.xlabel(r'$\alpha_1 \mathbin{/} \si{\degree}$') plt.ylabel(r'$\alpha_2 \mathbin{/} \si{\degree}$') plt.xticks(α1) plt.yticks(α2) plt.grid() plt.legend() # plt.gca().set_aspect('equal') plt.tight_layout() plt.savefig('build/plt/reflexionsgesetz.pdf') # plt.show()
I_0 = u_I(2731) # ohne Al-Absorper I_1 = u_I(1180) # mit Al-Absorber zwischen Röntgenröhre und Streuer I_2 = u_I(1024) # mit Al-Absorber zwischen Streuer und Geiger-Müller-Zählrohr t = ureg('300 s') # Integrationszeit N_0 = I_0 / t # ohne Al-Absorper N_1 = I_1 / t # mit Al-Absorber zwischen Röntgenröhre und Streuer N_2 = I_2 / t # mit Al-Absorber zwischen Streuer und Geiger-Müller-Zählrohr print(f'{N_0=}', f'{N_1=}', f'{N_2=}', sep='\n') max_N_possible = (1 / τ).to('Imp/s') max_N_measured = max(N_0, N_1, N_2) assert max_N_possible > max_N_measured * 1e3 print( '\n' f'größtmögliche Zählrate = 1/τ = {max_N_possible:.2f} ≫ {max_N_measured:.2f} = größte gemessene Zählrate' ) print(f'→ um den Faktor {(max_N_possible / max_N_measured).m.n:.0f} größer!') T_1 = N_1 / N_0 # Transmission der ungestreuten Röntgenstrahlung T_2 = N_2 / N_0 # Transmission der gestreuten Röntgenstrahlung print(f'T_1 = {T_1}', f'T_2 = {T_2}', sep='\n') λ_1 = (T_1 - b) / a λ_2 = (T_2 - b) / a print(f'λ_1 = {λ_1:.2f}') print(f'λ_2 = {λ_2:.2f}') λ_C = λ_2 - λ_1 # Compton-Wellenlänge λ_C_theo = 1 * ureg.h / (ureg.electron_mass * ureg.c) print(tools.fmt_compare_to_ref(λ_C, λ_C_theo, 'λ_C', unit='pm'))
import uncertainties.unumpy as unp import tools θ, N = np.genfromtxt('data/EmissionCu.dat', unpack=True) θ *= ureg.deg peak_indices = find_peaks(N, height=1000)[0] assert len(peak_indices) == 2 θ_Kβ, θ_Kα = θ[peak_indices] θ_Kα_lit = ureg('22.323 °') θ_Kβ_lit = ureg('20.217 °') print(tools.fmt_compare_to_ref(θ_Kα, θ_Kα_lit, name='θ_Kα')) print(tools.fmt_compare_to_ref(θ_Kβ, θ_Kβ_lit, name='θ_Kβ')) def energie(θ): d = ureg('201.4 pm') # Gitterebenenabstand return (ureg.h * ureg.c / (2 * d * np.sin(θ))).to('keV') E_Kα, E_Kβ = energie(θ_Kα), energie(θ_Kβ) assert E_Kα < E_Kβ print(tools.fmt_compare_to_ref(E_Kα, energie(θ_Kα_lit), name='E_Kα')) print(tools.fmt_compare_to_ref(E_Kβ, energie(θ_Kβ_lit), name='E_Kβ')) plt.plot(θ, N, '-o', zorder=5, label='Messwerte')
I_list = [] for i, U_b in enumerate(U_b_list): print(f"→ U_b = {U_b}") I = np.genfromtxt(f'V502/data/{U_b.m}V.dat', unpack=True) * ureg.A I_list.append(I) result = analyze(I, U_b, i) actor_tuple_list.append(result[0]) data_list.append(result[1]) print() e_div_m_list = tools.pintify([d[2] for d in data_list]) e_div_m_mean = np.mean(e_div_m_list) print( tools.fmt_compare_to_ref(e_div_m_mean, e_div_m_theo, unit='C/kg', name='e/m mean')) plt.legend(actor_tuple_list, [f"$U_b = {U_b.m} V$" for U_b in U_b_list]) plt.xlabel(r"$B \mathbin{/} \si{\micro\tesla}$") plt.ylabel(r"$\frac{D}{L²+D²} \mathbin{/} \si{\per\meter}$") plt.grid() # plt.show() plt.tight_layout() plt.savefig('build/plt/V502_1.pdf') D_list = list(range(max([len(I) for I in I_list ]))) # „Linien-Index“ auf dem Leuchtschirm D_list *= ureg.inch / 4 # …umgerechnet in die Ablenkung # generate_table('tab/V502_tab_a', [(U_b, a.to('1/m/T'), e_div_m.to('C/kg') / 1e11) for U_b, a, e_div_m in data_list], col_fmt=[{'d': 0}, {'d': 1}, {'d': 2}], headers=['U_b', 'a', 'e/m / 1e11'])
def analyze(T, manual_max_indices): print(f"→ {T=}") U_B, I_A = np.genfromtxt( f'build/dat/franck_hertz_{str(T).replace(".", "_")}.csv', comments='#', unpack=True, delimiter=',') U_B *= ureg.V # Beschleunigungsspannung I_A *= ureg.nA # Achtung: distance/width werden in *samples* angegeben! # Damit ist keine weitere Generalisierung möglich. max_indices = find_peaks(I_A.m, height=1.5, width=1)[0] # max_indices = find_peaks(I_A.m, height=1.5, distance=15)[0] if manual_max_indices: max_indices = np.sort( np.unique(np.concatenate([max_indices, manual_max_indices]))) print(f'{max_indices=}') print( f'Peaks: \n-U_B: {U_B[max_indices]:.3f}\n-I_A: {I_A[max_indices]:.3f}') # Abstand der relativen Maxima dif = np.diff(U_B[max_indices].to('V').m) * ureg.V dif_avg = tools.ufloat_from_list(dif.m) * ureg.V print(f'Abstände: {dif:.3f}', ) print('mittlerer Abstand:', dif_avg) print( tools.fmt_compare_to_ref(dif_avg * ureg.e, ureg('4.9 eV'), unit='eV', name='→ Anregungsenergie')) λ = ureg.c * ureg.h / (dif_avg * ureg.e) print('λ =', λ.to('nm')) # Ohne Berücksichtigung des Kontaktpotentials würde man erwarten, # dass der mittlere Abstand gleich dem Abstand des ersten Maximums von der 0 ist – # schließlich müssten die Elektronen bei dif_avg gerade zum ersten Mal # eine ausreichende Beschleunigung erfahren haben, um ein Hg-Atom zu ionisieren. # Das tatsächliche Beschleunigungspotential (und somit die Energie des Elektrons) # ist wegen des Kontaktpotentials aber geringer. # Das verschiebt die Franck-Hertz-Kurve nach rechts, # was wir uns folgendermaßen zu Nutze machen können: print('1. Maximum: ', U_B[max_indices[0]]) print('Kontaktpotential: ', U_B[max_indices[0]] - dif_avg) print( 'Kontaktpotential (Modulo): ', U_B[max_indices[0]] % dif_avg ) # sinnvoll, wenn das wirklich erste Maximum (bei 4.9 V) nicht bestimmt werden konnte plt.figure(f'{T=}') plt.plot(U_B, I_A, 'x-', label='Messwerte') plt.plot(U_B[max_indices], I_A[max_indices], 'xr', label='Maxima') for i in max_indices: plt.axvline(U_B[i], color='grey', linestyle='--', alpha=0.5) for k in range(len(max_indices) - 1): i1 = max_indices[k] i2 = max_indices[k + 1] plt.arrow(*(U_B[i1], I_A[i2]), *(U_B[i2] - U_B[i1], 0)) plt.annotate(f'{(U_B[i2] - U_B[i1]).to("V").m:.1f} V', (U_B[i1], I_A[i2] + ureg('0.15 nA'))) # plt.grid() plt.xlabel(r'$U_\text{A} \mathbin{/} \si{\volt}$') plt.ylabel(r'$I_\text{A}$') plt.yticks([]) plt.legend() plt.tight_layout() plt.savefig(f'build/plt/franck_hertz_{str(T).replace(".", "_")}.pdf')
ureg.setup_matplotlib() from scipy.signal import find_peaks, peak_widths from uncertainties import ufloat import uncertainties.unumpy as unp import tools θ, N = np.genfromtxt('data/Emissionsspektrum.dat', unpack=True) θ *= ureg.deg peak_indices, _ = find_peaks(N, height=1000) assert len(peak_indices) == 2 peaks = θ[peak_indices] print(tools.fmt_compare_to_ref(peaks[1], ureg('22.323 °'), name="θ_Kα")) print(tools.fmt_compare_to_ref(peaks[0], ureg('20.217 °'), name="θ_Kβ")) results_half = peak_widths(N, peak_indices, rel_height=0.5) w_h, l, r = results_half[1:] # TODO hard-coden ist doof :/ l = (l / 10 + 8) * ureg.deg r = (r / 10 + 8) * ureg.deg print(f"Halbwertsbreiten: {(r-l):.3f}°") def energie(θ): d = ureg('201.4 pm') # Gitterebenenabstand return (ureg.h * ureg.c / (2 * d * np.sin(θ.to('rad')))).to('keV')
t_a *= ureg('µs') t_b *= ureg('µs') A_a *= ureg('V') A_b *= ureg('V') d = tools.pint_concat(a, b) * 2 # hin und zurück t = tools.pint_concat(t_a, t_b) d, t = tools.remove_nans(d, t) speed, achse = tools.linregress(t, d) print(f"{speed=}") print(f"{achse=}") print( tools.fmt_compare_to_ref(speed, ureg('2730 m/s'), 'Schallgeschwindigkeit in Acryl', unit=ureg('m/s'))) t_bounds = tools.bounds(t) plt.plot(t, d, '+', label='Messwerte') plt.plot(t_bounds, (achse.nominal_value * ureg('mm') + speed.nominal_value * ureg('mm/µs') * t_bounds).to('mm'), label='Fit') #TODO Theoriewert dazu plotten plt.xlabel(r'$t \mathbin{/} \si{\micro\second}$') plt.ylabel(r'$d \mathbin{/} \si{\milli\meter}$') plt.legend() plt.tight_layout() plt.savefig('build/plt/schallgeschwindigkeit.pdf')
plt.tight_layout() plt.savefig('build/plt/V501_1.pdf') # generate_table('c_dings', list(zip(U_B_list.m, tools.pintify(a_list)))) print("\n\nApparaturkonstante:") a_list_nominal = tools.nominal_values(tools.pintify(a_list)) m, n = tools.linregress(1 / U_B_list, a_list_nominal) d = ureg('0.38 cm') # Abstand der Y-Ablenkplatten zueinander p = ureg('1.9 cm') # Länge der Y-Ablenkplatten L = ureg('1.03 cm') + ureg('14.3 cm') # Abstand *Beginn* der Y-Ablenkplatten → Leuchtschirm m_theo = (p*L)/(2*d) print(tools.fmt_compare_to_ref(m, m_theo, unit='mm', name='Apparaturkonstante')) plt.figure() plt.plot(1 / U_B_list.to('kV'), a_list_nominal, 'x', label='Werte') #label-Name lol plt.plot(1 / U_B_list.to('kV'), tools.nominal_value(m)*(1 / U_B_list)+tools.nominal_value(n), '-', label='Regressionsgerade') plt.grid() plt.xlabel(r'$\sfrac{1}{U_\text{b}} \mathbin{/} \si{\per\kilo\volt}$') plt.ylabel(r'$\sfrac{D}{U_\text{d}} \mathbin{/} \si{\centi\meter\per\volt}$') # plt.legend() # hier vllt. wirklich keine Legende… plt.tight_layout() plt.savefig('build/plt/V501_2.pdf') print("\n\nAmplitude:") a = a_list[np.argwhere(U_B_list == ureg('420 V'))[0][0]] print(f"{a=}") D = 1/2 * ureg('1/4 inch') # Amplitude: eine halbe Skaleneinheit
import numpy as np import pint ureg = pint.UnitRegistry() ureg.setup_matplotlib() import tools α, β = np.genfromtxt(f'data/Brechungsgesetz.csv', comments='#', delimiter=',', unpack=True) α *= ureg.deg # Einfallswinkel β *= ureg.deg # Brechungswinkel n = np.sin(α) / np.sin(β) # n1 = 1.000292 # Brechungsindex Luft # n2 = n1 * np.sin(α) / np.sin(β) n_avg = tools.ufloat_from_list(n.m) # print(f"Mittelwert n: {n_avg:.3f}") n_lit = 1.489 * ureg.dimensionless print(tools.fmt_compare_to_ref(n_avg, n_lit), 'Brechungsindex') v = (ureg.c / n_avg).to('m/s') # v = (ureg.c * np.sin(β) / np.sin(α)).to('m/s') print(f"Lichtgeschwindigkeit in Plexiglas: {v}")
θ_middle = θ[i_exact[0]] else: for i in range(len(N)): if N[i] < I_K and N[i + 1] > I_K: Δθ = θ[i + 1] - θ[i] ΔN = N[i + 1] - N[i] N_gerade = N[i] + ΔN * (θ - θ[i]) / Δθ θ_middle = (I_K - N[i]) * Δθ / ΔN + θ[i] break print(f"θ_middle = {θ_middle}") E = (ureg.h * ureg.c / (2 * d * np.sin(θ_middle.to('rad')))).to('keV') σ_K = calc_σ_K(E, Z) print(f"E = {E}") print(tools.fmt_compare_to_ref(σ_K, s_data['σ_K_lit'], name="σ_K")) ## Plots plt.figure() plt.plot(θ, N, 'x') plt.plot(θ[I_K_argmin], N[I_K_argmin], 'xr', label=('rel. Minima' if len(I_K_argmin) > 1 else 'rel. Minimum')) plt.plot(θ[I_K_argmax], N[I_K_argmax], 'xr', label=('rel. Maxima' if len(I_K_argmax) > 1 else 'rel. Maximum')) # plt.axvspan(*θ_bounds, alpha=0.25, label='Absorptionskante') if not i_exact: plt.plot(θ[i:i + 2], N[i:i + 2], color='gray')
ax.set_ylim([-0.5, 0.5]) # Für k=0 lässt sich keine Wellenlänge berechnen, daher `[k!=0]`. λ = d * np.sin(φ[k != 0]) / k[k != 0] λ_all[color] += list(λ) λ_mean = tools.ufloat_from_list(λ) ax.axvline(0, color='grey', zorder=0) ax.set_xlabel(r'$\varphi \mathbin{/} \si{\degree}$') ax.set_yticks([]) # krasser One-Liner, um 0° im Plot zu zentrieren :P ax.set_xlim(*(np.array([-1, 1]) * abs(max(ax.get_xlim(), key=abs)))) plt.tight_layout() plt.savefig(f'build/plt/beugung.pdf') # plt.show() λ_lit = { 'red': ureg('635 nm'), 'green': ureg('532 nm') } # siehe Versuchsanleitung und Versuchsaufbau for color, λ in λ_all.items(): λ = tools.pintify(λ) λ_all_mean = tools.ufloat_from_list(λ).to('nm') print(f"{color}:", tools.fmt_compare_to_ref(λ_all_mean, λ_lit[color]), '', sep='\n')