Courbes de titrages acido-basiques avec LaTeX

Des courbes de titrages et des diagrammes de distribution à insérer dans vos documents LaTeX.

En guise de prolongement à ce précédent article, où des scripts Python sont utilisés pour générer ce type de graphique, voici des solutions pour LaTeX.

Je rappelle que la méthode utilisée s’appuie sur la publication disponible ici, qui propose une méthode algébrique générale pour calculer les valeurs nécessaires.

Je choisis ici un document de type standalone : cette classe laisse la liberté de créer un document à la fois autonome, comme son nom l’indique, mais qui peut facilement être inséré dans un document maître (ce dernier devra alors appeler le package standalone). Un document standalone peut aussi générer une image png du document (celles visibles dans cet article, par exemple), en insérant une commande en option de la première ligne ; puisque cette commande fait appel à un logiciel installé par défaut pour l’installation, je vous renvoie à la documentation du package pour l’adapter à votre ordinateur.

\documentclass[border=0.2cm,11pt,convert={ghostscript,outext=.png,density=800x800}]{standalone}%conversion en png avec ghostscript

%COMPILé AVEC XeLaTeX

\usepackage[T1]{fontenc}
\usepackage[dvipsnames,svgnames]{xcolor}
\usepackage{lmodern}
\mathcode`\.="013B%virgule décimale en mode math
%\usepackage{tikz}% chargé automatiquement par pgfplots
\usepackage{pgfplots}\pgfplotsset{compat=newest}
\pgfplotsset{/pgf/number format/.cd,1000 sep={~},use comma}
\usepackage{siunitx}% unités et écriture de valeurs

Pour tracer les graphiques, on fait appel au package pgfplots, qui accepte des expressions mathématiques, des coordonnées, ou encore des données figurant dans un fichier csv externe. Un environnement axis rassemble les commandes de création du graphique ; cet environnement s’insère lui-même dans un environnement tikzpicture.

\begin{document}
	
\footnotesize

	% définitions des grandeurs chimiques :
	\def\Ke{1e-14}% produit ionique de l'eau
	\def\Ca{0.12}
	\def\Va{10.0} % volume d'acide (mL)
	\def\Cb{0.10}
	%---------------------------------------
	\pgfmathsetmacro{\Veq}{\Ca*\Va/\Cb}

	\begin{tikzpicture}
	[
	%options...
         ]
	\begin{axis}[%...options
	]
	%... commandes de tracés de courbes
	\end{axis}
	\end{tikzpicture}
\end{document}

La méthode de calcul exposée dans l’article implique de passer par la définition d’une succession de fonctions intermédiaires. La première d’entre elles est le pH, la dernière le volume de solution titrante versé, ce qui est tout à fait contre-intuitif, puisqu’en chimie c’est l’inverse : on impose le volume de solution titrante et on mesure le pH. Les grandeurs suivantes sont des fonctions ayant comme variable le pH. Les fonctions sont définies dans les crochets des options de la figure tikzpicture.

	\begin{tikzpicture}
	[
	declare function={%déclaration de fonctions :
	Oxo(\pH)=10^(-\pH);% concentration des ions H3O+
	a0(\pH)=1/(1+1/Oxo(\pH));%fraction de l'espèce protonée
	a1(\pH)=a0(\pH)*1/Oxo(\pH);% fraction de l'espèce déprotonée
	w(\pH)=\Ke/Oxo(\pH)-Oxo(\pH); % concentration OH-
	frac_base(\pH)=a1(\pH) + w(\pH)/\Cb;
	V_verse(\pH)=frac_base(\pH)*\Ca*\Va/\Cb;% volume de base versée
}]
	\begin{axis}[% mise en forme du graphique :
	xmin=0,xmax=25,
	ymin=0,ymax=14,
	xlabel=volume $ V_b $ versé (mL),
	ylabel=pH,
	ytick distance=2,
	minor y tick num=1,% nombre de graduations secondaires intermédiaires
	minor x tick num=4,% nombre de graduations secondaires intermédiaires
	grid,
	grid=both,% grilles primaire et secondaire
	title=titrage pH-métrique d'un acide fort,
	axis line shift=3pt,
	xtick align=outside,
	ytick align=outside,
	tickpos=left,
	]
	% courbe calculée :
	\addplot [domain=0:14,thick,NavyBlue,samples=100,
	]
	({V_verse(Oxo(x)},{x});% volume versé en x, et pH en y
	
	\end{axis}
	\end{tikzpicture}

Le code LaTeX complet pour le titrage d’acide fort :

Code LaTeX pour le titrage de base forte :


Cas des acides et bases faibles, des polyacides et des polybases

La méthode de calcul est très performante même pour des systèmes acido-basiques impliquant des pertes successives de protons : voir mon précédent article pour une mise en oeuvre avec Python.

Malheureusement, il semble que la méthode dépasse les capacités de calcul de LaTeX. Je propose donc ici l’alternative suivante : rédiger un script Python qui réalise tous les calculs nécessaires, et exporte les données dans un fichier .csv ; le code LaTeX n’a plus qu’à importer ces données pour les mettre en forme dans un graphique. Il suffit de placer dans un même dossier le fichier Python et les fichiers LaTeX. Les valeurs de concentrations, de volume, de pKa sont à modifier au début du script Python. Après exécution, une seule compilation LaTeX suffira à mettre à jour les données numériques.

Attention ! Il semble que pour certaines concentrations, des valeurs trop élevées entraînent malgré tout des erreurs dans LaTeX, notamment pour la dérivée…

Le code Python pour les titrages d’acides :

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Créé le Mon May 30 17:23:02 2022

@auteur: david ALBERTO
(www.astrolabe-science.fr)

Ce programme calcule les données nécessaires pour :
    -tracer un diagramme de distribution d'espèces acido-basiques appartenant à un même système.
    - tracer la courbe de titrage de l'acide par une base forte.
    - tracer les proportions de chaque espèce pendant le titrage.
    - tracer la dérivée du pH en fonction du volume de solution titrante.

Le script est prévu pour un n-acide ayant jusqu'à acidités.
Pour des triacides ou diacides ou monoacides,
il suffit de commenter les lignes inutiles faisant intervenir
les Ka_n, les a_n

Source pour la modélisation :
    Kalka, H. Polyprotic Acids and Beyond—An Algebraic Approach.
        Chemistry 2021, 3, 454-508.
        https://doi.org/10.3390/chemistry3020034

"""

import numpy as np
import pandas as pd# création de tableau de donnée et export en fichier csv

# Définition des pKa :------------------
pKa1=1.8
pKa2=6.6
# pKa3=12.3
# pKa4=12

NomFichier='donnees'
NomAcide='maleique' # sans accents !

"""
maléique :          1.8  6.6
phosphorique :      2.1  7.2    12.3
"""

# -------------------------
Ke=1e-14# produit ionique de l'eau
Ka1=10**-pKa1
Ka2=10**-pKa2
# Ka3=10**-pKa3
# Ka4=10**-pKa4

# -------------------------
pH=np.linspace(0,14,500,endpoint=True)# gamme de valeurs de pH

x=10**-pH# x est la concentration des ions H3O+

"""
Les termes "a0", "a1"... sont les fractions de chaque espèce dans la concentration tolae;
a0 : espèce totalement protonée
a1 : espèce ayant perdu 1 proton
a2 : espèce ayant perdu 2 protons, etc.
"""
a0=1/(1+Ka1/x
       +Ka1*Ka2/x**2
       # +Ka1*Ka2*Ka3/x**3
      # +Ka1*Ka2*Ka3*Ka4/x**4
      )

a1=a0*Ka1/x
a2=a0*Ka1*Ka2/x**2
# a3=a0*Ka1*Ka2*Ka3/x**3
# a4=a0*Ka1*Ka2*Ka3*Ka4/x**4

Ca=0.10# concentration de l'acide titré
Cb=0.12#concentration de la solution titrante
Va=10.0# volume de solution d'acide (mL)
w=Ke/x-x# concentration des ions OH-
Veq=Ca*Va/Cb# volume à l'équivalence

Y=(a1
    +2*a2
    # +3*a3
   # +4*a4
   )


n = Y + w/Cb#proportion de base versée par rapport à l'acide
V_verse=n*Va*Ca/Cb# volume de solution titrante versé

# tracé de la dérivée pour la courbe de titrage :
def derivee(x,y):
    deriv=[]
    for N in range(len(x)-1):
        deriv.append(abs((y[N+1]-y[N])/(x[N+1]-x[N])))
    return deriv


deriv=derivee(V_verse,pH)
deriv=deriv+[np.nan] # ajoute une donnée 'NaN' pour ajuster la longueur de liste

#  création d'un tableau de données :
donnees = pd.DataFrame({
                        'pH':np.array(pH),
                        'V':np.array(V_verse),
                        'derivee':np.array(deriv),
                        'a0':np.array(a0),
                        'a1':np.array(a1),
                        'a2':np.array(a2),
                        # 'a3':np.array(a3),
                        # 'a4':np.array(a4),
                        })
    


#  export des données en fichier csv :

donnees.to_csv(NomFichier+'_'+NomAcide+".csv",
          sep=';'# caractére séparant les colonnes
          )

Le code Python pour les titrages de bases :

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Créé le Mon May 30 17:23:02 2022

@auteur: david ALBERTO
(www.astrolabe-science.fr)

Ce programme calcule les données nécessaires pour :
    -tracer un diagramme de distribution d'espèces acido-basiques appartenant à un même système.
    - tracer la courbe de titrage de la base par un acide fort.
    - tracer les proportions de chaque espèce pendant le titrage.
    - tracer la dérivée du pH en fonction du volume de solution titrante.

Le script est prévu pour une n-base captant jusqu'à protons.
Pour des tribases ou dibases ou monobases,
il suffit de commenter les lignes inutiles faisant intervenir
les Ka_n, les a_n

Source pour la modélisation :
    Kalka, H. Polyprotic Acids and Beyond—An Algebraic Approach.
        Chemistry 2021, 3, 454-508.
        https://doi.org/10.3390/chemistry3020034

"""

import numpy as np
import pandas as pd# création de tableau de donnée et export en fichier csv

# Définition des pKa :------------------
pKa1=9.25
# pKa2=10.3
# pKa3=12.3
# pKa4=12

NomFichier='donnees'
NomBase='ammoniac' # sans accents !

"""
ammoniac :      9.25
carbonate :     6.4  10.3
"""
# -------------------------
# Paramètres du titrage :
Cb=0.12# concentration de la base titrée
Vb=10.0# volume de solution de base (mL)
Ca=0.10#concentration de la solution titrante
# -------------------------
Ke=1e-14# produit ionique de l'eau
Ka1=10**-pKa1
# Ka2=10**-pKa2
# Ka3=10**-pKa3
# Ka4=10**-pKa4

# -------------------------
pH=np.linspace(0,14,500,endpoint=True)# gamme de valeurs de pH

x=10**-pH# x est la concentration des ions H3O+

"""
Les termes "a0", "a1"... sont les fractions de chaque espèce dans la concentration totale;
a0 : espèce totalement protonée
a1 : espèce ayant perdu 1 proton
a2 : espèce ayant perdu 2 protons, etc.
"""
a0=1/(1+Ka1/x
        # +Ka1*Ka2/x**2
       # +Ka1*Ka2*Ka3/x**3
      # +Ka1*Ka2*Ka3*Ka4/x**4
      )

a1=a0*Ka1/x
# a2=a0*Ka1*Ka2/x**2
# a3=a0*Ka1*Ka2*Ka3/x**3
# a4=a0*Ka1*Ka2*Ka3*Ka4/x**4

w=Ke/x-x# concentration des ions OH-
Veq=Cb*Vb/Ca# 1er volume à l'équivalence

Y=(a1
    # +2*a2
    # +3*a3
   # +4*a4
   )


n = Y + w/Cb#proportion de base versée par rapport à l'acide

"""
Calcul du volume d'acide versé :
    À adapter selon les cas :
        Veq*(1-n) : monobase
        Veq*(2-n) : dibase
        Veq*(3-n) : tribase,etc.
"""
V_verse=Veq*(1-n) 
# V_verse=Veq*(2-n)
# V_verse=Veq*(3-n)
# V_verse=Veq*(4-n)

# tracé de la dérivée pour la courbe de titrage :
def derivee(x,y):
    deriv=[]
    for N in range(len(x)-1):
        deriv.append(abs((y[N+1]-y[N])/(x[N+1]-x[N])))
    return deriv


deriv=derivee(V_verse,pH)
deriv=deriv+[np.nan] # ajoute une donnée 'NaN' pour ajuster la longueur de liste

#  création d'un tableau de données :
donnees = pd.DataFrame({
                        'pH':np.array(pH),
                        'V':np.array(V_verse),
                        'derivee':np.array(deriv),
                        'a0':np.array(a0),
                        'a1':np.array(a1),
                        # 'a2':np.array(a2),
                        # 'a3':np.array(a3),
                        # 'a4':np.array(a4),
                        })
    


#  export des données en fichier csv :

donnees.to_csv(NomFichier+'_'+NomBase+".csv",
          sep=';'# caractére séparant les colonnes
          )

On peut facilement tracer l’évolution des concentrations des espèces au cours du titrage :

Soyez le premier à commenter

Laisser un commentaire