From 83e15ec97d15801a13f9bd3c54c2c1d96969bcb4 Mon Sep 17 00:00:00 2001 From: nunobrum Date: Sat, 13 May 2023 09:38:58 +0200 Subject: [PATCH 1/2] Changing list of Library dependencies. --- README.md | 3 +++ pyproject.toml | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 22132c5..68d24c4 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,9 @@ documentation is directly included in the source file docstrings. * Alternative contact : nuno.brum@gmail.com ## History ## +* Version 4.0.2\ + Changing list of Library dependencies. + * Version 4.0.1\ Bug fix on CLI for the Histogram.py and LTSteps.py diff --git a/pyproject.toml b/pyproject.toml index 6d8bbf5..acb3bae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ requires = [ build-backend = "setuptools.build_meta" [project] name = "PyLTSpice" -version = "4.0.1" +version = "4.0.2" authors = [ { name="Nuno Brum", email="me@nunobrum.com" }, ] @@ -15,7 +15,8 @@ readme = "README.md" license = { file="LICENSE" } requires-python = ">=3.7" dependencies = [ - "numpy==1.21", + "numpy", + "scipy", "psutil", "clipboard", "matplotlib" From e6041f27034ebf92d8f13d3c0970f92a450d85f3 Mon Sep 17 00:00:00 2001 From: nunobrum Date: Sat, 13 May 2023 09:41:29 +0200 Subject: [PATCH 2/2] Adding missing files. --- tests/fra_example.py | 58 ++++++++++++++++++++ tests/raw_plotting.py | 109 ++++++++++++++++++++++++++++++++++++++ tests/raw_write_tools.py | 111 +++++++++++++++++++++++++++++++++++++++ tests/rc_example.asc | 30 +++++++++++ 4 files changed, 308 insertions(+) create mode 100644 tests/fra_example.py create mode 100644 tests/raw_plotting.py create mode 100644 tests/raw_write_tools.py create mode 100644 tests/rc_example.asc diff --git a/tests/fra_example.py b/tests/fra_example.py new file mode 100644 index 0000000..09ad37e --- /dev/null +++ b/tests/fra_example.py @@ -0,0 +1,58 @@ +import matplotlib.pyplot as plt +import numpy as np +from numpy import abs as np_mag +from numpy import angle as np_angle +from PyLTSpice import RawRead + + + +def get_fra_data(logfile): + log = open(logfile, 'r' ) + + log_file_info = log.readlines() + log.close() + for line in log_file_info: + if line[0:12] == 'FRA Instance': + line = line.strip() + _, FRA_info = line.split(': ') + return( FRA_info ) + return( None ) + + +def plot_fra(name, freq, complex_data, FRA_data ): + bode_fig, ax1 = plt.subplots(figsize=(8,4)) + ax2 = ax1.twinx() + + gain = 20*np.log10(np_mag(complex_data)) + phase = np_angle( complex_data, deg=True) + for i in range(len(phase)): + if phase[i] > 0: + phase[i] = phase[i] - 360 + + ax1.semilogx(freq, gain, color='blue') + #ax1.set_title(name) + + ax1.legend([name]) + ax1.yaxis.label.set_color('blue') + ax1.set(xlabel='Frequency', ylabel='Gain (dB)') + ax2.semilogx(freq, phase, color='red', ls='dashed') + ax2.set_ylim([-280, -20]) + ax2.yaxis.label.set_color('red') + ax2.set(xlabel='Frequency', ylabel='Phase (o)') + ax1.minorticks_on() + ax1.xaxis.get_major_locator().set_params(numticks=99) + ax1.xaxis.get_minor_locator().set_params(numticks=99, subs=[.2, .4, .6, .8]) + ax1.grid(True, which='both', axis='both', ls='-') + ax2.grid(which='major', ls='dashed') + plt.title(FRA_data, ha='center') + plt.show() + + +lt_file_name = 'fra_eg1' +lt_fra_raw = RawRead(lt_file_name+'.fra_1.raw') +FRA_info = get_fra_data(lt_file_name+'.log') + +freq = lt_fra_raw.get_axis() +data = lt_fra_raw.get_trace('gain_1').get_wave(0) + +plot_fra( 'gain_1', freq, data, FRA_info ) \ No newline at end of file diff --git a/tests/raw_plotting.py b/tests/raw_plotting.py new file mode 100644 index 0000000..e3a2e70 --- /dev/null +++ b/tests/raw_plotting.py @@ -0,0 +1,109 @@ +import sys +import matplotlib.pyplot as plt +import os +from os.path import split as pathsplit +from os.path import join as pathjoin +import numpy as np +from numpy import abs as mag, angle +from PyLTSpice import RawRead + + +def what_to_units(whattype): + """Determines the unit to display on the plot Y axis""" + if 'voltage' in whattype: + return 'V' + if 'current' in whattype: + return 'A' + + +directory = os.getcwd() + +if len(sys.argv) > 1: + raw_filename = sys.argv[1] + trace_names = sys.argv[2:] + if len(trace_names) == 0: + trace_names = '*' +else: + test_directory = pathjoin(pathsplit(directory)[0], 'tests') + # filename = 'DC sweep.raw' + # filename = 'tran.raw' + # filename = 'tran - step.raw' + # filename = 'ac.raw' + # filename = 'AC - STEP.raw' + # filename = 'PI_Filter_tf.raw' + # filename = 'DC op point - STEP_1.raw' + # filename = 'Noise.raw' + # filename = "test2_gs_000.raw" + filename = 'fra_eg1.fra_1.raw' + filename = 'LTC6241_Noise.raw' + # trace_names = ("run", "V(out)", "V(err)") + trace_names = 'V(onoise)', 'V(inoise)' + raw_filename = pathjoin(test_directory, filename) + +LTR = RawRead(raw_filename, trace_names, verbose=True) +for param, value in LTR.raw_params.items(): + print("{}: {}{}".format(param, " " * (20 - len(param)), str(value).strip())) + +if trace_names == '*': + print("Reading all the traces in the raw file") + trace_names = LTR.get_trace_names() + +traces = [LTR.get_trace(trace) for trace in trace_names] +if LTR.axis is not None: + steps_data = LTR.get_steps() +else: + steps_data = [0] +print("Steps read are :", list(steps_data)) + +if 'complex' in LTR.flags: + n_axis = len(traces) * 2 +else: + n_axis = len(traces) + +fig, axis_set = plt.subplots(n_axis, 1, sharex='all') +write_labels = True + +for i, trace in enumerate(traces): + if 'complex' in LTR.flags: + axises = axis_set[2 * i: 2 * i + 2] # Returns two axis + else: + if n_axis == 1: + axises = [axis_set] # Needs to return a list + else: + axises = axis_set[i:i + 1] # Returns just one axis but enclosed in a list + magnitude = True + for ax in axises: + ax.grid(True) + if 'log' in LTR.flags: + ax.set_xscale('log') + for step_i in steps_data: + if LTR.axis: + x = LTR.get_axis(step_i) + else: + x = np.arange(LTR.nPoints) + y = LTR.get_wave(trace.name, step_i) + if 'complex' in LTR.flags: + x = mag(x) + if magnitude: + ax.set_yscale('log') + y = mag(y) + else: + y = angle(y, deg=True) + if write_labels: + ax.plot(x, y, label=str(steps_data[step_i])) + else: + ax.plot(x, y) + write_labels = False + + if 'complex' in LTR.flags: + if magnitude: + title = f"{trace.name} Mag [db{what_to_units(trace.whattype)}]" + magnitude = False + else: + title = f"{trace.name} Phase [deg]" + else: + title = f"{trace.name} [{what_to_units(trace.whattype)}]" + ax.set_title(title) + +plt.figlegend() +plt.show() diff --git a/tests/raw_write_tools.py b/tests/raw_write_tools.py new file mode 100644 index 0000000..ad7aef2 --- /dev/null +++ b/tests/raw_write_tools.py @@ -0,0 +1,111 @@ +import numpy as np +from PyLTSpice import RawRead, RawWrite, Trace + + +def test_readme_snippet(): + LW = RawWrite(fastacces=False) + tx = Trace('time', np.arange(0.0, 3e-3, 997E-11)) + vy = Trace('N001', np.sin(2 * np.pi * tx.data * 10000)) + vz = Trace('N002', np.cos(2 * np.pi * tx.data * 9970)) + LW.add_trace(tx) + LW.add_trace(vy) + LW.add_trace(vz) + LW.save("teste_snippet1.raw") + + +def test_trc2raw(): # Convert Teledyne-Lecroy trace files to raw files + f = open(r"Current_Lock_Front_Right_8V.trc") + raw_type = '' # Initialization of parameters that need to be overridden by the file header + wave_size = 0 + for line in f: + tokens = line.rstrip('\r\n').split(',') + if len(tokens) == 4: + if tokens[0] == 'Segments' and tokens[2] == 'SegmentSize': + wave_size = int(tokens[1]) * int(tokens[3]) + if len(tokens) == 2: + if tokens[0] == 'Time' and tokens[1] == 'Ampl': + raw_type = 'transient' + break + if raw_type == 'transient' and wave_size > 0: + data = np.genfromtxt(f, dtype='float,float', delimiter=',', max_rows=wave_size) + LW = RawWrite() + LW.add_trace(Trace('time', [x[0] for x in data])) + LW.add_trace(Trace('Ampl', [x[1] for x in data])) + LW.save("teste_trc.raw") + f.close() + + +def test_axis_sync(): # Test axis sync + LW = RawWrite() + tx = Trace('time', np.arange(0.0, 3e-3, 997E-11)) + vy = Trace('N001', np.sin(2 * np.pi * tx.data * 10000)) + vz = Trace('N002', np.cos(2 * np.pi * tx.data * 9970)) + LW.add_trace(tx) + LW.add_trace(vy) + LW.add_trace(vz) + LW.save("teste_w.raw") + LR = RawRead("..\\test_files\\testfile.raw") + LW.add_traces_from_raw(LR, ('V(out)',), force_axis_alignment=True) + LW.save("merge.raw") + test = """ + equal = True + for ii in range(len(tx)): + if t[ii] != tx[ii]: + print(t[ii], tx[ii]) + equal = False + print(equal) + + v = LR.get_trace('N001') + max_error = 1.5e-12 + for ii in range(len(vy)): + err = abs(v[ii] - vy[ii]) + if err > max_error: + max_error = err + print(v[ii], vy[ii], v[ii] - vy[ii]) + print(max_error) + """ + + +def test_write_ac(): + LW = RawWrite() + LR = RawRead("..\\tests\\PI_Filter.raw") + LR1 = RawRead("..\\tests\\PI_Filter_resampled.raw") + LW.add_traces_from_raw(LR, ('V(N002)',)) + LW.add_traces_from_raw(LR1, 'V(N002)', rename_format='N002_resampled', force_axis_alignment=True) + LW.flag_fastaccess = False + LW.save("..\\tests\\PI_filter_rewritten.raw") + LW.flag_fastaccess = True + LW.save("..\\tests\\PI_filter_rewritten_fast.raw") + + +def test_write_tran(): + LR = RawRead("..\\tests\\TRAN - STEP.raw") + LW = RawWrite() + LW.add_traces_from_raw(LR, ('V(out)', 'I(C1)')) + LW.flag_fastaccess = False + LW.save("..\\tests\\TRAN - STEP0_normal.raw") + LW.flag_fastaccess = True + LW.save("..\\tests\\TRAN - STEP0_fast.raw") + + +def test_combine_tran(): + LW = RawWrite() + for tag, raw in ( + ("AD820_15", "../tests/Batch_Test_AD820_15.raw"), + # ("AD820_10", "../tests/Batch_Test_AD820_10.raw"), + ("AD712_15", "../tests/Batch_Test_AD712_15.raw"), + # ("AD712_10", "../tests/Batch_Test_AD712_10.raw"), + # ("AD820_5", "../tests/Batch_Test_AD820_5.raw"), + # ("AD712_5", "../tests/Batch_Test_AD712_5.raw"), + ): + LR = RawRead(raw) + LW.add_traces_from_raw(LR, ("V(out)", "I(R1)"), rename_format="{}_{tag}", tag=tag, force_axis_alignment=True) + LW.flag_fastaccess = False + LW.save("../tests/Batch_Test_Combine.raw") + + +# test_readme_snippet() +# test_axis_sync() +# test_write_ac() +# test_write_tran() +test_combine_tran() diff --git a/tests/rc_example.asc b/tests/rc_example.asc new file mode 100644 index 0000000..b647d44 --- /dev/null +++ b/tests/rc_example.asc @@ -0,0 +1,30 @@ +Version 4 +SHEET 1 880 680 +WIRE -144 96 -176 96 +WIRE -96 96 -144 96 +WIRE 32 96 -16 96 +WIRE 48 96 32 96 +WIRE -176 112 -176 96 +WIRE 48 128 48 96 +WIRE -176 208 -176 192 +WIRE -48 208 -176 208 +WIRE 48 208 48 192 +WIRE 48 208 -48 208 +WIRE -48 224 -48 208 +FLAG -48 224 0 +FLAG -144 96 in +FLAG 32 96 out +SYMBOL voltage -176 96 R0 +WINDOW 123 0 0 Left 0 +WINDOW 39 0 0 Left 0 +SYMATTR InstName V1 +SYMATTR Value 10V +SYMBOL res 0 80 R90 +WINDOW 0 0 56 VBottom 2 +WINDOW 3 32 56 VTop 2 +SYMATTR InstName R1 +SYMATTR Value 1k +SYMBOL cap 32 128 R0 +SYMATTR InstName C1 +SYMATTR Value 1µ +TEXT 16 240 Left 2 !.op