@tscircuit/ngspice-spice-engine 0.0.16 → 0.0.18

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