From bcd760c060bcbb939d512f38c33b58c411620c5b Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 17 Apr 2025 15:06:38 +0100 Subject: [PATCH 1/6] Add requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b680ed5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +scikit-rf From f2c71e3df16b5d1c576d1b5f87cb403f5fa254ca Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 17 Apr 2025 15:17:32 +0100 Subject: [PATCH 2/6] Create gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..83dad5e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +stospice.py From c8600ee56f396878547f4ad303f6fd5c9c92e801 Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 17 Apr 2025 15:18:28 +0100 Subject: [PATCH 3/6] Update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 83dad5e..7646668 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -stospice.py +*:Zone.Identifier + From b6ba9242fcb7b75bc824cea818665535ee04ff92 Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 17 Apr 2025 15:18:41 +0100 Subject: [PATCH 4/6] Add matplotlib to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index b680ed5..49be80f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ scikit-rf +matplotlib From d5a1f43164e35d4c7e9ec7e5397c8d5b44e01067 Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 17 Apr 2025 15:18:51 +0100 Subject: [PATCH 5/6] Add shebang --- stospice.py | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 stospice.py diff --git a/stospice.py b/stospice.py old mode 100644 new mode 100755 index 9759901..fcaaab7 --- a/stospice.py +++ b/stospice.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python def stospice(filename, name, f, s, z0): dim = 100 From 4e01c9cb2aec6fb74c61e35550f15bedaeac40f7 Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 17 Apr 2025 17:56:58 +0100 Subject: [PATCH 6/6] Added code to extract comments from input and paste into output Improved command line Made file handline more Pithonesque Added example in output --- stospice.py | 79 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/stospice.py b/stospice.py index fcaaab7..3b25211 100755 --- a/stospice.py +++ b/stospice.py @@ -1,48 +1,79 @@ #!/usr/bin/env python -def stospice(filename, name, f, s, z0): + + +def extract_comments(infilename): + comments = [] + with open(infilename, "r") as ifd: + lines = ifd.read().splitlines() + for line in lines: + line = line.strip() + if not line.startswith("!"): + continue + comments.append(f"* {line[1:]}") + return comments + + +def stospice(filename, name, f, s, z0, comments=None): dim = 100 nports = s.shape[1] if nports > dim - 2: raise SystemExit('too many ports') z0 = z0 if hasattr(z0, '__len__') else [ z0 ] * nports - line = [] - nodes = " ".join(str(i+1) for i in range(nports+1)) - line.append(f'.SUBCKT {name} {nodes}') + lines = [] + ports = list(range(1, nports+1)) + nodes = " ".join(f"{p}" for p in ports) + nodes += " gnd_node" + lines.append(f"*\n*** Example use in SPICE:") + port_names = " ".join(f"Port{p}" for p in ports) + lines.append(f"** X {name} {port_names} GND") + lines.append("") + lines.append(f'.SUBCKT {name} {nodes}') + lines.append(f"Vgnd_node_{nports+1} {nports+1} gnd_node 0") for i in range(nports): - line.append(f"R{i+1}N { (i+1)} {dim*(i+1) } { -z0[i].real}") - line.append(f"R{i+1}P {dim*(i+1)} {dim*(i+1)+1} {2*z0[i].real}") - line.append('') + lines.append(f"R{i+1}N { (i+1)} {dim*(i+1) } { -z0[i].real}") + lines.append(f"R{i+1}P {dim*(i+1)} {dim*(i+1)+1} {2*z0[i].real}") + lines.append('') for i in range(nports): for j in range(nports): index = (i * nports) + j + 1 k = dim * (i + 1) + j + 1 out = nports + 1 if j == nports - 1 else k + 1 - line.append(f'A{k} %vd({dim*(j+1)} {nports+1}) %vd({k}, {out}) xfer{index}') - line.append(f'.model xfer{index} xfer R_I=true table=[') + lines.append(f'A{k} %vd({dim*(j+1)} {nports+1}) %vd({k}, {out}) xfer{index}') + lines.append(f'.model xfer{index} xfer R_I=true table=[') for n in range(len(s)): - line.append(f'+ {f[n]} {s[n,i,j].real} {s[n,i,j].imag}') - line.append('+ ]') - line.append('') - line.append('.ENDS\n') - text = '\n'.join(line) - with open(filename, 'w') as fd: + lines.append(f'+ {f[n]} {s[n,i,j].real} {s[n,i,j].imag}') + lines.append('+ ]') + lines.append('') + lines.append('.ENDS\n') + text = "" + if comments: + text += "\n".join(comments) + text += "\n" + text += '\n'.join(lines) + with open(filename, 'w+') as fd: fd.write(text) - if __name__ == '__main__': - import os - import sys + from pathlib import Path import skrf import argparse - parser = argparse.ArgumentParser() - parser.add_argument('filename', nargs=1, help='s-parameter file to validate against') + parser = argparse.ArgumentParser( + description="stospice: A program that converts S-Parameter (*.S[234]P) files into a spice netlist .inc file") + parser.add_argument('filename', type=str, help='s-parameter file to convert to SPICE netlist') + parser.add_argument('-o', dest="overwrite", action="store_true", help="Force overwrite exsting output", default=False) args = parser.parse_args() - filename = args.filename[0] - rootname = os.path.splitext(filename)[0] - incfile = f'{rootname}.inc' + filename = Path(args.filename) + incfile = filename.with_suffix('.inc') + if incfile.exists and not args.overwrite: + raise IOError("Output file {incfile} exists, use -o to overwrite") nw = skrf.Network(filename) - stospice(incfile, nw.name, nw.f, nw.s, nw.z0[0]) + comments = extract_comments(filename) + name = nw.name + stospice(incfile, name, nw.f, nw.s, nw.z0[0], comments) + print(f"Converted {filename} to {incfile} and created SPICE sub-circuit {name}") + +