Esses dias, precisei ler dados gerados no LTspice em um programa Python. Aliás, essa é uma solução relevante para incluir gráficos do LTspice em trabalhos acadêmicos, papers etc... visto que ele não gera gráficos de boa qualidade visual quando impressos.
A solução é bem simples:
No LTspice desenhe o circuito, simule etc... Selecione o gráfico, mande File/Export para gerar um .txt, selecionem os sinais a serem armazenados no arquivo. Como exemplo usei o circuito abaixo e fiz uma análise CC, variando V1 e medindo a tensão antes dos diodos:
Vou chamar esses resultados de diodo.txt. O LTspice gera um arquivo delimitado por tabulações. Agora, para ler em Python, eu poderia usar a biblioteca csv, mas existe uma forma mais pythônica de ler esses dados e plotá-los: usando a função loadtxt da biblioteca NumPy.
Os parâmetros dessa são:
- fname: nome do arquivo
- dtype: tipo de dados esperado
- delimiter: separador
- skiprows: quantas linhas pular no começo
- usecols: uma tupla que permite especificar as colunas que queremos pular
(se não abrir: https://gist.github.com/renanbirck/4743036)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python2.7 | |
# coding: utf-8 | |
# (pd) 2013 Renan Birck <renan.ee.ufsm@gmail.com> | |
import numpy as np, matplotlib.pyplot as plt | |
from scipy import optimize | |
from time import time | |
list_of_files = [('diodo.txt','Dois diodos em polaridades opostas')] | |
datalist = [ ( np.loadtxt(filename,skiprows=1), label ) for filename, label in list_of_files ] | |
Vin = None | |
Vout = None | |
for data, label in datalist: | |
if not Vin: | |
Vin = data[:,0] | |
if not Vout: | |
Vout = data[:,1] | |
plt.plot( data[:,0], data[:,1], label=label ) | |
plt.legend() | |
plt.title(u"Curva do grampeador a diodo") | |
plt.xlabel(u"Vin") | |
plt.ylabel(u"Vout") | |
plt.show() |
Ele pode ser usado com o arquivo diodo.txt que forneço de exemplo (aviso: 4 MB. Clique com o botão direito e mande salvar para o seu browser não sentar)
Obteremos isso:
Podemos mexer na legenda, etc etc... mas cheguei ao que eu queria demonstrar.
E agora, já que temos esses dados, podemos ajustar eles a um modelo. Visualmente, nota-se que eles parecem com uma tangente hiperbólica. Assim, façamos um modelo do tipo
e usaremos o método dos mínimos quadrados para ajustá-lo a uma função desse tipo (poderíamos usar qualquer outro método de otimização). O código então tornar-se-á:
(se não abrir: https://gist.github.com/renanbirck/4743133)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python2.7 | |
# coding: utf-8 | |
# (pd) 2013 Renan Birck <renan.ee.ufsm@gmail.com> | |
import numpy as np, matplotlib.pyplot as plt | |
from scipy import optimize | |
from time import time | |
list_of_files = [('diodo.txt','Dois diodos em polaridades opostas')] | |
datalist = [ ( np.loadtxt(filename,skiprows=1), label ) for filename, label in list_of_files ] | |
Vin = None | |
Vout = None | |
for data, label in datalist: | |
if not Vin: | |
Vin = data[:,0] | |
if not Vout: | |
Vout = data[:,1] | |
plt.plot( data[:,0], data[:,1], label=label ) | |
plt.legend() | |
plt.title(u"Curva do grampeador a diodo") | |
plt.xlabel(u"Vin") | |
plt.ylabel(u"Vout") | |
plt.show() | |
begin = time() | |
print "Entrando no ajuste de curvas..." | |
# Modelo para ajuste das curvas usando a tangente hiperbólica: | |
# f(x) = a tanh(bx+c) + d tanh(e*(x-f)+g) + h tanh(i*(x-j)+k) | |
fitfunc = lambda p, x: p[0]*np.tanh(p[1]*x+p[2]) + p[3]*np.tanh(p[4]*(x-p[5]) +p[6] ) + p[7]*np.tanh(p[8]*(x-p[9])+p[10] ) # Modelo | |
errfunc = lambda p, x, y: fitfunc(p,x) - y # Função objetivo (modelo - valor real) | |
p0 = [1,1,1,1,1,1,0,1,1,0,0] # Chutes iniciais | |
p1, success = optimize.leastsq(errfunc,p0[:],args=(Vin,Vout)) # MMQ | |
finish = time() | |
print "ajuste levou %f segundos." % (finish - begin) | |
plt.cla() | |
plt.clf() | |
plt.plot(Vin,Vout,"r-",label="Resposta do circuito") | |
plt.plot(Vin,fitfunc(p1,Vin),"g-",label="Resposta ajustada") | |
plt.plot(Vin,Vout-fitfunc(p1,Vin),"b-",label=u"Diferença") | |
plt.legend(loc=4) | |
plt.show() |
Após executarmos, obtemos o gráfico:
Como queríamos demonstrar, obtivemos um bom ajuste. O modelo é bem adequado; para visualizarmos os parâmetros bastaria um print p no final do código.
E nem doeu: foram exemplos adaptados do que eu encontrei na documentação do SciPy. :)
Quanto ao desempenho, a leitura dos dados leva 2 segundos, e o ajuste cerca de 15 segundos num i7-2670QM, mas isso pode (e vai) variar dependendo do chute inicial; para um trabalho mais avançado seria interessante e necessário fazer um meta-ajuste.
Nenhum comentário:
Postar um comentário
Não são lidos e não me responsabilizo pelo conteúdo deles.