Auswertung (Uni Mainz PGP2 SS17 Blockpraktikum)

Es bietet sich an zuerst alle Pakete zu importieren, die zum Ausführen des Notebooks benötigt werden. Stellt man während der Arbeit am Notebook fest, dass zusätzliche Pakete benötigt werden, sollte die Liste hier ergänzt werden.


In [1]:
# matplotlib und numpy importieren
%pylab nbagg

# Arbeiten mit Daten
import pandas as pd

# Zum Fitten
import lmfit  

# Fehlerrechnung
import uncertainties as uct
from uncertainties.umath import *


Populating the interactive namespace from numpy and matplotlib

Die Fitroutine minimiert das $\chi^2$, welches aus den Quadraten der Residuen (=Abweichung der Modellvorhersage von den Messwerten) berechnet wird. Die folgende Funktion bestimmt für ein beliebiges Modell die dazugehörige Residuenfunktion. Es ist nicht wichtig, diesen Quellcode zu verstehen. Im Zweifel reicht es, diese Zelle einfach auszuführen, damit die Funktion definiert ist.


In [2]:
def residual(userfcn):
    """
    Gibt für eine Modellfunktion die entsprechende Residuenfunktion 
    zurück, die für gewisse Parameter und x/y-Wertepaare die Residuen 
    (modell(x) - y) berechnet. Wird ein Fehler angegeben, dann werden 
    die Residuen noch mit dem Kehrwert des Fehlers gewichtet.
    
    Parameters
    ----------
    userfcn : callable
        The model function for which the residuals should be calculated. 
        This should take two arguments params and x, where params 
        denotes the parameters (lmfit.Parameters.parameter instance) to 
        be used in the model and x denotes the values for which the model 
        function should be evaluated. 
        
    Returns
    -------
    residualfunction : callable
        This function calculates the residuals . It takes the model parameters and
        x/y-values as arguments and optionally the uncertainties of the y-values
        as a keyword argument 'eps='.
        
    Note
    ----
    In Summary the userfcn should be a callable of the form
    
        model(params, x)
        
    which returns a ndarray with the y-values corresponding to the x-values and the
    model with the given parameters. The residual function which is returned is of 
    the form
    
        residual(params, x, y, eps=yerr)
        
    and returns a ndarray with the corresponding residuals for the parameters and the
    given x/y-value pairs.
    """
    def out(*args, **kwargs):
        p, x, y = args
        assert isinstance(p, lmfit.parameter.Parameters)
        if "eps" in kwargs:
            eps = kwargs.pop("eps")
        else:
            eps = None
            
        modell = userfcn(p.valuesdict(), x)
        if eps is None:
            residual = abs(modell-y)
        else:
            residual = abs((modell-y)/eps)
        return residual
    return out

Zusätzlich ändern wir einige globale Optionen zur Formatierung der Plots. Es ist sinnvoll, das auch am Anfang des Notebooks zu tun, damit diese Änderungen für alle Plots wirksam sind.


In [3]:
plt.rcParams['font.size'] = 10
plt.rcParams['axes.grid'] = True
plt.rcParams['figure.figsize'] = (4,3)
plt.rcParams['figure.dpi'] = 144

Nun zur eigentlichen Auswertung. Wir beginnen damit, die Daten von Aufgabe 1 zu importieren.

Daten importieren

Wir importieren erst einmal die Daten. Dazu nutzen wir das Paket pandas (http://pandas.pydata.org/), welches exzellent ist, um mit Daten zu arbeiten. Wir haben es als pd importiert. Das heißt, immer, wenn wir pd schreiben, weiß der Python-Interpreter, dass eigentlich pandas gemeint ist. Wir verwenden den Befehl read_csv für den Datenimport.


In [4]:
data = pd.read_csv('dat/a1-100ohm.csv')

Jetzt sind die Daten importiert und wir schauen sie uns an.


In [5]:
# Betrachte die ersten 4 (=Standardwert) Zeilen
data.head()


Out[5]:
Record Length 2500 Points -810.000017E-9 -12.0000 Unnamed: 5
0 Sample Interval 1.000E-9 s -8.090000e-07 -12.0 NaN
1 Trigger Point 810.000040 Samples -8.080000e-07 -12.0 NaN
2 NaN NaN NaN -8.070000e-07 -11.8 NaN
3 NaN NaN NaN -8.060000e-07 -12.0 NaN
4 NaN NaN NaN -8.050000e-07 -11.6 NaN

Das sind nur Einstellungen von dem Oszilloskop, die brauchen wir gar nicht! wir betrachten noch ein paar mehr der ersten Zeilen, um herauszufinden, wo die Daten anfangen.


In [6]:
data.head(20)


Out[6]:
Record Length 2500 Points -810.000017E-9 -12.0000 Unnamed: 5
0 Sample Interval 1.000E-9 s -8.090000e-07 -12.0 NaN
1 Trigger Point 810.000040 Samples -8.080000e-07 -12.0 NaN
2 NaN NaN NaN -8.070000e-07 -11.8 NaN
3 NaN NaN NaN -8.060000e-07 -12.0 NaN
4 NaN NaN NaN -8.050000e-07 -11.6 NaN
5 Source CH1 NaN -8.040000e-07 -11.8 NaN
6 Vertical Units Volts NaN -8.030000e-07 -11.8 NaN
7 Vertical Scale 5.00000 NaN -8.020000e-07 -12.0 NaN
8 Vertical Offset 0 NaN -8.010000e-07 -12.0 NaN
9 Horizontal Units s NaN -8.000000e-07 -12.2 NaN
10 Horizontal Scale 249.99999E-9 NaN -7.990000e-07 -12.0 NaN
11 Pt Fmt Y NaN -7.980000e-07 -12.0 NaN
12 Yzero 400.00000E-3 NaN -7.970000e-07 -12.0 NaN
13 Probe Atten 10.0000 NaN -7.960000e-07 -12.0 NaN
14 NaN NaN NaN -7.950000e-07 -12.2 NaN
15 Note TDS 2002B - 09:31:50 28.08.2017 NaN -7.940000e-07 -12.0 NaN
16 NaN NaN NaN -7.930000e-07 -12.0 NaN
17 NaN NaN NaN -7.920000e-07 -12.2 NaN
18 NaN NaN NaN -7.910000e-07 -12.0 NaN
19 NaN NaN NaN -7.900000e-07 -12.0 NaN

Offensichtlich fangen die Daten in Zeile 16 an. Wir können also getrost die ersten 16 Zeilen beim Import überspringen (die erste Zeile der Datei wird standardmäßig für die Spaltennamen verwendet).


In [7]:
data = pd.read_csv('dat/a1-100ohm.csv', skiprows=16)

Jetzt betrachten wir erneut die ersten Zeilen der importierten Daten.


In [8]:
data.head()


Out[8]:
Note TDS 2002B - 09:31:50 28.08.2017 Unnamed: 2 -794.000016E-9 -12.0000 Unnamed: 5
0 NaN NaN NaN -7.930000e-07 -12.0 NaN
1 NaN NaN NaN -7.920000e-07 -12.2 NaN
2 NaN NaN NaN -7.910000e-07 -12.0 NaN
3 NaN NaN NaN -7.900000e-07 -12.0 NaN
4 NaN NaN NaN -7.890000e-07 -12.2 NaN

Wir brauchen auch nur die vierte und fünfte Spalte, also importieren wir nur diese. Achtung! Python beginnt immer bei 0 mit Zählen, also hat die vierte Spalte den Index 3 und die fünfte Spalte den Index 4. Außerdem betrachten wir direkt die ersten Zeilen der importierten Daten.


In [9]:
data = pd.read_csv('dat/a1-100ohm.csv', skiprows=16, usecols=[3, 4])
data.head()


Out[9]:
-794.000016E-9 -12.0000
0 -7.930000e-07 -12.0
1 -7.920000e-07 -12.2
2 -7.910000e-07 -12.0
3 -7.900000e-07 -12.0
4 -7.890000e-07 -12.2

Jetzt ergänzen wir noch sinnvolle Spaltenüberschriften in unserem Import-Befehl und betrachten die Daten.


In [10]:
data = pd.read_csv('dat/a1-100ohm.csv', skiprows=16, usecols=[3, 4], names=["t", "U"])
data.head()


Out[10]:
t U
0 -7.940000e-07 -12.0
1 -7.930000e-07 -12.0
2 -7.920000e-07 -12.2
3 -7.910000e-07 -12.0
4 -7.900000e-07 -12.0

Das sieht gut aus, damit können wir arbeiten. Jetzt plotten wir die Daten. Es ist an dieser Stelle sinnvoll, die Zeitdaten direkt nach dem Import in Nanosekunden umzurechnen.


In [11]:
data = pd.read_csv('dat/a1-100ohm.csv', skiprows=16, usecols=[3, 4], names=["t", "U"])

# Zeit von Sekunden in Nanosekunden umrechnen
data.t *= 1e9

# Daten plotten, um einen Überblick zu gewinnen
data.plot(x="t", y="U")


Out[11]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f6eac2377b8>

Fitten

Diesen Datensatz wollen wir Fitten. Zum Fitten benötigt man immer ein Modell, Startparameter und Messwerte, für die der Fit durchgeführt werden soll. Wir definieren alles in der nächsten Zelle.


In [12]:
# Fitmodell definieren
def aufladekurve_kondensator(params, t):
    try :
        p = params  # needed for fitting with lmfit
    except:
        p = params.valuesdict()  # needed later for plotting a fitresult
        
    return p["U0"] * (1 - np.exp(-(t - p["t0"]) / p["tau"])) + p["offset"]
modell = aufladekurve_kondensator
    
# Startparameter festlegen
params = lmfit.Parameters()
params.add("U0", value=11.6, vary=True)
params.add("tau", 500)
params.add("t0", -50)
params.add("offset", -12)

# Messwerte für das Fitten auswählen
# Die Daten für t<0 werden für den Fit hier ignoriert, da zu sehen ist,
# dass der Anstieg der Spannung nicht durch unser Modell beschrieben wird.
# Das ist hier auch nicht schlimm, da noch genügend Messdaten vorliegen.
# Es ist auch sinnvoll, da die Rechteckspannung an den Rändern nicht perfekt
# ist. 
fitdata = data[(data.t > 0)]  

# Fitdaten auswählen
X, Y = fitdata.t, fitdata.U

# Fehler der y-Werte definieren
Yerr = 0.03 * fitdata.U

Jetzt erstellen wir einen $\chi^2$-Minimierer und führen den Fit durch. Definiert man das Modell immer in der Variable modell, die Parameter immer in params und die Messwerte in (X, Y, Yerr). Dann kann die nächste Zelle für jeden Fit 1zu1 übernommen werden.


In [13]:
# chi2 minimizer erstellen
minimizer = lmfit.Minimizer(userfcn=residual(modell), 
                            params=params, 
                            fcn_args=(X,Y), 
                            fcn_kws=dict(eps=Yerr),
                            nan_policy="omit"
                           )

# fit auch tatsächlich durchführen
result = minimizer.minimize()

# ergebnis ausgeben
print(lmfit.fit_report(result))


[[Fit Statistics]]
    # function evals   = 66
    # data points      = 1685
    # variables        = 4
    chi-square         = 8153.555
    reduced chi-square = 4.850
    Akaike info crit   = 2664.720
    Bayesian info crit = 2686.438
[[Variables]]
    U0:       23.8403209 +/- 4.87e+05 (2040909.22%) (init= 11.6)
    tau:      242.676249 +/- 1.292101 (0.53%) (init= 500)
    t0:      -95.8668475 +/- 4.96e+06 (5177428.06%) (init=-50)
    offset:  -11.6100358 +/- 4.87e+05 (4190851.07%) (init=-12)
[[Correlations]] (unreported correlations are <  0.100)
    C(U0, offset)                = -1.000 
    C(t0, offset)                =  1.000 
    C(U0, t0)                    = -1.000 
    C(U0, tau)                   = -0.195 
    C(tau, offset)               =  0.195 
    C(tau, t0)                   =  0.195 

Jetzt plotten wir das Resultat.


In [14]:
# plotten
fig, ax = plt.subplots()

data.plot(ax=ax, x="t", y="U", label="Messwerte")
ax.plot(data.t, modell(result.params, data.t), label="Fit", c="r")

ax.legend(loc="lower right", title='Kondensator ($R=100\,\Omega$)')

ax.set_ylim(-20,20)
ax.set_xlim(-500,None)

ax.set_xlabel('Zeit $t$ [ns]')
ax.set_ylabel('Spannung $U$ [V]')

plt.tight_layout()
plt.savefig('a1-kondensator-100ohm.pdf')
plt.show()


Jetzt fitten wir die Kurve für die Spule. Die Dokumentation wird abgekürzt.


In [15]:
# Daten importieren 
data = pd.read_csv('data/a1-aufladekurve-spule-100ohm.csv', skiprows=16, usecols=[3,4], names=["t", "U"])

# Zeit von Sekunden in millisekunden umrechnen
data.t = data.t * 1e6

# Fitmodell definieren
def aufladekurve_spule(params, t):
    try :
        p = params  # needed for fitting with lmfit
    except:
        p = params.valuesdict()  # needed later for plotting a fitresult
        
    return p["U0"] * (np.exp(-(t - p["t0"]) / p["tau"])) + p["offset"]
modell = aufladekurve_spule

# Startparameter festlegen
params = lmfit.Parameters()
params.add("U0", 22.5, vary='False')
params.add("tau", 100)
params.add("t0", -50)
params.add("offset", -12)

# Fitten
fitdata = data[(data.t > 10)]
X, Y = fitdata.t, fitdata.U
Yerr = 0.03 * fitdata.U
minimizer = lmfit.Minimizer(userfcn=residual(modell), 
                            params=params, 
                            fcn_args=(X,Y), 
                            fcn_kws=dict(eps=Yerr),
                            nan_policy="omit"
                           )
result = minimizer.minimize()
print(lmfit.fit_report(result))

# Plot erstellen
fig, ax = plt.subplots()
data.plot(ax=ax, x="t", y="U", label="Messwerte")
ax.plot(data.t, aufladekurve_spule(result.params, data.t), label="Fit", c="r")
ax.legend(loc="upper right", title='Kondensator ($R=100\,\Omega$)')
ax.set_xlim(-50,200)
ax.set_ylim(-5,25)
ax.set_xlabel('Zeit $t$ [$\mu$s]')
ax.set_ylabel('Spannung $U$ [V]')
plt.tight_layout()
plt.savefig('a1-spule-100ohm.pdf')
plt.show()


[[Fit Statistics]]
    # function evals   = 51
    # data points      = 2009
    # variables        = 4
    chi-square         = 15536.977
    reduced chi-square = 7.749
    Akaike info crit   = 4117.582
    Bayesian info crit = 4140.003
[[Variables]]
    U0:       30.4869217 +/- 1.51e+06 (4950209.33%) (init= 22.5)
    tau:      50.6677472 +/- 0.253606 (0.50%) (init= 100)
    t0:      -14.6903309 +/- 2.49e+06 (16972474.12%) (init=-50)
    offset:   0.58849667 +/- 0.010192 (1.73%) (init=-12)
[[Correlations]] (unreported correlations are <  0.100)
    C(U0, t0)                    = -1.000 
    C(tau, offset)               = -0.879 
    C(U0, offset)                =  0.138 
    C(t0, offset)                = -0.138 

Mit Messunsicherheiten rechnen

Dazu benutzen wir das Paket uncertainties, das uns die Fehlerrechnung abnimmt.


In [16]:
# Definiere Zeitkonstanten und Widerstand mit Unsicherheiten aus den Fits
tauC= uct.ufloat(242.68,1.27)
tauL = uct.ufloat(50.67, 0.25)
R = uct.ufloat(100, 100*0.05)

# Berechne Kapazität und Induktivität sowie Resonanzfrequenz 
C = tauC/R * 1e-9
L = tauL * R * 1e-6
omega = 1 / (sqrt(L*C))
nu = omega / (2*pi)

# Gebe Ergebnis aus
for i,j in zip(['C = ', 'L = ', 'omega = ', 'nu = '], [C, L, omega, nu]):
    print('{}{}'.format(i,j))


C = (2.43+/-0.12)e-09
L = 0.00507+/-0.00025
omega = (2.852+/-0.010)e+05
nu = (4.539+/-0.016)e+04

Aufgabe 2

Wir plotten die Messung.


In [17]:
# Daten plotten
data = pd.read_csv('dat/a2-100ohm.csv', skiprows=15, usecols=[3,4], names=["t", "U"])
data.t *= 1e6

fig, ax = plt.subplots(dpi=144)
data.plot(ax=ax, x='t', legend=False)
ax.set_xlabel('Zeit $t$ [$\mu$s]')
ax.set_ylabel('Spannung $U$ [V]')
ax.set_ylim(-.3,.3)
plt.tight_layout()
plt.savefig('a2-100ohm.pdf')
plt.show()


Bestimmung von Periodendauer, Frequenz und Kreisfrequenz.


In [18]:
# abgelesene Werte zweier Punkte gleicher Phase nach N Perioden
t1 = uct.ufloat(12.09, .5)
t2 = uct.ufloat(194.6, 1)
N = 8

# periodendauer
T = (t2 - t1) / N

# frequenz
f = 1/T

# kreisfrequenz
omega = 2*pi*f

# ausgabe der werte
for i,j in zip(['T', 'f', 'omega'], [T,f,omega]):
    print('{} = '.format(i), '{:f}'.format(j))


T =  22.81+/-0.14
f =  0.04383+/-0.00027
omega =  0.2754+/-0.0017

Bestimmung des logarithmischen Dekrements und der Güte


In [19]:
# Werte aus Graphen ablesen
U1 = uct.ufloat(0.25, 0.01)
U2 = uct.ufloat(0.05, 0.01)
N = 8

# log Dekrement und Güte berechen
delta = 1 / N * log(U1 / U2)
q = pi / delta
tau = q / omega

# Ausgabe der Werte
for i,j in zip(['delta', 'q', 'tau'], [delta, q, tau]):
    print('{} = '.format(i), '{:f}'.format(j))


delta =  0.201+/-0.025
q =  15.6+/-2.0
tau =  57+/-7

Aufgabe 3


In [20]:
# Plot erstellen
data1 = pd.read_csv('dat/a3-a-kleinefrequenz-100ohm.csv', skiprows=16, usecols=[3,4], names=["t", "U"])
data1.t *= 1e6

data2 = pd.read_csv('dat/a3-a-resonanzfrequenz-100ohm.csv', skiprows=16, usecols=[3,4], names=["t", "U"])
data2.t *= 1e6


fig, (ax1, ax2) = plt.subplots(2)
data1.plot(ax=ax1, x='t', title='$\\omega \\ll \\omega_0$', legend=False)
data2.plot(ax=ax2, x='t', title='$\\omega = \\omega_0$', legend=False)
for ax in (ax1, ax2):
    ax.set_xlabel('Zeit $t$ [$\mu$s]')
    ax.set_ylabel('Spannung $U$ [V]')
ax1.set_yticks([-2,-1,0,1,2])
ax2.set_yticks([-40,-20,0,20,40])
plt.tight_layout()
plt.savefig('a3-a-100ohm.pdf')
plt.show()


Resonanzüberhöhung bzw. Güten berechnen


In [21]:
# Werte ablesen
Uklein = uct.ufloat(1.87, 0.1)
Ures = uct.ufloat(32.5, 1.2)

# Güte bestimmen
q = Ures / Uklein

# Ausgabe
print("q = ", q)


q =  17.4+/-1.1

Zeitkonstante des Anschwingens bestimmen


In [22]:
# Plot
data = pd.read_csv('dat/a3-b-resonanz.csv')
data.columns = ['t', 'U']

fig, ax = plt.subplots()
data.plot(ax=ax, x='t', legend=False)
ax.set_xlabel('Zeit $t$ [$\mu$s]')
ax.set_ylabel('Spannung $U$ [V]')
plt.tight_layout()
plt.savefig('a3-b-resonanz.pdf')
plt.show()



In [23]:
# Ablesen der Werte
Umax = Ures
U1 = uct.ufloat(4, 2)
U2 = uct.ufloat(30,2)
N = 14

t1 = uct.ufloat(44e-6,1e-6)
t2 = uct.ufloat(469e-6, 1e-6)
Nperioden = 19
T = (t2 - t1) / Nperioden
omega = 2 * pi / T

# Berechnung der Zeitkonstanten
delta_anschwing = 1 / N * log((Umax - U1) / (Umax - U2))
q = pi / delta_anschwing
tau = pi / (delta_anschwing * omega)

# Ausgabe
for i,j, in zip(['delta_anschwing', 'q', 'T', 'omega', 'tau'], [delta_anschwing, q, T, omega, tau]):
    print('{} = {}'.format(i,j))


delta_anschwing = 0.17+/-0.07
q = 18+/-7
T = (2.237+/-0.007)e-05
omega = (2.809+/-0.009)e+05
tau = (6.4+/-2.4)e-05

Plotten der übrigen Anschwingkurven


In [24]:
data1 = pd.read_csv('dat/a3-b-schwebung+5kHz-100ohm.csv', skiprows=16, usecols=[3,4], names=['t', 'U'])
data2 = pd.read_csv('dat/a3-b-schwebung-5kHz-100ohm.csv', skiprows=16, usecols=[3,4], names=['t', 'U'])
data3 = pd.read_csv('dat/a3-b-schwebung+10kHz-100ohm.csv', skiprows=16, usecols=[3,4], names=['t', 'U'])
data4 = pd.read_csv('dat/a3-b-schwebung-10kHz-100ohm.csv', skiprows=16, usecols=[3,4], names=['t', 'U'])

for data in [data1, data2, data3, data4]:
    data.t *= 1e6

fig, ((ax1, ax3), (ax2, ax4)) = plt.subplots(2,2, figsize=(8,6), dpi=100)
for data, ax, title in zip(
    [data1, data2, data3, data4], 
    [ax1, ax2, ax3, ax4], 
    ['$+5$ kHz', '$-5$ kHz', '$+10$ kHz', '$-10$ kHz']
):
    data.plot(ax=ax, x='t', legend=False, title=title)
    
for ax in (ax1, ax2, ax3, ax4):
    ax.set_xlim(0,400)
    ax.set_ylim(-12, 12)
for ax in (ax1, ax2):
    ax.set_ylabel('Spannung $U$ [V]')
for ax in (ax2, ax4):
    ax.set_xlabel('Zeit $t$ [$\mu$s]')
for ax in (ax1, ax3):
    ax.set_xlabel('')
plt.tight_layout()
plt.savefig('a3-b-schwebungen.pdf')
plt.show()


Aufgabe 4

Hier wurde die Datei 'a4-data-100ohm' selbst erstellt, deshalb sieht der Import-Befehl anders aus.


In [25]:
# Daten einlesen
data = pd.read_csv('dat/a4-100ohm.csv', comment='#')

# div's in Spannungen umrechnen
data.U0 = data.U0 * data.skal
data.U1 = data.U1 * data.skal

# alpha berechnen
data['alpha'] = arcsin(np.sqrt(data.U1 / data.U0)) / pi
for i in arange(14,28):
    data.ix[i,'alpha'] = 1 - data.ix[i,'alpha']
data

# fehler für alpha und für f berechnen
deltaU = 0.2 * data.skal
data['alpha_err'] = np.sqrt(
    deltaU**2 / data.U0**2 / (1 - (data.U1**2 / data.U0**2)) \
    + deltaU**2 * data.U1**2 / data.U0**4 / (1 - (data.U1**2 / data.U0**2))
)
data['f_err'] = 0.1

# Plotten
fig, ax = plt.subplots()
data.plot(ax=ax, kind='scatter', x='f',y='alpha', yerr='alpha_err', legend=False, edgecolor='none', s=10)
ax.set_xlabel('Frequenz $f$ [kHz]')
ax.set_ylabel('Phasenverschiebung $\\alpha$')
ax.set_yticks([0,0.25,0.5,0.75,1])
ax.set_yticklabels(['$0$', '$\\frac{\\pi}{4}$', '$\\frac{\\pi}{2}$', '$\\frac{3\\pi}{4}$', '$\\pi$'])
ax.set_ylim(0,1)
plt.tight_layout()
plt.savefig('a4-100ohm.pdf')
plt.show()



In [26]:
data.U0.max()/sqrt(2)
fres = uct.ufloat(44.70, 0.01)

# fmin und fmax aus graph ablesen
fmin = uct.ufloat(42.70, 0.01)
fmax = uct.ufloat(46.65, 0.01)

q = fres / (fmax - fmin)
tau = q / fres

for i, j in zip(['fres', 'fmin', 'fmax', 'q', 'tau'], [fres, fmin, fmax, q, tau]):
    print('{} = {}'.format(i,j))


fres = 44.700+/-0.010
fmin = 42.700+/-0.010
fmax = 46.650+/-0.010
q = 11.32+/-0.04
tau = 0.2532+/-0.0009

Aufgabe 5


In [27]:
data = pd.read_csv('dat/a5-100ohm.csv', skiprows=16, usecols=[3,4,10], names=['t', 'CH1', 'CH2'])

# Bestimmung der Frequenzskalierung
# ---------------------------------

# Diese Frequenzen habt ihr (theoretisch) mit einer Rechteckspannung am Wobblegenerator bestimmt
fmin = uct.ufloat(10, 2)  
fmax = uct.ufloat(83, 2)

# Den Wert hättet ihr (theoretisch) beim Anlegen der Rechteckspannung ablesen sollen.
# Er war aber bei jeder Praktikumsgruppe identisch mit dem der Dreieckspannung
Urechteck = uct.ufloat(40, 0.5)  

# Hier muss natürlich die zweifache Amplitude der Dreieckspannung abgelesen werden,
# da die Frequenzen ja auch vom Minimum bis zum Maximum der Dreieckspannung durch-
# laufen werden
Udreieck = uct.ufloat(40, 0.5)

# Der Umrechnungsfaktor zwischen Rechteck und Dreieckspannung, da die Grenzfrequenzen
# (eigentlich) bei Rechteckspannung bestimmt werden, aber die Messung bei Dreieckspannung
# durchgeführt wird
gamma = Urechteck / Udreieck

# Die Resonanzspannung von CH1 ist eigentlich nur wichtig, um die Höhe bei dem 
# 1/sqrt(2)-fachen einzuzeichnen
Ures = uct.ufloat(12.33, 0.5)

# Die Anzahl der Kästchen auf der x-Achse 
smin = uct.ufloat(0.069, 0.001)
smax = uct.ufloat(0.717, 0.001)
sres = uct.ufloat(0.393, 0.001)
s = smax - smin

# Skalierung berechnen
skal = (fmax * gamma - fmin) / s

# Bestimmung von delta omega
Ured = Ures / sqrt(2)

# sklein und sgross können natürlich erst mithilfe des unteren Plots abgelesen werden, indem
# die axhline bei y=Ures/sqrt(2) hinzugefügt wird
sklein = uct.ufloat(0.382, 0.001)
sgross = uct.ufloat(0.405, 0.001)

# Güte bestimmen
delta_omega = (sgross - sklein) * skal
omega = fmin + (sres - smin) * skal
q = omega / delta_omega

for i,j in zip(['gamma', 's', 'skal', 'delta_omega', 'omega', 'q'], [gamma, s, skal, delta_omega, omega, q]):
    print('{} = {}'.format(i,j))


gamma = 1.000+/-0.018
s = 0.6480+/-0.0014
skal = 113+/-5
delta_omega = 2.59+/-0.20
omega = 46.5+/-1.6
q = 17.9+/-1.4

In [28]:
# Plot
fig, ax = plt.subplots()

data.plot(ax=ax, x='t', y="CH2", color="g", legend=False)

ax2 = ax.twinx()
data.plot(ax=ax2, x='t', y="CH1", color="b", legend=False)
ax2.set_ylabel("Amplitude CH1 [div]")


ax.set_xlabel('Frequenzachse [div]')
ax.set_ylabel('Amplitude CH2 [div]')

ax.set_xlim(0.,0.8)
ax.set_ylim(-21,21)

ax.axhline(y=Ures.nominal_value / sqrt(2), xmin=0.2, xmax=0.8, c='r', linewidth=1.)
ax.axvline(x=smin.nominal_value, c='g', linewidth=1., alpha=0.5)
ax.axvline(x=smax.nominal_value, c='g', linewidth=1., alpha=0.5)
ax.axvline(x=sklein.nominal_value, c='y', linewidth=1., alpha=0.5)
ax.axvline(x=sgross.nominal_value, c='y', linewidth=1., alpha=0.5)
ax.axvline(x=sres.nominal_value, c='m', linewidth=1., alpha=0.5)

ax.set_title('Resonanzkurve, 100$\Omega$')
ax.annotate('$\\frac{U_{\\rm{res}}}{\\sqrt{2}}$', 
            xy=(0.655, Ures.nominal_value / sqrt(2)), 
            xycoords='data', 
            ha='left', va='center', 
            color="r")

handles, labels = ax.get_legend_handles_labels()
hndls2, lbls2 = ax2.get_legend_handles_labels()

handles.append(hndls2[0])
labels.append(lbls2[0])

ax.legend(reversed(handles), reversed(labels), loc="upper left", fontsize="small")

plt.grid()
plt.tight_layout()
plt.savefig('a5-100ohm.pdf')
plt.show()


Vergrößerter Plot um die Resonanz


In [29]:
# Plot
fig, ax = plt.subplots()

data.plot(ax=ax, x='t', y="CH2", color="g", legend=False)

ax2 = ax.twinx()
data.plot(ax=ax2, x='t', y="CH1", color="b", legend=False)
ax2.set_ylabel("Amplitude CH1 [div]")


ax.set_xlabel('Frequenzachse [div]')
ax.set_ylabel('Amplitude CH2 [div]')

ax.set_xlim(0.3,0.5)
ax.set_ylim(-21,21)

ax.axhline(y=Ures.nominal_value / sqrt(2), xmin=0.2, xmax=0.8, c='r', linewidth=1.)
ax.axvline(x=sklein.nominal_value, c='y', linewidth=1., alpha=0.5)
ax.axvline(x=sgross.nominal_value, c='y', linewidth=1., alpha=0.5)
ax.axvline(x=sres.nominal_value, c='m', linewidth=1., alpha=0.5)

ax.set_title('Resonanzkurve (vergrößert), 100$\Omega$')
ax.annotate('$\\frac{U_{\\rm{res}}}{\\sqrt{2}}$', 
            xy=(0.655, Ures.nominal_value / sqrt(2)), 
            xycoords='data', 
            ha='left', va='center', 
            color="r")

handles, labels = ax.get_legend_handles_labels()
hndls2, lbls2 = ax2.get_legend_handles_labels()

handles.append(hndls2[0])
labels.append(lbls2[0])

ax.legend(reversed(handles), reversed(labels), loc="upper left", fontsize="small")

plt.grid()
plt.tight_layout()
plt.savefig('a5-100ohm.pdf')
plt.show()



In [ ]: