Determinacinó de Carbono Activo en Suelo

Table of Contents

1. Método de Weil adaptado por Culman

1.1. Curva de calibración del colorímetro

Para determinar carbono activo utilizando la metodología propuesta por Weil et al. (2003), se mide absorbancia a 530nm (verde) de una muestra de suelo tratada con una solución de \(KMnO_4\). La determinación de concentración de carbono activo se utiliza la siguiente expresión:

\begin{equation} POXC \left[ \frac{mg}{kg_{soil}} \right] = \left[0.02 [\frac{mol}{L}] - (a + b \times Abs) \right] \times 9000 [\frac{mg C}{mol}] \times 0.02 [\frac{rx solution}{W_t}] \end{equation}

donde:

  • \(a\): es la ordenada al origen de la curva de calibración
  • \(b\): es la pendiente de la curva de calibración
  • \(Abs\): es la absorbancia de la muestra de suelo
  • \(W_t\): es el peso de la muestra de suelo en \(kg\)

La curva de calibración se construye midiendo absorbancia para concentraciones conocidas de \(KMnO_4\). Se prepararon soluciones con las concentraciones detalladas en la tabla a continuación.

1.1.1. Carga de datos

Los datos se leen de un archivo CSV, con punto y coma (;) como separadores de campo y comas (,) como separador decimal. Se asume que la primer fila contiene los encabezados. iloc se utiliza para seleccionar sólo algunas filas de la tabla de datos.

import numpy as np
import pandas as pd

data = pd.read_csv('CalibraciónPermanganato_M5.csv', sep=';', decimal=',').iloc[[0,1,2,3]]
print(data)
   Concentración  Medicion Abs FCA  Medicion Abs FCEN  Medicion Abs Espectrofotometro
0          0.005             0.110              0.168                           0.107
1          0.010             0.210              0.261                           0.213
2          0.015             0.313              0.355                           0.325
3          0.020             0.421              0.456                           0.435

Esto simplemente imprime las columnas de la tabla de Pandas.

print(data.columns)
Index(['Concentración', 'Medicion Abs FCA', 'Medicion Abs FCEN',
       'Medicion Abs Espectrofotometro'],
      dtype='object')

1.1.2. Cálculo de los parámetros de la regresión lineal

A partir de los datos anteriores calculamos la regresión lineal con el paquete stats para obtener la pendiente y la ordenada al origen, necesarias para calcular la concentración de carbono activo:

from scipy import stats

conc = data['Concentración']
#absor = data['Medicion Abs Espectrofotometro']
absor = data['Medicion Abs FCA']

result = stats.linregress(absor, conc)
print(f'Pendiente = {result.slope}\nOrdenada = {result.intercept}')
Pendiente = 0.048247983457834244
Ordenada = -0.00021334364113932344
print(result)
LinregressResult(slope=0.048247983457834244, intercept=-0.00021334364113932344, rvalue=0.9998490972373407, pvalue=0.00015090276265927738, stderr=0.000592757309912432, intercept_stderr=0.0001706199173031585)
  1. Análisis de errores: intervalos de confianza de la regresión lineal

    Ahora calculamos los intervalos de confianza de los parámetros de la regresión lineal (pendiente y ordenada), con un nivel de significancia \(\gamma\) determinado [1].

    from scipy.stats import t
    import sigfig as sf
    
    gamma = (100-95)/100 #Nivel de confianza del 95% igual a 2*sigma
    #gamma = (100-68)/100 #Nivel de confianza del 95% igual a 1*sigma
    t_n2 = t.ppf(1-gamma/2, 4-2)
    
    # pendiente_conc_abs = 1/result.slope
    # ordenda_conc_abs = -result.intercept/result.slope
    pendiente_conc_abs = result.slope
    ordenada_conc_abs = result.intercept
    
    err_pendiente = (result.stderr)*t_n2
    err_ordenada = (result.intercept_stderr)*t_n2
    
    #print(f'Pendiente = {pendiente_conc_abs} +- {err_pendiente}\nOrdenada = {ordenda_conc_abs} +- {err_ordenada}')
    print(f'Pendiente = {sf.round(pendiente_conc_abs, err_pendiente)}')
    print(f'Ordenada = {sf.round(ordenada_conc_abs, err_ordenada)}')
    
    Pendiente = 0.048 ± 0.003
    Ordenada = -0.0002 ± 0.0007
    
  2. Interpretación gráfica del intervalo de confianza de la regresión lineal

    El intervalo de confianza representa toda la familia de rectas posibles cuyas pendientes se encuentran en el intervalo de confianza \((pendiente\_conc\_abs \pm err\_pendiente)\) y ordenadas en el intervalo \((ordenda\_conc\_abs \pm err\_ordenada)\)

    import matplotlib.pyplot as plt
    
    fig=plt.figure(figsize=(8,5))
    
    plt.plot(absor, conc, 'o')
    y = pendiente_conc_abs * absor + ordenada_conc_abs
    y1 = (pendiente_conc_abs + err_pendiente) * absor + ordenada_conc_abs - err_ordenada
    y2 = (pendiente_conc_abs - err_pendiente) * absor + ordenada_conc_abs + err_ordenada
    plt.plot(absor, y, '-r')
    plt.plot(absor, y1, '-g')
    plt.plot(absor, y2, '-g')
    plt.xlabel("Absorbancia")
    plt.ylabel("Concentración molar")
    plt.grid()
    
    fig.tight_layout()
    fname = 'myfig.png'
    plt.savefig(fname)
    fname # return this to org-mode
    

    myfig.png

    También es posible hacer el gráfico de la regresión lineal y el intervalo de confianza con el paquete Seaborn

    import seaborn as sns
    fig_sns=plt.figure(figsize=(8,5))
    
    ax = sns.regplot(x=absor, y=conc)
    ax.set_xlabel("Absorbancia")
    ax.set_ylabel("Concentración molar")
    ax.grid()
    
    fname = 'myfig_sns.png'
    fig_sns = ax.get_figure()
    fig_sns.savefig(fname)
    fname # return this to org-mode
    

    myfig_sns.png

1.2. Análisis de muestras de suelo

Calculamos ahora la concentración de carbono activo utilizando la ecuación propuesta por Weil et al. (2003):

\begin{equation} POXC \left[ \frac{mg}{kg_{soil}} \right] = \left[0.02 [\frac{mol}{L}] - (a + b \times Abs) \right] \times 9000 [\frac{mg C}{mol}] \times 0.02 [\frac{rx solution}{W_t}] \end{equation}

donde:

  • \(a\): es la ordenada al origen de la regresión lineal
  • \(b\): es la pendiente de la regresión lineal
  • \(Abs\): es la absorbancia de la muestra de suelo
  • \(W_t\): es el peso de la muestra de suelo en \(kg\)
Table 1: Parámetros de la regresión lineal para la curva de calibración de \(KMnO_4\) para el colorímetro de FCA
  Curva de calibración 2 (FCA)
Pendiente 19.62
Ordenada -0.002
Error Pendiente 0.44
Error Ordenada 0.006

Las medidas de absorbancia para 4 muestras de suelo están dadas en la tabla 2.

Table 2: Valores de absorbancia para 4 muestras de suelo medidas con el colorímetro de FCA.
Muestras Abosrbancias FCA
A2 0.29
2 0.237
6 0.232
19 0.122

Nota: los valores de pendiente y ordenada de la tabla 1 corresponden a la función \(Absorbancia(concentración)\). Pero para el cálculo de POXC necesitamos la función inversa. Podemos calcular la regresión lineal intercambiando las variables o, calcular los parámetros pendiente y ordenada para la función inversa a partir de los dados en la tabla 1:

\begin{equation} Absorbancia = b \times concentración + a \end{equation} \begin{equation} Concentración = \frac{Absorbancia}{b} - \frac{a}{b} \end{equation}

entonces

\begin{equation} b' = 1/b \end{equation} \begin{equation} a' = -a/b \end{equation}

Vamos a continuar utilizando los parámetros obtenidos para la curva de calibración de Culman, por lo que no es necesario calcular la función inversa. Para la muestra A2 el valor la concentración de carbono activo es:

import numpy as np
a = ordenada_conc_abs
b = pendiente_conc_abs
da = err_ordenada
db = err_pendiente
W_t = 0.0025
Abs_A2 = 0.29

POXC = (0.02 - (a + b*Abs_A2)) * 9000 * 0.02 / W_t
print(f'POXC = {sf.round(POXC, 3)} [mg/kg]')
POXC = 448.0 [mg/kg]

1.3. Cálculo del error en la concentración de carbono activo

Para calcular el error final en \(POXC\) hay que hacer propagación de errores, teniendo en cuenta los errores en la pendiente y la ordenada al origen de la regresión lineal:

\begin{equation} \Delta POXC = \sqrt{ {\left( \frac{\partial POXC}{\partial{a}} \times \Delta a \right)}^2 + {\left( \frac{\partial POXC}{\partial{b}} \times \Delta b \right)}^2} \end{equation}

donde:

  • \(\frac{\partial POXC}{\partial{a}}\) es la derivada parcial de \(POXC\) respecto de \(a\)
  • \(\frac{\partial POXC}{\partial{b}}\) es la derivada parcial de \(POXC\) respecto de \(b\)
  • \(\Delta a\) es el error en \(a\)
  • \(\Delta b\) es el error en \(b\)

La ecuación 4 sólo tiene en cuenta los errores en los parámetros de ajuste (ordenada y pendiente), despreciando los errores en la Absorbancia (\(Abs\)) y la masa de la muestra de suelo (\(W_t\)). Esto es así ya que los errores relativos en estas medidas es menor que el error en los parámetros de ajuste.

operando en la ecuación 1 se obtiene que:

\begin{equation} \frac{\partial POXC}{\partial{a}} = 9000 \times 0.02 / W_t \end{equation} \begin{equation} \frac{\partial POXC}{\partial{b}} = Abs \times 9000 \times 0.02 / W_t \end{equation}

Aplicando el resultado anterior a la muestra de suelo *A2“ resulta:

dPOXC_da = 9000 * 0.02/W_t
dPOXC_db = Abs_A2 * 9000 * 0.02/W_t

dPOXC = np.sqrt( (dPOXC_da * da)**2 + (dPOXC_db * db)**2  )

print(f'POXC = {sf.round(POXC, dPOXC)}')
POXC = 450 ± 80

El intervalo de confianza es:

POXC = (370.0, 520.0)

El error relativo porcentual es:

\(\Delta POXC = 17\%\)

1.4. Interpretación gráfica de la propagación del error

Ahora vamos a graficar la función resultante \(POXC vs Abs\), para ver gráficamente cómo se propagan los errores. Para ello vamos a generar una serie de datos aleatorios de pendientes y ordenadas según los intervalos de confianza calculados y luego, sobre esa nueva serie de datos, calculamos la regresión lineal.

from scipy import stats

conc = data['Concentración']
#absor = data['Medicion Abs Espectrofotometro']
absor = data['Medicion Abs FCA']
pendientes =  (np.random.randn(4)*db)+b
ordenadas = (np.random.randn(4)*da + a)

def calc_poxc(absorbance):
    return (0.02 - (ordenadas + pendientes*absorbance)) * 9000 * 0.02 / W_t

poxc = calc_poxc(absor)
result = stats.linregress(absor, poxc)
print(  f'Pendiente = {sf.round(result.slope, (result.stderr)*t_n2)}')
Pendiente = -3500 ± 800

Ahora graficamos la familia de rectas encontradas y vemos si los intervalos de confianza se condicen con el error calculado por propagación:

fname = './myfig_poxc_reg.png'
fig=plt.figure(figsize=(8,5))

pendiente = result.slope
ordenada = result.intercept
err_pendiente = (result.stderr)*t_n2
err_ordenada = (result.intercept_stderr)*t_n2

plt.plot(absor, poxc, 'o')
y = pendiente * absor + ordenada
y1 = (pendiente + err_pendiente) * absor + ordenada - err_ordenada
y2 = (pendiente - err_pendiente) * absor + ordenada + err_ordenada
plt.plot(absor, y, '-r')
plt.plot(absor, y1, '-g')
plt.plot(absor, y2, '-g')
plt.xlabel("Absorbancia")
plt.ylabel("POXC [mg/Kg]")
plt.grid()

fig.tight_layout()

plt.savefig(fname)
fname # return this to org-mode

myfig_poxc_reg.png

2. Protocolo Mc Knight

Este protocolo comparte la misma metodología que aquel propuesto por Culman, excepto en: la alícuota de 0,5 mL de la muestra tratada se diluye en 30 mL de agua destilada; no se realiza una curva de calibración, sino que solo se usa el valor de absorbancia del Permanganato de Potasio y el valor de absorbancia de la muestra.

\begin{equation} POXC[mg/kg]=(1-\frac{abs_{muestra}}{abs_{KMnO4}}*0,02M)* 0,02 * 9000)/ 0,0025 \end{equation}

2.1. Análisis de errores

En este caso las fuentes de error son las absorbancias tanto de la muestra como del permanganato. Por lo tanto, el erro en \(POXC\) viene dado por:

\begin{equation} \Delta POXC = \sqrt{ {\left( \frac{\partial POXC}{\partial{abs_{muestra}}} \times \Delta abs_{muestra} \right)}^2 + {\left( \frac{\partial POXC}{\partial{abs_{KMnO4}}} \times \Delta abs_{KMnO4} \right)}^2} \end{equation}

donde:

  • \(\frac{\partial POXC}{\partial{abs_{muestra}}}\) es la derivada parcial de \(POXC\) respecto de \(abs_{muestra}\)
  • \(\frac{\partial POXC}{\partial{abs_{KMnO4}}}\) es la derivada parcial de \(POXC\) respecto de \(abs_{KMnO4}\)
  • \(\Delta abs_{muestra}\) es el error en \(abs_{muestra}\)
  • \(\Delta abs_{KMnO4}\) es el error en \(abs_{KMnO4}\)

Los errores en \(abs_{muestra}\) y \(abs_{KMnO4}\) son los que corresponden al instrumento utilizado. Si existen razones para suponer que hay otras fuentes de error (por ejemplo, de método al prepara las dilusiones), es necesario estimar esos errores haciendo estadística. Es decir, midiendo varias veces la misma muestra, y calcular el valor promedio y desvación estándar de la absorbancia.

3. Apéndice

Si lo que tenemos es la función inversa \(abs(conc)\) necesitamos la función inversa, por lo que es conveniente calcular la regresión al revés, considerando la absorbancia como la variable independiente. Comparamos los resultados para demostrar que da lo mismo.

print('La función original....')
print(f'Pendiente = {sf.round(b, db)}')


result_inv = stats.linregress(conc, absor)

err_pendiente = (err_pendiente)*t_n2
err_ordenada = (err_ordenada)*t_n2

b = result_inv.slope
a = result_inv.intercept
db = (result_inv.stderr)*t_n2
da = (result_inv.intercept_stderr)*t_n2

print('Resultado de la regresión calculada con absorbancia como variable independiente')
print(f'Pendiente_inv = {sf.round(result_inv.slope, (result_inv.stderr)*t_n2)}')

print('Ahora calculamos los parámetros de la función inversa y sus errores:')

b_inv = 1/b
a_inv = -a/b

err_b_inv = 1/b**2 * db
err_a_inv = np.sqrt((-1/b * da)**2 + (-a/b**2 * db)**2)

print(  f'Pendiente = {sf.round(b_inv, err_b_inv)}')
print('Da exactamente lo mismo!!!')
La función original....
Pendiente = 0.048 ± 0.003
Resultado de la regresión calculada con absorbancia como variable independiente
Pendiente_inv = 21 ± 1
Ahora calculamos los parámetros de la función inversa y sus errores:
Pendiente = 0.048 ± 0.003
Da exactamente lo mismo!!!

4. Referencias

  1. John R. Taylor, “Introduction To Error Analysis: The Study of Uncertainties in Physical Measurements”, University Science Books, 1997.

Author: Pablo Cremades

Created: 2023-11-04 Sat 09:40