Labbrapport: laboration 2 - reaktionskinetik för ett koboltkomplex

Utförd av: L., H.
Datum: 2013-01-11
Handledare: Taha Ahmed

Syfte

Syftet med laborationen är att ...

Teori

$\left[\mathrm{Co\left(NH_3\right)_5H_2O}\right]^{3+} \;\xrightarrow[-\mathrm{H_2O}]{+\mathrm{NO_2^-}}\; \left[\mathrm{Co\left(NH_3\right)_5NO_2}\right]^{2+} \rightarrow \left[\mathrm{Co\left(NH_3\right)_5ONO}\right]^{2+}$ (mekanism 1)

$\left[\mathrm{Co\left(NH_3\right)_5H_2O}\right]^{3+} \;\xrightarrow[-\mathrm{H_2O}]{+\mathrm{NO_2^-}}\; \left[\mathrm{Co\left(NH_3\right)_5ONO}\right]^{2+} \rightarrow \left[\mathrm{Co\left(NH_3\right)_5NO_2}\right]^{2+}$ (mekanism 2)

Vi följer ligandutbytet spektrofotometriskt

Reaktionsmekanism för ligandutbytet

$$r = -\frac{d\left[\left[\mathrm{Co(NH_3)_5H_2O}\right]^{3+}\right]}{dt} = k_1 \left[\left[\mathrm{Co(NH_3)_5H_2O}\right]^{3+}\right] \left[\mathrm{HNO_2}\right] \left[\mathrm{NO_2^-}\right]$$
$$r = -\frac{d\left[\left[\mathrm{Co(NH_3)_5H_2O}\right]^{3+}\right]}{dt} = k_1^\prime \left[\left[\mathrm{Co(NH_3)_5H_2O}\right]^{3+}\right]$$

Där $k_1^\prime = k_1 \left[\mathrm{HNO_2}\right] \left[\mathrm{NO_2^-}\right]$.
Jämvikt inställer sig mellan de två isomererna. Den observerade hastighetskonstanten är av första ordningen, $k_2 = k_+ + k_-$.

$$r = -\frac{d\left[\left[\mathrm{Co(NH_3)_5H_2O}\right]^{3+}\right]}{dt} = k_2 \left(\left[\left[\mathrm{Co(NH_3)_5H_2O}\right]^{3+}\right] - \left[\left[\mathrm{Co(NH_3)_5H_2O}\right]^{3+}\right]_\mathrm{eq}\right)$$

Beskrivning av den kinetiska modellen

\begin{equation} R \;\;\xrightarrow[]{k_1^\prime}\;\; I \;\;\xrightarrow[]{k_2}\;\; P \end{equation}
\begin{equation}\tag{4} [R]_t = [R]_0 \exp(-k_1^\prime t) \end{equation}
\begin{equation}\tag{5} [I]_t = \frac{k_1^\prime [R]_0}{k_2 - k_1^\prime} \left(\exp(-k_1^\prime t) - \exp(-k_2 t)\right) \end{equation}
\begin{equation}\tag{6} [P]_t = [R]_0 - [R]_t - [I]_t \end{equation}
\begin{equation}\tag{7} \mathrm{Abs}_\mathrm{lösning} = {\mathrm{Abs_R}} + {\mathrm{Abs_I}} + {\mathrm{Abs_P}} = l\left([R\:]\varepsilon_\mathrm{R} + [I\:]\varepsilon_\mathrm{I} + [P\:]\varepsilon_\mathrm{P}\right) \end{equation}
\begin{equation}\tag{8} \mathrm{Abs}_t = l[R\:]_0\left(\varepsilon_P + \left(\varepsilon_R + \frac{\varepsilon_I k_1^\prime - \varepsilon_P k_2}{k_2 - k_1^\prime} \right)\exp(-k_1^\prime t) + \frac{k_1^\prime(\varepsilon_P - \varepsilon_I)}{k_2 - k_1^\prime}\exp(-k_2 t)\right) \end{equation}
\begin{equation}\tag{9} \mathrm{Abs}_t = \mathrm{Abs} _\infty + \Delta\mathrm{Abs}_1\exp(-k_1^\prime t) + \Delta\mathrm{Abs}_2\exp(-k_2 t) \end{equation}
\begin{equation}\tag{10} \mathrm{Abs}_t = \mathrm{Abs} _\infty + \Delta\mathrm{Abs}_1\exp(-t/\tau_1) + \Delta\mathrm{Abs}_2\exp(-t/\tau_2), \quad\quad k_1^\prime = \left(\tau_1\right)^{-1}, \quad k_2 = \left(\tau_2\right)^{-1} \end{equation}

Svar till förstuderingsfrågor

Del 1

  1. Bestäm våglängden vid absorptionsmaxima för de tre koboltkomplexen (aqua, nitro, nitrito). Vilken färg har ljus med motsvarande våglängd? Vilken färg har lösningar som absorberar vid respektive våglängd?

  2. Skissa absorbansen, Abs, vid 510 nm mot tiden, t, för de två föreslagna reaktionsmekanismerna.

  3. Vilken eller vilka av följande våglängder kan användas för att urskilja mellan de två föreslagna reaktionsmekanismerna?

    • 415 nm,
    • 450 nm,
    • 482 nm,
    • 495 nm,
    • 510 nm.
  4. Antag att mekanism 1 är korrekt. Vilken eller vilka av de ovanstående våglängderna skulle vara bra för att använda för att bestämma hastighetskonstanten för

    • reaktion 1?
    • reaktion 2?
    • reaktion 1 och reaktion 2?
  5. Går det att använda resonemanget från fråga 4 (ovan) om vi istället antar att mekanism 2 är korrekt? Vilka skillnader kan förutses?

Del 2

  1. Vilka är de önskvärda reaktionsförhållandena för att ligandutbytesreaktionen ska bli en pseudo-första ordningens reaktion?

  2. Nämn två parametrar som är viktiga att kontrollera under ett kinetikexperiment.

Utförande

Utrustning och kemikalier

Spektrofotometer (fabrikat, modell), termostat (fabrikat, modell), pH-meter, etc.
Co-lösningar (koncentrationer, och dylikt).

Beredning av reaktionslösningar

  1. Tillredde reaktionslösningar
    Lösning av $\mathrm{Co}$-komplex vatten.
    Lösning av $\mathrm{NaNO_2}$ i vatten, med tillsats av stark syra.

  2. Startade upp termostaten

  3. Tillverkade lösning för mätning av "slutproduktens" absorbans

  4. Förvärmde lösningarna (temperatur?)

  5. Kalibrerade spektrofotometerns baslinje med avjonat vatten

  6. Kinetikstudier vid $510~\mathrm{nm}$ och $45^{\circ}\mathrm{C}$

  7. Bestämde $[\mathrm{HNO_2}]$ och $[\mathrm{NO_2^-}]$

  8. Mätte absorbans för startmaterialet

  9. Mätte absorbans för "slutprodukten"

Resultat

Vi börjar med att plotta den uppmätta absorbanskurvan. För att kunna göra det behöver vi importera den funktion som vi vill använda för plottning (vi använder matplotlib). Detta gäller för resten av dokumentet.

In [150]:
import matplotlib.pyplot as plt
# Öka bredden på text-output till 140 kolumner
numpy.set_printoptions(linewidth = 140)
# Gör plottar lite större än annars
figsize(14, 8.75)

Nedan plottar vi vår experimentellt uppmätta absorbanskurva, Abs mot tid i sekunder.
Det är tydligt att isomeriseringsreaktionen följer reaktionsmekanism 2 (Abs ökar först, sjunker sedan).

In [151]:
filnamn = "data-Lindgren-Holm.csv"
# perhaps we could use scipy.loadtxt() instead? More pedagogical if it avoids the "unpack" parameter
# from scipy import loadtxt
# loadtxt("TEK0006.CSV", delimiter=",", usecols=(0,1)) # load cols number 0 and 1
x_data, y_data = numpy.loadtxt(filnamn, delimiter=",", unpack=True)
plt.plot(x_data, y_data)
plt.xlabel("Tid/sekunder")
plt.ylabel("Abs")
plt.title(filnamn)
plt.yscale("linear")
plt.show()

Här har vi vissa saker som förmodligen bör lösas:

  1. Hur tar vi enklast bort outliers i data?

Analys av kinetikdata -- anpassning av kinetikspår

Vi importerar två funktioner som vi kommer att använda för kurvanpassningen (curve_fit) och för annan beräkning (chdtrc).

In [152]:
# fit with arbitrary function
# från modulen scipy.optimize importerar vi funktionen curve_fit, som optimiserar anpassningen baserat på non-linear least squares
from scipy.optimize import curve_fit
# något obskyr funktion, källa http://docs.scipy.org/doc/scipy/reference/generated/scipy.special.chdtrc.html
from scipy.special import chdtrc
# uncertainties för att enklare utföra beräkningar med osäkerheter
from uncertainties import unumpy

De fyra följande rutorna med kod är viktiga, och bör skrivas för hand av studenten.

In [153]:
# Definiera den kinetiska modellen
def kinetic_model(t, abs0, abs1, abs2, tau1, tau2):
    return abs0 + abs1 * exp(-t/tau1) + abs2 * exp(-t/tau2)
In [154]:
# Namngivning i strängen p_names av rent kosmetiska skäl (används senare...)
p_names = ("abs0", "abs1", "abs2", "tau1", "tau2")
# Initialvärden för parametrarna till vår kinetiska modell (gissningar)
p_guess = (2.0E-1,  # abs0 = p_guess[0]
          -5.0E-2,  # abs1 = p_guess[1]
           2.0E-1,  # abs2 = p_guess[2]
           250,     # tau1 = p_guess[3]
           900)     # tau2 = p_guess[4]
# Beräkna absorbansvärden baserat på initialvärdena ovan (för senare jämförelse med anpassade parametrar)
y_initial = kinetic_model(x_data, *p_guess)
In [155]:
# Använd den kinetiska modellen för att anpassa parametrarna
# popt: anpassade parametrar, pcov: deras kovariansmatris (statistik)
popt, pcov = curve_fit(kinetic_model,
                       x_data,
                       y_data,
                       p0 = p_guess,
                       maxfev = int(1E2))
# maxfev is the maximum number of iterations tried; you
# can try increasing this value if the fit fails.
In [156]:
# Stoppa in de anpassade parametrarna i den kinetiska modellen och beräkna anpassad absorbans-kurva
y_fit = kinetic_model(x_data, *popt)
# Beräkna residualer (skillnad mellan experimentell absorbans och anpassad absorbans-kurva)
y_residual = y_data - y_fit
# Calculate degrees of freedom of fit
DoF = len(x_data) - len(p_guess)
# Calculate Chi-Squared
chisq = sum((y_residual)**2)

Resterande rutor med kod i denna sektion ("Analys av kinetikdata") kan med fördel kopieras och klistras in verbatim, ingen anledning att knappa in rad-för-rad.

In [157]:
plot_exp, = plt.plot(x_data, y_data, "k:", linewidth = 2, label = "Experimental")
plot_init, = plt.plot(x_data, y_initial, "c-", linewidth = 2, label = "Initial fit")
plot_final, = plt.plot(x_data, y_fit, "r--", linewidth = 2, label = "Optimized fit")
# Skapa en legend
legend(loc = 1, ncol = 1)
# Skapa titel och benämning på axlarna
plt.title("Comparing experimental data, initial fit, and optimized fit")
plt.xlabel("Time/seconds")
plt.ylabel("Abs")
plt.show()
In [158]:
# Show residual: difference between data and optimized fit
plt.plot(x_data, y_residual, "r-")
plt.title("Residual")
# Draw horizontal line at 0
plt.axhline(y = 0)
# Label axes
plt.xlabel("Time/seconds")
plt.ylabel("Abs")
plt.show()
In [159]:
print "Antal datapunkter  =", len(x_data)
print "Antal parametrar   =", len(p_guess)
print "Degrees of freedom =", DoF
Antal datapunkter  = 1601
Antal parametrar   = 5
Degrees of freedom = 1596
In [160]:
print "Kovariansmatris : \n", pcov, "\n"
Kovariansmatris : 
[[  6.10020726e-09  -4.71160660e-08   4.24484128e-08   1.13179885e-04  -2.72915619e-04]
 [ -4.71160660e-08   4.31034079e-07  -3.98674727e-07  -1.09888474e-03   2.34604279e-03]
 [  4.24484128e-08  -3.98674727e-07   3.72520016e-07   1.04321100e-03  -2.15564451e-03]
 [  1.13179885e-04  -1.09888474e-03   1.04321100e-03   3.04216653e+00  -5.87442427e+00]
 [ -2.72915619e-04   2.34604279e-03  -2.15564451e-03  -5.87442427e+00   1.31057966e+01]] 

In [161]:
# Göm undan i en funktion?
print "Correlation Matrix :"
for i,row in enumerate(pcov):
    for j in range(len(popt)) :
        print "%10f"%(pcov[i, j]/sqrt(pcov[i, i]*pcov[j, j])), # note: comma at end of print statement suppresses new line
    print # required for proper formatting of matrix
Correlation Matrix :
  1.000000  -0.918842   0.890460   0.830817  -0.965216
 -0.918842   1.000000  -0.994920  -0.959632   0.987071
  0.890460  -0.994920   1.000000   0.979954  -0.975597
  0.830817  -0.959632   0.979954   1.000000  -0.930341
 -0.965216   0.987071  -0.975597  -0.930341   1.000000
In [162]:
print "Estimated parameters with uncertainties (initial guess in parentheses)"
poptwerr = range(len(popt))
for i in range(len(popt)):
    # Here (inside the for-loop) we should build up a unumpy array (arrary with uncertainty values) for each parameter
    poptwerr[i] = unumpy.uarray([popt[i], pcov[i,i]**0.5*max(1, sqrt(chisq/DoF))])
    print ("  %s = %10.5f +/- %10.8f   (%9.5f)" %(p_names[i], unumpy.nominal_values(poptwerr[i]), unumpy.std_devs(poptwerr[i]), p_guess[i]))
Estimated parameters with uncertainties (initial guess in parentheses)
  abs0 =    0.15877 +/- 0.00007810   (  0.20000)
  abs1 =   -0.10565 +/- 0.00065653   ( -0.05000)
  abs2 =    0.22035 +/- 0.00061034   (  0.20000)
  tau1 =  408.55501 +/- 1.74418076   (250.00000)
  tau2 = 1358.81341 +/- 3.62019289   (900.00000)
In [163]:
print "Curve fit converged with:"
print "  ChiSq     = %1.5E" %(chisq)
print "  DoF       = %4g" %(DoF)
print "  ChiSq/DoF = %1.5E" %(chisq/DoF)
print "  CDF       = %4.2f%%" %(100*chdtrc(DoF,chisq))
Curve fit converged with:
  ChiSq     = 1.29030E-04
  DoF       = 1596
  ChiSq/DoF = 8.08461E-08
  CDF       = 100.00%

Next step: calculate $k$ and $K$, preferably without losing uncertainties
Perhaps we should use the uncertainties package!

In [164]:
k1prim = 1 / poptwerr[3]
k2 = 1 / poptwerr[4]
print "k1prim =", k1prim, "ENHET?"
print "k2 =", k2, "ENHET?"
k1prim = 0.00244765079648+/-1.04493772085e-05 ENHET?
k2 = 0.00073593621875+/-1.96070413922e-06 ENHET?

Ta 5 ml av $\mathrm{HNO_2}/\mathrm{NaNO_2}$-lösningen och späd ut det med 5 ml avjonat vatten (så att koncentrationen blir samma som under kinetikmätningen). Mät pH på lösningen.
Från känd koncentration av $\mathrm{NaNO_2}$, känt pH och $p\mathrm{K_a}$-värde för $\mathrm{HNO_2}$ (se SI-data) kan ni sedan räkna ut $[\mathrm{HNO_2}]$ och $[\mathrm{NO_2^-}]$.
Vi saknar värden för $[\mathrm{NaNO_2}]$, $[\mathrm{HNO_2}]$ och $[\mathrm{NO_2^-}]$.

In [165]:
conc_NaNO2 = 0.5 # mol/L
conc_HNO2 = 0.0125 # mol/L
conc_NO2m = 0.5 # mol/L
k1 = k1prim / (conc_HNO2 * conc_NO2m)
print "k1 =", k1 # HÄR BEHÖVS KORREKTA VÄRDEN
print "k2 =", k2
k1 = 0.391624127437+/-0.00167190035336
k2 = 0.00073593621875+/-1.96070413922e-06
In [166]:
# Conc Co is known (each lab group should calculate from weighed mass)
conc_Co = 1 # HÄR BEHÖVS LÄMPLIGT VÄRDE
# Abs / (conc * length)
# Abs read from plot at 510 nm, conc in M, length in dm
epsilon510_ONO = 0.35 / (6.7E-3 * 0.1)
epsilon510_NO2 = 0.15 / (6.7E-3 * 0.1)
\begin{equation} A_\infty = \varepsilon_\mathrm{ONO^-} \cdot [\mathrm{ONO^-}] \cdot l + \varepsilon_\mathrm{NO_2^-} \cdot [\mathrm{NO_2^-}] \cdot l \end{equation}
\begin{equation} [\mathrm{Co^{3+}}] = [\mathrm{ONO^-}] + [\mathrm{NO_2^-}] \quad\Leftrightarrow\quad [\mathrm{ONO^-}] = [\mathrm{Co^{3+}}] - [\mathrm{NO_2^-}] \end{equation}
\begin{equation} [\mathrm{NO_2^-}] = \frac{A_\infty - \varepsilon_\mathrm{ONO^-} \cdot [\mathrm{Co^{3+}}] \cdot l}{\varepsilon_\mathrm{NO_2^-} \cdot l - \varepsilon_\mathrm{ONO^-} \cdot l} \end{equation}

Slutsats

Anpassningen ...

Check this out
http://nbviewer.ipython.org/
Could be nice in combination with http://gist.github.com/
(Let students add ipynb file contents to gist.github.com

Referenser

In [166]: