Die Geschwindigkeit eines Objektes kann durch \ref{eq:velocity} berechnet werden.
\begin{equation} v = \frac{s}{t} \label{eq:velocity} \end{equation}Die Messwerte zu den einzelnen Versuchen wurden durch den Dozenten zur Verfügung gestellt. Sie sind alle im Anhang vorzufinden. Die zur Versuchsdurchführung verwendeten Tools beinhalten den Taschenrechner, Excel und Python mit diversen Libraries (Jupyter, Scipy, Pandas, Matplotlib, Seaborn).
In [1]:
# Preparations
import math
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import numpy as np
from scipy import stats
from scipy.optimize import curve_fit
import seaborn as sns
from IPython.display import Latex
import warnings
from PrettyTable import PrettyTable
warnings.filterwarnings("ignore", module="matplotlib")
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
plt.rcParams['savefig.dpi'] = 75
# plt.rcParams['figure.autolayout'] = False
# plt.rcParams['figure.figsize'] = 10, 6
plt.rcParams['axes.labelsize'] = 18
plt.rcParams['axes.titlesize'] = 20
plt.rcParams['font.size'] = 16
plt.rcParams['lines.linewidth'] = 2.0
plt.rcParams['lines.markersize'] = 8
plt.rcParams['legend.fontsize'] = 14
plt.rcParams['text.usetex'] = True
plt.rcParams['text.latex.unicode'] = True
plt.rcParams['font.family'] = "STIX"
plt.rcParams['text.latex.preamble'] = "\\usepackage{subdepth}, \\usepackage{type1cm}"
sns.set(color_codes=True)
def average(data):
return 1 / len(data) * sum(data)
def error(data, average_of_data):
s = sum([(x - average_of_data)**2 for x in data])
return math.sqrt(s / (len(data) * (len(data) - 1)))
def std_deviation(error_of_average, length_of_dataset):
return error_of_average * math.sqrt(length_of_dataset)
def average_with_weights(data, weights):
d = data
w = weights
return (d * w**-2).sum() / (w**-2).sum()
def error_with_weights(weights):
w = weights
return 1 / math.sqrt((w**-2).sum())
def wavg(group, avg_name, weight_name):
d = group[avg_name]
w = group[weight_name]
return (d * w**-2).sum() / (w**-2).sum()
def werr(group, weight_name):
return 1 / math.sqrt((group[weight_name]**-2).sum())
In [2]:
# Evaluate Data
# Read Data
v1_df = pd.read_csv('data/laufzeiten.csv')
v1_s = 2.561
v1_s_u = 0.003
v1_theta = 23
# Calculate mean etc.
v1_mean = v1_df.mean()['t']
v1_sem = v1_df.sem()['t']
v1_std = v1_df.std()['t']
# Calculate velocity & error
v1_v = v1_s / v1_mean
v1_v_u = math.sqrt((v1_s_u / v1_mean)**2 + (-v1_s * v1_sem / v1_mean**2)**2)
v1_error_percent_v = v1_v_u / v1_v * 100
v1_error_percent_t = v1_sem / v1_mean * 100
v1_data = PrettyTable(list(zip(v1_df['measurement'], v1_df['t'])), entries_per_column=10, extra_header=['Messung [1]', 'Laufzeit [s]'])
Die Schallgeschwindigkeit soll durch die Mittlere Laufzeit über eine bekannte Strecke bestimmt werden.
{{v1_data}}
Wikipedia führt eine Formel \ref{eq:vschall} zur Berechnung der Schallgeschwindigkeit bei einer bestimmten Temperatur. Diese kann auch in Horst Kuchlings Taschenbuch der Physik gefunden werden.
\begin{equation} c_{luft} = (331.3 + 0.606 \cdot \theta) \frac{m}{s} = (331.3 + 0.606 \cdot 23) \frac{m}{s} = 345.24\frac{m}{s} \label{eq:vschall} \end{equation}Mithilfe des zuvor ermittelten Mittelwertes kann die Mittlere Schallgeschwindigkeit als:
In [3]:
# Plot all values
ax = v1_df.plot(kind='scatter', x='measurement', y='t', label='gemessene Laufzeit')
plt.xlabel('Messung [1]')
plt.xlim([0, len(v1_df['t']) + 1])
plt.ylim([0.0065, 0.0085])
plt.ylabel('t [ms]')
plt.axhline(y=v1_mean, axes=ax, color='red', label='Mittelwert')
plt.axhline(y=v1_mean+v1_sem, axes=ax, color='green', label='Mittelwert ± Fehler')
plt.axhline(y=v1_mean-v1_sem, axes=ax, color='green')
plt.axhline(y=v1_mean+v1_std, axes=ax, color='purple', label='Mittelwert ± Standardabweichung')
plt.axhline(y=v1_mean-v1_std, axes=ax, color='purple')
plt.legend(bbox_to_anchor=(0.02, 0.98), loc=2, borderaxespad=0.2)
plt.show()
#plt.savefig('laufzeiten.pgf')
In [22]:
# Evaluate Data
# Read Data
v2_df = pd.read_csv('data/eisengehalt.csv')
# Calculate mean etc.
v2_mean = v2_df.mean()['content']
v2_sem = v2_df.sem()['content']
v2_weightedmean = wavg(v2_df, 'content', 'error')
v2_weightedsem = werr(v2_df, 'error')
v2_data = PrettyTable(list(zip(v2_df['measurement'], v2_df['content'], v2_df['error'])), entries_per_column=len(v2_df['error']), extra_header=['Messung [1]', 'Gehalt [%]', 'Absoluter Fehler [%]'])
{{v2_data}}
Der einfache Mittelwert und sein Fehler ergeben sich analog zu Aufgabe 1.
Der gewichtete Mittelwert und sein Fehler werden als
bestummen.
In [23]:
# Plot all data
ax = v2_df.plot(yerr=v2_df['error'], kind='scatter', x='measurement', y='content', label='Eisengehalt in Legierung')
plt.axhline(y=v2_mean, axes=ax, color='purple', label='Ungewichteter Mittelwert')
plt.axhline(y=v2_weightedmean, axes=ax, color='red', label='Gewichteter Mittelwert')
plt.xlabel('Messung [1]')
plt.xlim([0, len(v2_df['content']) + 1])
plt.ylabel('Eisengehalt [%]')
plt.legend(bbox_to_anchor=(0.02, 0.98), loc=2, borderaxespad=0.2)
plt.show()
#plt.savefig('eisengehalt.pgf')
In [24]:
# Evaluate Data
# Read Data
v3_df = pd.read_csv('data/federkonstante.csv')
# Find best values with a fit
def spring(z, k, F0):
return k * z + F0
v3_values, v3_covar = curve_fit(spring, v3_df['z'], v3_df['F'])
v3_F_fit = [spring(z, v3_values[0], v3_values[1]) for z in v3_df['z']]
v3_slope, v3_intercept, v3_r_value, v3_p_value, v3_std_err = stats.linregress(v3_df['z'], v3_df['F'])
v3_data = PrettyTable(list(zip(v3_df['F'], v3_df['z'])), entries_per_column=len(v3_df['F']), extra_header=['Kraft [N]', 'Auslenkung [m]'])
{{v3_data}}
Die Steigung der Regressionsgeraden und somit die Federkonstante $k$ wird wie folgt erhalten:
Der zugehörige Achsenabschnitt und somit die Ruhekraft $F_0$ errechnet sich aus:
Die empirische Korrelation ist:
mit zugehörigem Bestimmtheitsmass:
In [25]:
# Plot all data
ax = v3_df.plot(kind='scatter', x='z', y='F', label='gemessene Zugkraft')
plt.plot(v3_df['z'], v3_F_fit, axes=ax, label='Zugkraft mit Value Fitting')
plt.xlabel('Auslenkung [m]')
plt.ylabel('Zugkraft [F]')
plt.legend(bbox_to_anchor=(0.02, 0.98), loc=2, borderaxespad=0.2)
plt.show()
Der Fit errechnet die folgenden relevenanten Werte für das Experiment:
In [26]:
# Evaluate Data
np.seterr(all='ignore')
# Read Data
v4_df = pd.read_csv('data/pendel.csv')
def pendulum(t, A, l, f, d, y0):
return A * np.exp(-l*t)*np.sin(2*math.pi*f*t-d)+y0
v4_values, v4_covar = curve_fit(pendulum, v4_df['t'], v4_df['y'])
v4_y_fit = [pendulum(t, v4_values[0], v4_values[1], v4_values[2], v4_values[3], v4_values[4]) for t in v4_df['t']]
v4_valerr = np.sqrt(np.diag(v4_covar))
v4_data = PrettyTable(list(zip(v4_df['t'], v4_df['y'])), entries_per_column=23, extra_header=['Zeit [s]', 'Auslenkung [m]'])
Von einem Pendel ist die Auslenkung in y-Richtung zu verschiedenen Zeitpunkten $t_i$ bekannt. Mithilfe der Methode der kleinsten Quadrate können Offset, Amplitude, Frequenz und Phase des Pendels bestimmt werden. Die Funktion des Pendels welche mit dem Fit angenähert wird schreibt sich wie folgt:
{{v4_data}}
Mit der Methode der Chi-Quadrate (nichtlineare Regression) wurden durch scipy die folgenden besten Werte ermittelt:
In [27]:
# Plot all data
ax = v4_df.plot(kind='scatter', x='t', y='y', label='gemessene Auslenkung')
plt.plot(v4_df['t'], v4_y_fit, axes=ax, label='Auslenkung mit Value Fitting')
plt.xlabel('Zeit [s]')
plt.ylabel('Auslenkung [m]')
plt.legend(bbox_to_anchor=(0.02, 0.98), loc=2, borderaxespad=0.2)
plt.show()
In [28]:
# Read data
# Calculate parameters of fit
import functools
v5_df = pd.read_csv('data/tiefpass.csv')
v5_Ue = 4
v5_R = 500
def Ua(Ue, R, f, C):
return Ue / 2 / np.sqrt(1+(2*math.pi*f*C*R)**2)
def phi(R, f, C):
return np.arctan(-2*math.pi*f*R*C)/2/math.pi*360
v5_values_Ua, v5_covar_Ua = curve_fit(functools.partial(Ua, v5_Ue, v5_R), v5_df['f'], v5_df['Ua'].div(2))
v5_f_fit = np.linspace(10, v5_df['f'][len(v5_df['f'])-1], 1000)
v5_Ua_fit = [Ua(v5_Ue, v5_R, f, -v5_values_Ua[0]) * 2 for f in v5_f_fit]
v5_valerr_Ua = np.sqrt(np.diag(v5_covar_Ua))
v5_values_phi, v5_covar_phi = curve_fit(functools.partial(phi, v5_R), v5_df['f'], v5_df['phi'])
v5_phi_fit = [phi(v5_R, f, v5_values_phi[0]) for f in v5_f_fit]
v5_valerr_phi = np.sqrt(np.diag(v5_covar_phi))
v5_data = PrettyTable(list(zip(v5_df['f'], v5_df['Ua'], v5_df['phi'])), entries_per_column=len(v5_df['f']), extra_header=['Frequenz [Hz]', '$U_a$ [V]', 'Phase [\degree]'])
Am Eingang eines RC-Tiefpassfilters wurde eine sinusförmige Wechselspannung mit einer Amplitude $U_E = 4 V_{pp}$ und einer variabler Frequenz angelegt. Gemessen wurde die Ausgangsspannung $U_A$ sowie die Phasenverschiebung $\varphi$ in Abhängigkeit der Frequenz $f$. Der Widerstand $R$ ist mit $R=500\Omega$ beziffert.
In [29]:
from IPython.display import Image
Image(filename='images/rc-lowpass.png')
Out[29]:
{{v5_data}}
Die Kapazität C kann durch zwei verschiedene Funktionen bestimmt werden:
Die Kapazität kann mit einem Fit an die Ausgangsspannung $U_a$ auf
und mit einem Fit an die Phase $U_a$ auf
bestimmt werden.
In [30]:
# Plot all data
ax = v5_df.plot(kind='scatter', x='f', y='Ua', label='gemessene Spannunsgwerte', logx=True)
plt.plot(v5_f_fit, v5_Ua_fit, axes=ax, label='Spannung mit Value Fit')
plt.xlabel('Frequenz [Hz]')
plt.ylabel('Spannung [V]')
plt.legend(bbox_to_anchor=(0.02, 0.98), loc=2, borderaxespad=0.2)
plt.show()
In [31]:
# Plot all data
ax = v5_df.plot(kind='scatter', x='f', y='phi', label='gemessene Phase', logx=True)
plt.plot(v5_f_fit, v5_phi_fit, axes=ax, label='Phase mit Value Fit')
plt.xlabel('Frequenz [Hz]')
plt.ylabel('Phase [$^{\circ}$]')
plt.legend(bbox_to_anchor=(0.02, 0.98), loc=2, borderaxespad=0.2)
plt.show()
Grösse | Wert |
---|---|
Schallgeschwindigkeit in Luft $c_{luft, wikipedia}$ | 345.3$\frac{m}{s}$ |
Mittelwert $\overline{c}$ | {{'{0:.2f}'.format(v1_v)}}$\frac{m}{s}$ |
Unsicherheit des Mittelwertes $s_{\overline{c(s, t)}}$ | {{'{0:.2f}'.format(v1_v_u)}}$\frac{m}{s}$ |
Schallgeschwindigkeit $c_{luft}$ | ({{'{0:.2f}'.format(v1_v)}} ± {{'{0:.2f}'.format(v1_v_u)}})$\frac{m}{s}$ |
Der experimentell bestimmte Wert hat somit eine Abweichung von {{'{0:.2f}'.format((v1_v-345.3)/v1_v*100)}}% von Literaturwerten. Dies zeigt dass der Wert ziemlich genau bestummen werden konnte. Des weiteren sind zu den Literaturwerten keine Toleranzen bekannt. Dies lässt darauf schliessen dass diese schlichtweg unbekannt sind oder einfach weggelassen wurden. Somit kann es gut sein dass der errechnete Wert im Toleranzbereich liegt.
Ausserdem liegen 13 von 20 Messpunkten innerhalb des Standardabweichungsintervalles. Dies sind 65% was ziemlich gut dem erwarteten Wert von 68% entspricht. Mit zusätzlichen Experimenten und Messungen würde sich der Wert gut gegen 68% annähern.
Die Messresultate sind alles in allem plausibel und ergeben gute Werte.
gewichtet | ungewichtet | |
---|---|---|
Mittelwert | {{'{0:.2f}'.format(v2_mean)}}% | {{'{0:.2f}'.format(v2_weightedmean)}}% |
Unsicherheit | {{'{0:.2f}'.format(v2_sem)}}% | {{'{0:.2f}'.format(v2_weightedsem)}}% |
Eisengehalt | ({{'{0:.2f}'.format(v2_mean)}} + {{'{0:.2f}'.format(v2_sem)}})% | ({{'{0:.2f}'.format(v2_weightedmean)}} + {{'{0:.2f}'.format(v2_weightedsem)}})% |
die Resultate des gewichteten sowie ungewichteten Mittelwert unterscheiden sich um lediglich {{'{0:.4f}'.format((1 - v2_weightedmean / v2_mean) * 100)}}%. Ein Unterschied im Promillebereich. Jedoch beträgt die Unsicherheit beim gewichteten Mittelwert ganze {{'{0:.2f}'.format((1 - v2_weightedsem / v2_sem)/0.01)}}% weniger, was ihn um einiges präziser als den ungewichten Mittelwert macht. Er wäre dem ungewichteten Mittelwert vorzuziehen für weitere Berechungen.
TI-89 | linear Regression | |
---|---|---|
Federkonstante $k$ | {{'{0:.2f}'.format(v3_values[0])}}$\frac{N}{m}$ | {{'{0:.2f}'.format(v3_values[0])}}$\frac{N}{m}$ |
Vorspannung $F_0$ | {{'{0:.2f}'.format(v3_values[1])}}N | {{'{0:.2f}'.format(v3_values[1])}}N |
Empirische Korrelation $r_{xy}$ | {{'{0:.4f}'.format(v3_r_value)}} | {{'{0:.4f}'.format(v3_r_value)}} |
Bestimmtheitsmass $R^2$ | {{'{0:.4f}'.format(v3_r_value**2)}}% | {{'{0:.4f}'.format(v3_r_value**2)}}% |
Beide betrachteten Methoden – mit dem TI-89 sowie auch mit der linearen Regression von scipy wurden identische Ergebnisse erzielt. Es ist somit anzunehmen, dass die beiden Instrumente mit der gleichen Algorithmik (wahrscheinlich die Methode der kleinsten Quadrate) arbeitet.
Mit einem Fit der Gleichung für das gedämpfte Pendel lassen sich die nachstehenden charakteristischen Werte für das schwingende Pendel bestimmen.
Grösse | Wert |
---|---|
Amplitude $A$ | ({{'{0:.2f}'.format(v4_values[0])}} ± {{'{0:.2f}'.format(v4_valerr[0])}})m |
Dämpfung $\Gamma$ | ({{'{0:.2f}'.format(v4_values[1])}} ± {{'{0:.4f}'.format(v4_valerr[1])}})$\frac{1}{s}$ |
Frequenz $f$ | ({{'{0:.2f}'.format(v4_values[2])}} ± {{'{0:.4f}'.format(v4_valerr[2])}})Hz |
Phasenverschiebung $\delta$ | ({{'{0:.2f}'.format(v4_values[3])}} ± {{'{0:.2f}'.format(v4_valerr[3])}}) |
Anfangsauslenkung $y_0$ | ({{'{0:.2f}'.format(v4_values[4])}} ± {{'{0:.2f}'.format(v4_valerr[4])}})m |
Bei einem Vergleich der gefitteten Kurve mit der Kurve der gemessenen Werten lässt sich feststellen dass diese Werte alle plausibel sind. Gute Anfangswerte waren nicht notwendig, der Fit hat bestens ohne geklappt!
Bei diesem Versuch wurde wiederum mit einem nichtlinearen Fit gearbeitet. Wiederum war es keine Notwenigkeit die Startwerte zu berechnen. Bei diesem Versuch standen jedoch zwei verschiedene Messreihen zur Verfügung um die gesuchte Kapazität $C$ zu bestimmen.
C per Spannungskurve | C per Phase | |
---|---|---|
Kapazität $C$ | ({{'{0:.2f}'.format(-v5_values_Ua[0]/1e-9)}} ± {{'{0:.2f}'.format(v5_valerr_Ua[0] * 1e9)}})nF | ({{'{0:.2f}'.format(v5_values_phi[0] * 1e9)}} ± {{'{0:.2f}'.format(v5_valerr_phi[0] / 1e-9)}})nF |
Bei diesem Versuch liefern beide alternativen Methoden unterschiedliche werte. Wie man bei den Plots \ref{fig:phitiefpass} und \ref{fig:Utiefpass} fder Fitting Curves sehen kann ist die Kurve des Spannungsfits sehr passgenau an den Messpunkten angelegt. Dies ist bei der Kurve des Phasenfits nicht so gut der Fall. Hier ist anzunehmen, dass das Datenset für den Fit der Phase zu klein beziehungsweise ungünstig war und somit kein so guter Fit gemacht werden konnte. Alles in allem wäre dem Spannungsfit mehr zu vertrauen. Um einen guten Kompromiss zu machen kann man nun die beiden erhaltenen Werte gewichtet mitteln. Dies ergibt einen Mittelwert von ({{'{0:.2f}'.format(average_with_weights(np.array([-v5_values_Ua[0], v5_values_phi[0]]), np.array([v5_valerr_Ua[0], v5_valerr_phi[0]])) * 1e9)}} ± {{'{0:.2f}'.format(error_with_weights(np.array([v5_valerr_Ua[0], v5_valerr_phi[0]])) / 1e-9)}})nF.
In [ ]: