Le programme SPICE (Simulated Program with Integrated Circuit Emphasis) effectue des simulations de circuits électroniques analogiques. La version de référence (spice 2g6, 1983) est écrite en fortran. Une version plus récente (spice 3, 1985) est écrite en C. De nombreux logiciels commerciaux de simulation utilisent le moteur de calcul de SPICE, en ajoutant des fonctions supplémentaires.
On s'intéresse ici aux versions libres de spice, ngspice et SpiceOpus, qui reposent sur spice3f5. Ces deux programmes lisent un fichier texte comportant une description du circuit et différentes commandes. La commande print permet d'exporter les résultats dans un fichier texte. La commande plot permet de tracer des courbes. Afin d'obtenir des sorties graphiques de haute qualité, ou d'effectuer différents traitements des données, il peut être utile d'importer dans Python les données exportées par SPICE avec la commande print. Cette page présente une fonction python faisant cette importation.
Pour exporter des données dans un fichier texte, la commande spice est : PRINT v1 v2 ... > fichier.txt, où v1 v2 ... sont les noms des vecteurs de données à exporter.
La fonction suivante effectue l'importation des données du fichier, qu'elle renvoit sous forme d'un dictionnaire dont les clés sont les noms des champs. Les tableaux numpy obtenus sont des tableaux de réels ou de complexes.
import re
import numpy
def lectureSpicePrint(filename):
f = open(filename,"r")
lignes = f.readlines()
k = 0
while not re.match("-+",lignes[k]):
print(lignes[k])
k += 1
k += 1
entete =lignes[k].strip()
champs = re.split("\s+",entete)
print(champs)
k += 2
ligne = lignes[k].strip()
valeurs = re.split("\s+",ligne)
complexes = []
data = {}
j = 0
for i in range(len(champs)):
valeurs[i] = valeurs[i].strip()
if valeurs[j][len(valeurs[j])-1] == ",":
complexes.append(True)
j += 2
data[champs[i]] = numpy.zeros(0,numpy.complex128)
else:
complexes.append(False)
j += 1
data[champs[i]] = numpy.zeros(0,numpy.float64)
index = 0
while k < len(lignes):
ligne = lignes[k].strip()
if re.match("^[\d+]",ligne):
valeurs = re.split("\s+",ligne)
j = 0
for i in range(len(champs)):
if complexes[i]:
valeurs[j]= valeurs[j][:len(valeurs[2])-1]
valeurs[j]= valeurs[j].replace(",",".")
valeurs[j+1]= valeurs[j+1].replace(",",".")
data[champs[i]] = numpy.append(data[champs[i]],complex(float(valeurs[j]),float(valeurs[j+1])))
j += 2
else:
valeurs[j]= valeurs[j].replace(",",".")
data[champs[i]] = numpy.append(data[champs[i]],float(valeurs[j]))
j += 1
k += 1
f.close()
return data
On considère un circuit RC :
Figure pleine pageLe fichier ci-dessous décrit ce circuit et fait une analyse AC (réponse fréquentielle). Les données exportées sont la tension en décibel et la phase sur le noeud 2.
Circuit RC
v1 1 0 dc 0 ac 1
r1 1 2 1k
c1 2 0 100n
r2 2 0 1MEG
.control
ac dec 10 10Hz 100kHz
print vdb(2) vp(2)> export-1.txt
.endc
.end
Voici la commande exécutée :
ngspice -b circuitRC-1.cir
et l'importation des données dans python :
from lectureSpicePrint import lectureSpicePrint
from matplotlib.pyplot import *
data = lectureSpicePrint("export-1.txt")
f = data["frequency"]
vdb2 = data["vdb(2)"]
vp2 = data["vp(2)"]
figure(figsize=(10,10))
subplot("211")
plot(f,vdb2)
xscale('symlog')
xlabel('f (Hz)')
ylabel('GdB')
grid()
subplot("212")
plot(f,vp2)
xscale('symlog')
xlabel('f (Hz)')
ylabel('phi (rad)')
grid()
Figure pleine pageFaisons une analyse transitoire avec le même circuit :
Circuit RC
v1 1 0 dc 1
r1 1 2 1k
c1 2 0 100n ic=0
r2 2 0 1MEG
.control
tran 1Us 1ms uic
print v(2)> export-2.txt
.endc
.end
ngspice -b circuitRC-2.cir
data = lectureSpicePrint("export-2.txt")
t = data["time"]*1000
v2 = data["v(2)"]
figure(figsize=(10,5))
plot(t,v2)
xlabel("t (ms)")
ylabel("v2 (V)")
grid()
Figure pleine page