When doing AC analysis LTspice output text files are presented with 2 columns tab ('\t') separated:
This is how the file is organized:
Freq. V(n002)
1.00000000000000e+001 7.89537182408547e-005,1.25658745335168e-002
1.01157945425990e+001 8.07927122987158e-005,1.27113688143752e-002
1.02329299228075e+001 8.26745385298576e-005,1.28585474288659e-002
1.03514216667934e+001 8.46001944587697e-005,1.30074298662202e-002
1.04712854805090e+001 8.65707008374969e-005,1.31580358408370e-002
[...]
A direct reading with numpy loadtxt
is possibile importing the line as a string and then creating the 2 arrays
import numpy as np
import matplotlib.pyplot as plt
data = np.loadtxt('passaalto_ltspice_ac.txt', skiprows=1, dtype=str)
# create:
# - the freq array from the first column
# - the v array (of complex) manipulating the second column
freq = data[:,0].astype(float)
v = np.array([complex(float(s.split(',')[0]),float(s.split(',')[1])) for s in data[:,1]])
After that, gain and phase values are ready (e.g. for plotting):
# defining a function to be reused
def plot(freq,v):
fig, ax1 = plt.subplots(dpi=100)
ax1.set_xscale('log')
ax2 = ax1.twinx()
ax1.plot(freq, v.real, label='amplitude', color='r')
ax2.plot(freq, np.arctan(v.imag/v.real)/np.pi*180, label='phase', color='b')
ax1.set_xlabel('Frequency [Hz]')
ax1.set_ylabel('Voltage [V]', color='r')
ax2.set_ylabel('Phase [deg.]', color='b')
ax1.legend(loc='center left', frameon=False)
ax2.legend(loc='center right', frameon=False)
return
plot(freq,v)
freq = []
v = []
# opening the text file, process line by line
with open('passaalto_ltspice_ac.txt') as f:
for i,l in enumerate(f.readlines()):
# skip the header
if i>0:
# each line is a string, parse it filling other string variables
col1 = l.rstrip().split('\t')[0] # string with the frequency
col2 = l.rstrip().split('\t')[1] # string with real and imaginary part
col_r = col2.split(',')[0] # real
col_im= col2.split(',')[1] # imag
# cast the values and fill the lists
freq.append(float(col1))
v.append(complex(f'{col_r}+{col_im}j'))
# create numpy arrays
freq = np.array(freq)
v = np.array(v)
plot(freq,v)
# This "dictionary of functions" define a set of rules to be applied column by column
conv_function = {0: lambda s:float(s), # this is simply casting the string to a float (1st field of the file)
1: lambda s: complex(s.decode().split(',')[0]+'+'+s.decode().split(',')[1]+'j') # the 2nd field has to be parsed and cast to a complex
}
# the genfromtxt is driven by the "converters" on how to properly cast the found strings to correct data types (1 float and 1 complex)
data = np.genfromtxt('passaalto_ltspice_ac.txt', delimiter='\t',skip_header=1,converters=conv_function)
freq, v = data['f0'], data['f1'] # f0 and f1 are default names for the structured array which has been created by the genfromtxt method
plot(freq,v)
import numpy as np
import matplotlib.pyplot as plt
When doing analysis scanning on some paramter LTspice output appends each step data to the same file.
For instance, in the case of a scan on a "Rl" parameter (R load) with 2 signals in the file (Vin, Vout):
time V(n002) V(n003)
Step Information: Rl=470 (Run: 1/5)
0.000000000000000e+000 0.000000e+000 -6.369808e-001
1.562499990503952e-010 9.817477e-007 -6.369802e-001
2.499999984806323e-009 1.570796e-005 -6.369672e-001
1.683874996888335e-005 1.056037e-001 -5.432294e-001
[...]
3.997307499968883e-003 -1.691667e-002 -6.513905e-001
4.000000000000000e-003 -9.797175e-016 -6.369818e-001
Step Information: Rl=1K (Run: 2/5)
0.000000000000000e+000 0.000000e+000 -6.589904e-001
6.249999962015806e-010 3.926991e-006 -6.589870e-001
[...]
Moreover, the number of lines per step (sampled data) changes from one step to another!
Therefore, the file has to be parsed line by line to get these numbers before importing into usable arrays
filename = 'transistor2_clipping2.txt'
### Parsing on the file line by line
# The number of lines-per-step is stored into one list,
# During the loop the piece of string containing the paramter values is stored into another list
current_step=-1
step_row_count=[]
step_param_values=[]
with open(filename) as f:
for l in f.readlines():
if l.split(' ')[0]=='Step':
current_step += 1
step_row_count.append(0)
step_param_values.append(l.split(' ')[2])
if current_step>-1 and l.split(' ')[0]!='Step':
step_row_count[current_step] += 1
# Results
print('Lines for each step:',step_row_count)
print('Params values:',step_param_values)
Now the file can ben scanned used loadtxt
iteratively in order to import the data into different arrays
data_list=[]
for i,nrow in enumerate(step_row_count):
# compute exact number of lines to be skipped and to be imported
lines_to_be_skipped = 2 + sum(step_row_count[0:i]) + i
lines_to_be_read = step_row_count[i]
data_list.append(np.loadtxt(filename, delimiter='\t', skiprows=lines_to_be_skipped, max_rows=lines_to_be_read ))
The data_list
list contains one numpy array for each step
plt.subplots(figsize=(12,6),dpi=100)
for i,data in enumerate(data_list):
plt.plot(data[:,0],data[:,1])
plt.plot(data[:,0],data[:,2], label=step_param_values[i])
plt.legend()
plt.show()