@tscircuit/ngspice-spice-engine 0.0.16 → 0.0.17
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 +31 -9
- package/dist/index.js +274 -120
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { ResultType } from '@tscircuit/eecircuit-engine';
|
|
2
1
|
import { SpiceEngine } from '@tscircuit/props';
|
|
2
|
+
import { ResultType } from '@tscircuit/eecircuit-engine';
|
|
3
|
+
import { SimulationTransientVoltageGraph, SimulationTransientCurrentGraph } from 'circuit-json';
|
|
3
4
|
|
|
4
5
|
interface TranParams {
|
|
5
6
|
tstep?: number;
|
|
@@ -12,20 +13,41 @@ declare const parseTranParams: (spiceString: string) => TranParams | null;
|
|
|
12
13
|
|
|
13
14
|
declare const rewritePspiceCompatibilitySyntax: (spiceString: string) => string;
|
|
14
15
|
|
|
15
|
-
interface
|
|
16
|
-
netName: string;
|
|
17
|
-
time: number[];
|
|
18
|
-
voltage: number[];
|
|
19
|
-
probeMetadata?: ProbeMetadata;
|
|
20
|
-
}
|
|
21
|
-
interface ProbeMetadata {
|
|
16
|
+
interface VoltageProbeMetadata {
|
|
22
17
|
simulation_voltage_probe_id: string;
|
|
23
18
|
name?: string;
|
|
24
19
|
spice_vector: string;
|
|
25
20
|
source_node_name: string;
|
|
26
21
|
reference_node_name?: string;
|
|
27
22
|
}
|
|
23
|
+
interface CurrentProbeMetadata {
|
|
24
|
+
simulation_current_probe_id: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
spice_vector: string;
|
|
27
|
+
source_component_id?: string;
|
|
28
|
+
source_trace_id?: string;
|
|
29
|
+
}
|
|
30
|
+
interface VoltageGraph {
|
|
31
|
+
graphType: "voltage";
|
|
32
|
+
netName: string;
|
|
33
|
+
time: number[];
|
|
34
|
+
voltage: number[];
|
|
35
|
+
probeMetadata?: VoltageProbeMetadata;
|
|
36
|
+
}
|
|
37
|
+
interface CurrentGraph {
|
|
38
|
+
graphType: "current";
|
|
39
|
+
currentName: string;
|
|
40
|
+
time: number[];
|
|
41
|
+
current: number[];
|
|
42
|
+
probeMetadata?: CurrentProbeMetadata;
|
|
43
|
+
}
|
|
44
|
+
type SimulationGraph = VoltageGraph | CurrentGraph;
|
|
45
|
+
|
|
46
|
+
declare const eecircuitResultToSimulationGraphs: (result: ResultType, spiceString: string) => SimulationGraph[];
|
|
28
47
|
declare const eecircuitResultToVGraphs: (result: ResultType, spiceString: string) => VoltageGraph[];
|
|
48
|
+
|
|
49
|
+
declare const simulationGraphsToCircuitJson: (graphs: SimulationGraph[], spiceString: string) => Array<SimulationTransientVoltageGraph | SimulationTransientCurrentGraph>;
|
|
50
|
+
|
|
29
51
|
declare const createNgspiceSpiceEngine: () => Promise<SpiceEngine>;
|
|
30
52
|
|
|
31
|
-
export { type TranParams, createNgspiceSpiceEngine, createNgspiceSpiceEngine as default, eecircuitResultToVGraphs, parseTranParams, rewritePspiceCompatibilitySyntax };
|
|
53
|
+
export { type TranParams, createNgspiceSpiceEngine, createNgspiceSpiceEngine as default, eecircuitResultToSimulationGraphs, eecircuitResultToVGraphs, parseTranParams, rewritePspiceCompatibilitySyntax, simulationGraphsToCircuitJson };
|
package/dist/index.js
CHANGED
|
@@ -1,28 +1,3 @@
|
|
|
1
|
-
// lib/linear-interpolate.ts
|
|
2
|
-
var linearInterpolate = (targetX, xPoints, yPoints) => {
|
|
3
|
-
if (xPoints.length === 0) {
|
|
4
|
-
return 0;
|
|
5
|
-
}
|
|
6
|
-
if (targetX <= xPoints[0]) {
|
|
7
|
-
return yPoints[0];
|
|
8
|
-
}
|
|
9
|
-
if (targetX >= xPoints[xPoints.length - 1]) {
|
|
10
|
-
return yPoints[yPoints.length - 1];
|
|
11
|
-
}
|
|
12
|
-
let i = 1;
|
|
13
|
-
while (i < xPoints.length && xPoints[i] < targetX) {
|
|
14
|
-
i++;
|
|
15
|
-
}
|
|
16
|
-
const x1 = xPoints[i - 1];
|
|
17
|
-
const y1 = yPoints[i - 1];
|
|
18
|
-
const x2 = xPoints[i];
|
|
19
|
-
const y2 = yPoints[i];
|
|
20
|
-
if (x2 === x1) {
|
|
21
|
-
return y1;
|
|
22
|
-
}
|
|
23
|
-
return y1 + (y2 - y1) * (targetX - x1) / (x2 - x1);
|
|
24
|
-
};
|
|
25
|
-
|
|
26
1
|
// lib/parse-tran-params.ts
|
|
27
2
|
var SUFFIX_MULTIPLIERS = {
|
|
28
3
|
t: 1e12,
|
|
@@ -173,43 +148,84 @@ var rewritePspiceValueBooleanCarets = (spiceString) => {
|
|
|
173
148
|
};
|
|
174
149
|
var rewritePspiceCompatibilitySyntax = (spiceString) => rewritePspiceValueBooleanCarets(rewritePspiceResistorTcPairs(spiceString));
|
|
175
150
|
|
|
176
|
-
// lib/
|
|
177
|
-
var
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return instance;
|
|
182
|
-
};
|
|
183
|
-
var simulationPromise = null;
|
|
184
|
-
var getSimulation = async () => {
|
|
185
|
-
if (!simulationPromise) {
|
|
186
|
-
simulationPromise = ensureSimulation().catch((error) => {
|
|
187
|
-
simulationPromise = null;
|
|
188
|
-
throw error;
|
|
189
|
-
});
|
|
151
|
+
// lib/create-graph-from-requested-plot.ts
|
|
152
|
+
var getNetName = (rawName) => {
|
|
153
|
+
const diffMatch = rawName.match(/^v\(([^,]+),\s*([^)]+)\)$/i);
|
|
154
|
+
if (diffMatch?.[1] && diffMatch?.[2]) {
|
|
155
|
+
return `${diffMatch[1].trim()}-${diffMatch[2].trim()}`;
|
|
190
156
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const match = spiceString.match(/\.print\s+tran\s+(.*)/i);
|
|
195
|
-
if (!match?.[1]) {
|
|
196
|
-
return null;
|
|
157
|
+
const match = rawName.match(/^v\((.*)\)$/i);
|
|
158
|
+
if (!match) {
|
|
159
|
+
return rawName;
|
|
197
160
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
161
|
+
return match[1] ?? rawName;
|
|
162
|
+
};
|
|
163
|
+
var getCurrentName = (rawName) => {
|
|
164
|
+
const match = rawName.match(/^i\((.*)\)$/i);
|
|
165
|
+
if (!match) {
|
|
166
|
+
return rawName;
|
|
201
167
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
168
|
+
return match[1] ?? rawName;
|
|
169
|
+
};
|
|
170
|
+
var createVoltageGraphFromRequestedPlot = ({
|
|
171
|
+
lowerCaseToken,
|
|
172
|
+
originalToken,
|
|
173
|
+
timeValues,
|
|
174
|
+
voltageDataMap,
|
|
175
|
+
voltageProbeMetadata
|
|
176
|
+
}) => {
|
|
177
|
+
if (!lowerCaseToken.startsWith("v(")) return null;
|
|
178
|
+
const diffMatch = originalToken.match(/^v\(([^,]+),\s*([^)]+)\)$/i);
|
|
179
|
+
let voltage;
|
|
180
|
+
if (diffMatch?.[1] && diffMatch?.[2]) {
|
|
181
|
+
voltage = voltageDataMap.get(lowerCaseToken);
|
|
182
|
+
if (!voltage) {
|
|
183
|
+
const node1 = diffMatch[1].trim();
|
|
184
|
+
const node2 = diffMatch[2].trim();
|
|
185
|
+
const node1Data = voltageDataMap.get(`v(${node1.toLowerCase()})`);
|
|
186
|
+
const node2Data = voltageDataMap.get(`v(${node2.toLowerCase()})`);
|
|
187
|
+
if (node1Data && node2Data) {
|
|
188
|
+
voltage = node1Data.map((v, i) => v - (node2Data[i] ?? 0));
|
|
189
|
+
}
|
|
207
190
|
}
|
|
191
|
+
} else {
|
|
192
|
+
voltage = voltageDataMap.get(lowerCaseToken);
|
|
208
193
|
}
|
|
209
|
-
return
|
|
194
|
+
if (!voltage) return null;
|
|
195
|
+
const metadata = voltageProbeMetadata.get(lowerCaseToken);
|
|
196
|
+
const voltageGraph = {
|
|
197
|
+
graphType: "voltage",
|
|
198
|
+
netName: metadata?.name ?? getNetName(originalToken),
|
|
199
|
+
time: timeValues,
|
|
200
|
+
voltage,
|
|
201
|
+
probeMetadata: metadata
|
|
202
|
+
};
|
|
203
|
+
return voltageGraph;
|
|
210
204
|
};
|
|
205
|
+
var createCurrentGraphFromRequestedPlot = ({
|
|
206
|
+
lowerCaseToken,
|
|
207
|
+
originalToken,
|
|
208
|
+
timeValues,
|
|
209
|
+
currentDataMap,
|
|
210
|
+
currentProbeMetadata
|
|
211
|
+
}) => {
|
|
212
|
+
if (!lowerCaseToken.startsWith("i(")) return null;
|
|
213
|
+
const current = currentDataMap.get(lowerCaseToken);
|
|
214
|
+
if (!current) return null;
|
|
215
|
+
const metadata = currentProbeMetadata.get(lowerCaseToken);
|
|
216
|
+
const currentGraph = {
|
|
217
|
+
graphType: "current",
|
|
218
|
+
currentName: metadata?.name ?? getCurrentName(originalToken),
|
|
219
|
+
time: timeValues,
|
|
220
|
+
current,
|
|
221
|
+
probeMetadata: metadata
|
|
222
|
+
};
|
|
223
|
+
return currentGraph;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// lib/extract-probe-metadata.ts
|
|
211
227
|
var normalizeSpiceVector = (value) => value.toLowerCase().replace(/\s/g, "");
|
|
212
|
-
var
|
|
228
|
+
var extractVoltageProbeMetadata = (spiceString) => {
|
|
213
229
|
const metadata = /* @__PURE__ */ new Map();
|
|
214
230
|
for (const line of spiceString.split(/\r?\n/)) {
|
|
215
231
|
const match = line.match(/^\s*\*\s*tscircuit_probe\s+(.+)\s*$/);
|
|
@@ -219,30 +235,92 @@ var extractProbeMetadata = (spiceString) => {
|
|
|
219
235
|
if (typeof parsed.simulation_voltage_probe_id !== "string" || typeof parsed.spice_vector !== "string" || typeof parsed.source_node_name !== "string") {
|
|
220
236
|
continue;
|
|
221
237
|
}
|
|
222
|
-
|
|
238
|
+
const normalizedSpiceVector = normalizeSpiceVector(parsed.spice_vector);
|
|
239
|
+
const voltageProbeMetadata = {
|
|
223
240
|
simulation_voltage_probe_id: parsed.simulation_voltage_probe_id,
|
|
224
241
|
name: typeof parsed.name === "string" ? parsed.name : void 0,
|
|
225
242
|
spice_vector: parsed.spice_vector,
|
|
226
243
|
source_node_name: parsed.source_node_name,
|
|
227
244
|
reference_node_name: typeof parsed.reference_node_name === "string" ? parsed.reference_node_name : void 0
|
|
228
|
-
}
|
|
245
|
+
};
|
|
246
|
+
metadata.set(normalizedSpiceVector, voltageProbeMetadata);
|
|
229
247
|
} catch {
|
|
230
248
|
}
|
|
231
249
|
}
|
|
232
250
|
return metadata;
|
|
233
251
|
};
|
|
234
|
-
var
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
252
|
+
var extractCurrentProbeMetadata = (spiceString) => {
|
|
253
|
+
const metadata = /* @__PURE__ */ new Map();
|
|
254
|
+
for (const line of spiceString.split(/\r?\n/)) {
|
|
255
|
+
const match = line.match(/^\s*\*\s*tscircuit_current_probe\s+(.+)\s*$/);
|
|
256
|
+
if (!match?.[1]) continue;
|
|
257
|
+
try {
|
|
258
|
+
const parsed = JSON.parse(match[1]);
|
|
259
|
+
if (typeof parsed.simulation_current_probe_id !== "string" || typeof parsed.spice_vector !== "string") {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
const normalizedSpiceVector = normalizeSpiceVector(parsed.spice_vector);
|
|
263
|
+
const currentProbeMetadata = {
|
|
264
|
+
simulation_current_probe_id: parsed.simulation_current_probe_id,
|
|
265
|
+
name: typeof parsed.name === "string" ? parsed.name : void 0,
|
|
266
|
+
spice_vector: parsed.spice_vector,
|
|
267
|
+
source_component_id: typeof parsed.source_component_id === "string" ? parsed.source_component_id : void 0,
|
|
268
|
+
source_trace_id: typeof parsed.source_trace_id === "string" ? parsed.source_trace_id : void 0
|
|
269
|
+
};
|
|
270
|
+
metadata.set(normalizedSpiceVector, currentProbeMetadata);
|
|
271
|
+
} catch {
|
|
272
|
+
}
|
|
238
273
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
274
|
+
return metadata;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
// lib/extract-requested-plots.ts
|
|
278
|
+
var extractRequestedPlots = (spiceString) => {
|
|
279
|
+
const match = spiceString.match(/\.print\s+tran\s+(.*)/i);
|
|
280
|
+
if (!match?.[1]) {
|
|
281
|
+
return null;
|
|
242
282
|
}
|
|
243
|
-
|
|
283
|
+
const tokens = match[1].match(/[VI]\s*\([^)]+\)/gi);
|
|
284
|
+
if (!tokens) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
const plotMap = /* @__PURE__ */ new Map();
|
|
288
|
+
for (const token of tokens) {
|
|
289
|
+
const lowerCaseToken = token.toLowerCase().replace(/\s/g, "");
|
|
290
|
+
if (!plotMap.has(lowerCaseToken)) {
|
|
291
|
+
plotMap.set(lowerCaseToken, token);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return plotMap;
|
|
244
295
|
};
|
|
245
|
-
|
|
296
|
+
|
|
297
|
+
// lib/linear-interpolate.ts
|
|
298
|
+
var linearInterpolate = (targetX, xPoints, yPoints) => {
|
|
299
|
+
if (xPoints.length === 0) {
|
|
300
|
+
return 0;
|
|
301
|
+
}
|
|
302
|
+
if (targetX <= xPoints[0]) {
|
|
303
|
+
return yPoints[0];
|
|
304
|
+
}
|
|
305
|
+
if (targetX >= xPoints[xPoints.length - 1]) {
|
|
306
|
+
return yPoints[yPoints.length - 1];
|
|
307
|
+
}
|
|
308
|
+
let i = 1;
|
|
309
|
+
while (i < xPoints.length && xPoints[i] < targetX) {
|
|
310
|
+
i++;
|
|
311
|
+
}
|
|
312
|
+
const x1 = xPoints[i - 1];
|
|
313
|
+
const y1 = yPoints[i - 1];
|
|
314
|
+
const x2 = xPoints[i];
|
|
315
|
+
const y2 = yPoints[i];
|
|
316
|
+
if (x2 === x1) {
|
|
317
|
+
return y1;
|
|
318
|
+
}
|
|
319
|
+
return y1 + (y2 - y1) * (targetX - x1) / (x2 - x1);
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
// lib/eecircuit-result-to-simulation-graphs.ts
|
|
323
|
+
var eecircuitResultToSimulationGraphs = (result, spiceString) => {
|
|
246
324
|
if (!result?.data || result.dataType !== "real") {
|
|
247
325
|
return [];
|
|
248
326
|
}
|
|
@@ -258,46 +336,62 @@ var eecircuitResultToVGraphs = (result, spiceString) => {
|
|
|
258
336
|
for (const item of voltageDataItems) {
|
|
259
337
|
voltageDataMap.set(item.name.toLowerCase(), item.values);
|
|
260
338
|
}
|
|
339
|
+
const currentDataItems = result.data.filter(
|
|
340
|
+
(item) => item.type === "current" && Array.isArray(item.values)
|
|
341
|
+
);
|
|
342
|
+
const currentDataMap = /* @__PURE__ */ new Map();
|
|
343
|
+
for (const item of currentDataItems) {
|
|
344
|
+
currentDataMap.set(normalizeSpiceVector(item.name), item.values);
|
|
345
|
+
}
|
|
261
346
|
const requestedPlots = extractRequestedPlots(spiceString);
|
|
262
|
-
const
|
|
347
|
+
const voltageProbeMetadata = extractVoltageProbeMetadata(spiceString);
|
|
348
|
+
const currentProbeMetadata = extractCurrentProbeMetadata(spiceString);
|
|
263
349
|
if (!requestedPlots) {
|
|
264
|
-
return
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
350
|
+
return [
|
|
351
|
+
...voltageDataItems.map((item) => {
|
|
352
|
+
const metadata = voltageProbeMetadata.get(
|
|
353
|
+
normalizeSpiceVector(item.name)
|
|
354
|
+
);
|
|
355
|
+
const voltageGraph = {
|
|
356
|
+
graphType: "voltage",
|
|
357
|
+
netName: metadata?.name ?? getNetName(item.name),
|
|
358
|
+
time: timeValues,
|
|
359
|
+
voltage: item.values,
|
|
360
|
+
probeMetadata: metadata
|
|
361
|
+
};
|
|
362
|
+
return voltageGraph;
|
|
363
|
+
}),
|
|
364
|
+
...currentDataItems.map((item) => {
|
|
365
|
+
const metadata = currentProbeMetadata.get(
|
|
366
|
+
normalizeSpiceVector(item.name)
|
|
367
|
+
);
|
|
368
|
+
const currentGraph = {
|
|
369
|
+
graphType: "current",
|
|
370
|
+
currentName: metadata?.name ?? getCurrentName(item.name),
|
|
371
|
+
time: timeValues,
|
|
372
|
+
current: item.values,
|
|
373
|
+
probeMetadata: metadata
|
|
374
|
+
};
|
|
375
|
+
return currentGraph;
|
|
376
|
+
})
|
|
377
|
+
];
|
|
273
378
|
}
|
|
274
379
|
const graphs = [];
|
|
275
380
|
for (const [lowerCaseToken, originalToken] of requestedPlots.entries()) {
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
voltage = voltageDataMap.get(lowerCaseToken);
|
|
291
|
-
}
|
|
292
|
-
if (voltage) {
|
|
293
|
-
const metadata = probeMetadata.get(lowerCaseToken);
|
|
294
|
-
graphs.push({
|
|
295
|
-
netName: metadata?.name ?? getNetName(originalToken),
|
|
296
|
-
time: timeValues,
|
|
297
|
-
voltage,
|
|
298
|
-
probeMetadata: metadata
|
|
299
|
-
});
|
|
300
|
-
}
|
|
381
|
+
const graph = createVoltageGraphFromRequestedPlot({
|
|
382
|
+
lowerCaseToken,
|
|
383
|
+
originalToken,
|
|
384
|
+
timeValues,
|
|
385
|
+
voltageDataMap,
|
|
386
|
+
voltageProbeMetadata
|
|
387
|
+
}) ?? createCurrentGraphFromRequestedPlot({
|
|
388
|
+
lowerCaseToken,
|
|
389
|
+
originalToken,
|
|
390
|
+
timeValues,
|
|
391
|
+
currentDataMap,
|
|
392
|
+
currentProbeMetadata
|
|
393
|
+
});
|
|
394
|
+
if (graph) graphs.push(graph);
|
|
301
395
|
}
|
|
302
396
|
const tranParams = parseTranParams(spiceString);
|
|
303
397
|
if (tranParams?.tstep && tranParams.tstep > 0 && tranParams.tstop && graphs.length > 0) {
|
|
@@ -310,39 +404,94 @@ var eecircuitResultToVGraphs = (result, spiceString) => {
|
|
|
310
404
|
(_, i) => tstart + i * tstep
|
|
311
405
|
);
|
|
312
406
|
const oldTimeValues = graphs[0].time;
|
|
313
|
-
return graphs.map((graph) =>
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
407
|
+
return graphs.map((graph) => {
|
|
408
|
+
if (graph.graphType === "voltage") {
|
|
409
|
+
return {
|
|
410
|
+
...graph,
|
|
411
|
+
time: newTimeValues,
|
|
412
|
+
voltage: newTimeValues.map(
|
|
413
|
+
(t) => linearInterpolate(t, oldTimeValues, graph.voltage)
|
|
414
|
+
)
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
...graph,
|
|
419
|
+
time: newTimeValues,
|
|
420
|
+
current: newTimeValues.map(
|
|
421
|
+
(t) => linearInterpolate(t, oldTimeValues, graph.current)
|
|
422
|
+
)
|
|
423
|
+
};
|
|
424
|
+
});
|
|
320
425
|
}
|
|
321
426
|
}
|
|
322
427
|
return graphs;
|
|
323
428
|
};
|
|
324
|
-
var
|
|
429
|
+
var eecircuitResultToVGraphs = (result, spiceString) => {
|
|
430
|
+
return eecircuitResultToSimulationGraphs(result, spiceString).filter(
|
|
431
|
+
(graph) => graph.graphType === "voltage"
|
|
432
|
+
);
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
// lib/simulation-graphs-to-circuit-json.ts
|
|
436
|
+
var simulationGraphsToCircuitJson = (graphs, spiceString) => {
|
|
325
437
|
const tranParams = parseTranParams(spiceString);
|
|
326
438
|
return graphs.map((graph, index) => {
|
|
327
|
-
|
|
439
|
+
if (graph.graphType === "voltage") {
|
|
440
|
+
const graphIdSource2 = graph.probeMetadata?.simulation_voltage_probe_id ?? `${index}_${graph.netName}`;
|
|
441
|
+
const graphElement2 = {
|
|
442
|
+
type: "simulation_transient_voltage_graph",
|
|
443
|
+
simulation_experiment_id: "placeholder_simulation_experiment_id",
|
|
444
|
+
simulation_transient_voltage_graph_id: `simulation_graph_${graphIdSource2}`,
|
|
445
|
+
name: graph.netName,
|
|
446
|
+
voltage_levels: graph.voltage,
|
|
447
|
+
timestamps_ms: graph.time.map((timePoint) => timePoint * 1e3),
|
|
448
|
+
start_time_ms: (tranParams?.tstart ?? 0) * 1e3,
|
|
449
|
+
time_per_step: (tranParams?.tstep ?? 0) * 1e3,
|
|
450
|
+
end_time_ms: (tranParams?.tstop ?? 0) * 1e3,
|
|
451
|
+
source_probe_id: graph.probeMetadata?.simulation_voltage_probe_id,
|
|
452
|
+
source_probe_name: graph.probeMetadata?.name,
|
|
453
|
+
source_node_name: graph.probeMetadata?.source_node_name,
|
|
454
|
+
reference_node_name: graph.probeMetadata?.reference_node_name
|
|
455
|
+
};
|
|
456
|
+
return graphElement2;
|
|
457
|
+
}
|
|
458
|
+
const graphIdSource = graph.probeMetadata?.simulation_current_probe_id ?? `${index}_${graph.currentName}`;
|
|
328
459
|
const graphElement = {
|
|
329
|
-
type: "
|
|
460
|
+
type: "simulation_transient_current_graph",
|
|
330
461
|
simulation_experiment_id: "placeholder_simulation_experiment_id",
|
|
331
|
-
|
|
332
|
-
name: graph.
|
|
333
|
-
|
|
462
|
+
simulation_transient_current_graph_id: `simulation_graph_${graphIdSource}`,
|
|
463
|
+
name: graph.currentName,
|
|
464
|
+
current_levels: graph.current,
|
|
334
465
|
timestamps_ms: graph.time.map((timePoint) => timePoint * 1e3),
|
|
335
466
|
start_time_ms: (tranParams?.tstart ?? 0) * 1e3,
|
|
336
467
|
time_per_step: (tranParams?.tstep ?? 0) * 1e3,
|
|
337
468
|
end_time_ms: (tranParams?.tstop ?? 0) * 1e3,
|
|
338
|
-
source_probe_id: graph.probeMetadata?.
|
|
469
|
+
source_probe_id: graph.probeMetadata?.simulation_current_probe_id,
|
|
339
470
|
source_probe_name: graph.probeMetadata?.name,
|
|
340
|
-
|
|
341
|
-
|
|
471
|
+
source_component_id: graph.probeMetadata?.source_component_id,
|
|
472
|
+
source_trace_id: graph.probeMetadata?.source_trace_id
|
|
342
473
|
};
|
|
343
474
|
return graphElement;
|
|
344
475
|
});
|
|
345
476
|
};
|
|
477
|
+
|
|
478
|
+
// lib/index.ts
|
|
479
|
+
var ensureSimulation = async () => {
|
|
480
|
+
const { Simulation: SimulationCtor } = await import("@tscircuit/eecircuit-engine");
|
|
481
|
+
const instance = new SimulationCtor({ ngBehavior: "psa" });
|
|
482
|
+
await instance.start();
|
|
483
|
+
return instance;
|
|
484
|
+
};
|
|
485
|
+
var simulationPromise = null;
|
|
486
|
+
var getSimulation = async () => {
|
|
487
|
+
if (!simulationPromise) {
|
|
488
|
+
simulationPromise = ensureSimulation().catch((error) => {
|
|
489
|
+
simulationPromise = null;
|
|
490
|
+
throw error;
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return simulationPromise;
|
|
494
|
+
};
|
|
346
495
|
var simulate = async (spiceString) => {
|
|
347
496
|
const simulation = await getSimulation();
|
|
348
497
|
const simulationSpiceString = rewritePspiceCompatibilitySyntax(spiceString);
|
|
@@ -357,9 +506,12 @@ var simulate = async (spiceString) => {
|
|
|
357
506
|
if (!result) {
|
|
358
507
|
return { simulationResultCircuitJson: [] };
|
|
359
508
|
}
|
|
360
|
-
const graphs =
|
|
509
|
+
const graphs = eecircuitResultToSimulationGraphs(
|
|
510
|
+
result,
|
|
511
|
+
simulationSpiceString
|
|
512
|
+
);
|
|
361
513
|
return {
|
|
362
|
-
simulationResultCircuitJson:
|
|
514
|
+
simulationResultCircuitJson: simulationGraphsToCircuitJson(
|
|
363
515
|
graphs,
|
|
364
516
|
simulationSpiceString
|
|
365
517
|
)
|
|
@@ -374,7 +526,9 @@ var index_default = createNgspiceSpiceEngine;
|
|
|
374
526
|
export {
|
|
375
527
|
createNgspiceSpiceEngine,
|
|
376
528
|
index_default as default,
|
|
529
|
+
eecircuitResultToSimulationGraphs,
|
|
377
530
|
eecircuitResultToVGraphs,
|
|
378
531
|
parseTranParams,
|
|
379
|
-
rewritePspiceCompatibilitySyntax
|
|
532
|
+
rewritePspiceCompatibilitySyntax,
|
|
533
|
+
simulationGraphsToCircuitJson
|
|
380
534
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/ngspice-spice-engine",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "A tscircuit-compatible SPICE engine using ngspice.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@tscircuit/eecircuit-engine": "https://jscdn.tscircuit.com/@tscircuit/eecircuit-engine/1.7.4.tgz",
|
|
21
|
-
"@tscircuit/props": "^0.0.
|
|
21
|
+
"@tscircuit/props": "^0.0.551",
|
|
22
22
|
"bun-match-svg": "^0.0.14",
|
|
23
|
-
"circuit-json": "^0.0.
|
|
24
|
-
"circuit-to-svg": "^0.0.
|
|
23
|
+
"circuit-json": "^0.0.437",
|
|
24
|
+
"circuit-to-svg": "^0.0.357",
|
|
25
25
|
"format-si-unit": "^0.0.7",
|
|
26
26
|
"@biomejs/biome": "^2.2.7",
|
|
27
27
|
"@types/bun": "latest",
|