@tscircuit/ngspice-spice-engine 0.0.15 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -2
- package/dist/index.js +73 -7
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SpiceEngine } from '@tscircuit/props';
|
|
2
1
|
import { ResultType } from '@tscircuit/eecircuit-engine';
|
|
2
|
+
import { SpiceEngine } from '@tscircuit/props';
|
|
3
3
|
|
|
4
4
|
interface TranParams {
|
|
5
5
|
tstep?: number;
|
|
@@ -10,6 +10,8 @@ interface TranParams {
|
|
|
10
10
|
}
|
|
11
11
|
declare const parseTranParams: (spiceString: string) => TranParams | null;
|
|
12
12
|
|
|
13
|
+
declare const rewritePspiceCompatibilitySyntax: (spiceString: string) => string;
|
|
14
|
+
|
|
13
15
|
interface VoltageGraph {
|
|
14
16
|
netName: string;
|
|
15
17
|
time: number[];
|
|
@@ -26,4 +28,4 @@ interface ProbeMetadata {
|
|
|
26
28
|
declare const eecircuitResultToVGraphs: (result: ResultType, spiceString: string) => VoltageGraph[];
|
|
27
29
|
declare const createNgspiceSpiceEngine: () => Promise<SpiceEngine>;
|
|
28
30
|
|
|
29
|
-
export { type TranParams, createNgspiceSpiceEngine, createNgspiceSpiceEngine as default, eecircuitResultToVGraphs, parseTranParams };
|
|
31
|
+
export { type TranParams, createNgspiceSpiceEngine, createNgspiceSpiceEngine as default, eecircuitResultToVGraphs, parseTranParams, rewritePspiceCompatibilitySyntax };
|
package/dist/index.js
CHANGED
|
@@ -108,6 +108,71 @@ var parseTranParams = (spiceString) => {
|
|
|
108
108
|
return null;
|
|
109
109
|
};
|
|
110
110
|
|
|
111
|
+
// lib/rewrite-pspice-compatibility-syntax.ts
|
|
112
|
+
var pspiceNumberToken = String.raw`([+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))(?:[eE][+-]?\d+)?)`;
|
|
113
|
+
var rewritePspiceResistorTcPairs = (spiceString) => spiceString.split(/\r?\n/).map((line) => {
|
|
114
|
+
if (!/^\s*r/i.test(line)) return line;
|
|
115
|
+
return line.replace(
|
|
116
|
+
new RegExp(
|
|
117
|
+
String.raw`\bTC\s*=\s*${pspiceNumberToken}\s*,\s*${pspiceNumberToken}\b`,
|
|
118
|
+
"gi"
|
|
119
|
+
),
|
|
120
|
+
"TC1=$1 TC2=$2"
|
|
121
|
+
);
|
|
122
|
+
}).join("\n");
|
|
123
|
+
var pspiceComparisonOperator = "(?:<=|>=|==|!=|(?<![!<>=])=(?!=)|<|>)";
|
|
124
|
+
var pspiceComparisonOperand = String.raw`(?:V\s*\([^)]*\)|\{[^}\r\n]+\}|${pspiceNumberToken}(?:[a-zA-Z]+)?|[A-Za-z_][\w.$]*)`;
|
|
125
|
+
var pspiceComparisonExpression = String.raw`${pspiceComparisonOperand}\s*${pspiceComparisonOperator}\s*${pspiceComparisonOperand}`;
|
|
126
|
+
var pspiceComparisonBeforeCaretPattern = new RegExp(
|
|
127
|
+
String.raw`${pspiceComparisonExpression}\s*$`,
|
|
128
|
+
"i"
|
|
129
|
+
);
|
|
130
|
+
var pspiceComparisonAfterCaretPattern = new RegExp(
|
|
131
|
+
String.raw`^\s*\+?\s*${pspiceComparisonExpression}`,
|
|
132
|
+
"i"
|
|
133
|
+
);
|
|
134
|
+
var isPspiceBooleanCaret = (block, caretOffset, operatorLength) => pspiceComparisonBeforeCaretPattern.test(block.slice(0, caretOffset)) && pspiceComparisonAfterCaretPattern.test(
|
|
135
|
+
block.slice(caretOffset + operatorLength)
|
|
136
|
+
);
|
|
137
|
+
var rewritePspiceValueBooleanCarets = (spiceString) => {
|
|
138
|
+
let result = "";
|
|
139
|
+
let cursor = 0;
|
|
140
|
+
const valueStartPattern = /\bVALUE\s*\{/gi;
|
|
141
|
+
for (; ; ) {
|
|
142
|
+
valueStartPattern.lastIndex = cursor;
|
|
143
|
+
const match = valueStartPattern.exec(spiceString);
|
|
144
|
+
if (!match) break;
|
|
145
|
+
const blockStart = match.index;
|
|
146
|
+
const firstBraceIndex = spiceString.indexOf("{", blockStart);
|
|
147
|
+
let depth = 0;
|
|
148
|
+
let blockEnd = -1;
|
|
149
|
+
for (let i = firstBraceIndex; i < spiceString.length; i++) {
|
|
150
|
+
const char = spiceString[i];
|
|
151
|
+
if (char === "{") {
|
|
152
|
+
depth += 1;
|
|
153
|
+
} else if (char === "}") {
|
|
154
|
+
depth -= 1;
|
|
155
|
+
if (depth === 0) {
|
|
156
|
+
blockEnd = i + 1;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (blockEnd === -1) break;
|
|
162
|
+
result += spiceString.slice(cursor, blockStart);
|
|
163
|
+
const block = spiceString.slice(blockStart, blockEnd);
|
|
164
|
+
result += block.replace(/\s+\^\s+/g, (operator, offset, fullBlock) => {
|
|
165
|
+
if (isPspiceBooleanCaret(fullBlock, offset, operator.length)) {
|
|
166
|
+
return operator.replace("^", "!=");
|
|
167
|
+
}
|
|
168
|
+
return operator;
|
|
169
|
+
});
|
|
170
|
+
cursor = blockEnd;
|
|
171
|
+
}
|
|
172
|
+
return result + spiceString.slice(cursor);
|
|
173
|
+
};
|
|
174
|
+
var rewritePspiceCompatibilitySyntax = (spiceString) => rewritePspiceValueBooleanCarets(rewritePspiceResistorTcPairs(spiceString));
|
|
175
|
+
|
|
111
176
|
// lib/index.ts
|
|
112
177
|
var ensureSimulation = async () => {
|
|
113
178
|
const { Simulation: SimulationCtor } = await import("@tscircuit/eecircuit-engine");
|
|
@@ -127,7 +192,7 @@ var getSimulation = async () => {
|
|
|
127
192
|
};
|
|
128
193
|
var extractRequestedPlots = (spiceString) => {
|
|
129
194
|
const match = spiceString.match(/\.print\s+tran\s+(.*)/i);
|
|
130
|
-
if (!match
|
|
195
|
+
if (!match?.[1]) {
|
|
131
196
|
return null;
|
|
132
197
|
}
|
|
133
198
|
const tokens = match[1].match(/[VI]\s*\([^)]+\)/gi);
|
|
@@ -162,7 +227,6 @@ var extractProbeMetadata = (spiceString) => {
|
|
|
162
227
|
reference_node_name: typeof parsed.reference_node_name === "string" ? parsed.reference_node_name : void 0
|
|
163
228
|
});
|
|
164
229
|
} catch {
|
|
165
|
-
continue;
|
|
166
230
|
}
|
|
167
231
|
}
|
|
168
232
|
return metadata;
|
|
@@ -179,7 +243,7 @@ var getNetName = (rawName) => {
|
|
|
179
243
|
return match[1] ?? rawName;
|
|
180
244
|
};
|
|
181
245
|
var eecircuitResultToVGraphs = (result, spiceString) => {
|
|
182
|
-
if (!result
|
|
246
|
+
if (!result?.data || result.dataType !== "real") {
|
|
183
247
|
return [];
|
|
184
248
|
}
|
|
185
249
|
const timeData = result.data.find((item) => item.type === "time");
|
|
@@ -281,7 +345,8 @@ var voltageGraphsToCircuitJson = (graphs, spiceString) => {
|
|
|
281
345
|
};
|
|
282
346
|
var simulate = async (spiceString) => {
|
|
283
347
|
const simulation = await getSimulation();
|
|
284
|
-
|
|
348
|
+
const simulationSpiceString = rewritePspiceCompatibilitySyntax(spiceString);
|
|
349
|
+
simulation.setNetList(simulationSpiceString);
|
|
285
350
|
let result;
|
|
286
351
|
try {
|
|
287
352
|
result = await simulation.runSim();
|
|
@@ -292,11 +357,11 @@ var simulate = async (spiceString) => {
|
|
|
292
357
|
if (!result) {
|
|
293
358
|
return { simulationResultCircuitJson: [] };
|
|
294
359
|
}
|
|
295
|
-
const graphs = eecircuitResultToVGraphs(result,
|
|
360
|
+
const graphs = eecircuitResultToVGraphs(result, simulationSpiceString);
|
|
296
361
|
return {
|
|
297
362
|
simulationResultCircuitJson: voltageGraphsToCircuitJson(
|
|
298
363
|
graphs,
|
|
299
|
-
|
|
364
|
+
simulationSpiceString
|
|
300
365
|
)
|
|
301
366
|
};
|
|
302
367
|
};
|
|
@@ -310,5 +375,6 @@ export {
|
|
|
310
375
|
createNgspiceSpiceEngine,
|
|
311
376
|
index_default as default,
|
|
312
377
|
eecircuitResultToVGraphs,
|
|
313
|
-
parseTranParams
|
|
378
|
+
parseTranParams,
|
|
379
|
+
rewritePspiceCompatibilitySyntax
|
|
314
380
|
};
|