@tscircuit/ngspice-spice-engine 0.0.18 → 0.0.20

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
1
  import { SpiceEngine } from '@tscircuit/props';
2
- import { SimulationTransientVoltageGraph, SimulationTransientCurrentGraph } from 'circuit-json';
2
+ import { SimulationAcSweepVoltageGraph, SimulationAnalysisResult } from 'circuit-json';
3
3
 
4
4
  interface TranParams {
5
5
  tstep?: number;
@@ -10,6 +10,18 @@ interface TranParams {
10
10
  }
11
11
  declare const parseTranParams: (spiceString: string) => TranParams | null;
12
12
 
13
+ type SimulationAnalysis = {
14
+ type: "transient";
15
+ } | {
16
+ type: "dc_operating_point";
17
+ } | {
18
+ type: "dc_sweep";
19
+ sweepUnit: "V" | "A";
20
+ } | {
21
+ type: "ac_sweep";
22
+ };
23
+ declare const parseSimulationAnalysis: (spiceString: string) => SimulationAnalysis | null;
24
+
13
25
  declare const rewritePspiceCompatibilitySyntax: (spiceString: string) => string;
14
26
 
15
27
  type ComplexNumber = {
@@ -58,6 +70,7 @@ interface CurrentProbeMetadata {
58
70
  }
59
71
  interface VoltageGraph {
60
72
  graphType: "voltage";
73
+ analysisType: "transient";
61
74
  netName: string;
62
75
  time: number[];
63
76
  voltage: number[];
@@ -65,18 +78,68 @@ interface VoltageGraph {
65
78
  }
66
79
  interface CurrentGraph {
67
80
  graphType: "current";
81
+ analysisType: "transient";
68
82
  currentName: string;
69
83
  time: number[];
70
84
  current: number[];
71
85
  probeMetadata?: CurrentProbeMetadata;
72
86
  }
73
- type SimulationGraph = VoltageGraph | CurrentGraph;
87
+ interface DcOperatingPointVoltageResult {
88
+ graphType: "voltage";
89
+ analysisType: "dc_operating_point";
90
+ netName: string;
91
+ voltage: number;
92
+ probeMetadata?: VoltageProbeMetadata;
93
+ }
94
+ interface DcOperatingPointCurrentResult {
95
+ graphType: "current";
96
+ analysisType: "dc_operating_point";
97
+ currentName: string;
98
+ current: number;
99
+ probeMetadata?: CurrentProbeMetadata;
100
+ }
101
+ interface DcSweepVoltageGraph {
102
+ graphType: "voltage";
103
+ analysisType: "dc_sweep";
104
+ netName: string;
105
+ sweepValues: number[];
106
+ sweepUnit: "V" | "A";
107
+ voltage: number[];
108
+ probeMetadata?: VoltageProbeMetadata;
109
+ }
110
+ interface DcSweepCurrentGraph {
111
+ graphType: "current";
112
+ analysisType: "dc_sweep";
113
+ currentName: string;
114
+ sweepValues: number[];
115
+ sweepUnit: "V" | "A";
116
+ current: number[];
117
+ probeMetadata?: CurrentProbeMetadata;
118
+ }
119
+ type ComplexSample = SimulationAcSweepVoltageGraph["complex_voltages"][number];
120
+ interface AcSweepVoltageGraph {
121
+ graphType: "voltage";
122
+ analysisType: "ac_sweep";
123
+ netName: string;
124
+ frequenciesHz: number[];
125
+ complexVoltages: ComplexSample[];
126
+ probeMetadata?: VoltageProbeMetadata;
127
+ }
128
+ interface AcSweepCurrentGraph {
129
+ graphType: "current";
130
+ analysisType: "ac_sweep";
131
+ currentName: string;
132
+ frequenciesHz: number[];
133
+ complexCurrents: ComplexSample[];
134
+ probeMetadata?: CurrentProbeMetadata;
135
+ }
136
+ type SimulationGraph = VoltageGraph | CurrentGraph | DcOperatingPointVoltageResult | DcOperatingPointCurrentResult | DcSweepVoltageGraph | DcSweepCurrentGraph | AcSweepVoltageGraph | AcSweepCurrentGraph;
74
137
 
75
138
  declare const eecircuitResultToSimulationGraphs: (result: ResultType, spiceString: string) => SimulationGraph[];
76
139
  declare const eecircuitResultToVGraphs: (result: ResultType, spiceString: string) => VoltageGraph[];
77
140
 
78
- declare const simulationGraphsToCircuitJson: (graphs: SimulationGraph[], spiceString: string) => Array<SimulationTransientVoltageGraph | SimulationTransientCurrentGraph>;
141
+ declare const simulationGraphsToCircuitJson: (graphs: SimulationGraph[], spiceString: string) => SimulationAnalysisResult[];
79
142
 
80
143
  declare const createNgspiceSpiceEngine: () => Promise<SpiceEngine>;
81
144
 
82
- export { type TranParams, createNgspiceSpiceEngine, createNgspiceSpiceEngine as default, eecircuitResultToSimulationGraphs, eecircuitResultToVGraphs, parseTranParams, rewritePspiceCompatibilitySyntax, simulationGraphsToCircuitJson };
145
+ export { type SimulationAnalysis, type TranParams, createNgspiceSpiceEngine, createNgspiceSpiceEngine as default, eecircuitResultToSimulationGraphs, eecircuitResultToVGraphs, parseSimulationAnalysis, parseTranParams, rewritePspiceCompatibilitySyntax, simulationGraphsToCircuitJson };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // lib/import-eecircuit-engine.ts
2
- var EECIRCUIT_ENGINE_URL = "https://jscdn.tscircuit.com/@tscircuit/eecircuit-engine/1.7.4/+esm";
2
+ var EECIRCUIT_ENGINE_URL = "https://jscdn.tscircuit.com/@tscircuit/eecircuit-engine/1.7.6/+esm";
3
3
  var modulePromise = null;
4
4
  var importEecircuitEngine = async () => {
5
5
  if (!modulePromise) {
@@ -20,6 +20,7 @@ var importEecircuitEngine = async () => {
20
20
  };
21
21
 
22
22
  // lib/parse-tran-params.ts
23
+ import { parseSpiceNetlist, Tran } from "spicets";
23
24
  var SUFFIX_MULTIPLIERS = {
24
25
  t: 1e12,
25
26
  g: 1e9,
@@ -57,51 +58,33 @@ var parseNumericToken = (token) => {
57
58
  return base * multiplier;
58
59
  };
59
60
  var parseTranParams = (spiceString) => {
60
- const lines = spiceString.split(/\r?\n/);
61
- for (const rawLine of lines) {
62
- const line = rawLine.trim();
63
- if (!line || line.startsWith("*")) {
64
- continue;
65
- }
66
- if (!line.toLowerCase().startsWith(".tran")) {
67
- continue;
68
- }
69
- const [withoutComments = ""] = line.split(";");
70
- const tokens = withoutComments.split(/\s+/).filter(Boolean);
71
- if (tokens.length <= 1) {
72
- return {};
73
- }
74
- const values = [];
75
- let uic = false;
76
- for (const token of tokens.slice(1)) {
77
- if (token.toLowerCase() === "uic") {
78
- uic = true;
79
- continue;
80
- }
81
- const value = parseNumericToken(token);
82
- if (value !== void 0) {
83
- values.push(value);
84
- }
85
- }
86
- const params = {};
87
- if (values[0] !== void 0) {
88
- params.tstep = values[0];
89
- }
90
- if (values[1] !== void 0) {
91
- params.tstop = values[1];
92
- }
93
- if (values[2] !== void 0) {
94
- params.tstart = values[2];
95
- }
96
- if (values[3] !== void 0) {
97
- params.tmax = values[3];
98
- }
99
- if (uic) {
100
- params.uic = true;
101
- }
102
- return params;
61
+ const tran = parseSpiceNetlist(spiceString, {
62
+ dialect: "ngspice"
63
+ }).analyses.find((analysis) => analysis instanceof Tran);
64
+ if (!tran) {
65
+ return null;
103
66
  }
104
- return null;
67
+ const params = {};
68
+ const tstep = tran.step ? parseNumericToken(tran.step.raw) : void 0;
69
+ const tstop = parseNumericToken(tran.stop.raw);
70
+ const tstart = tran.start ? parseNumericToken(tran.start.raw) : void 0;
71
+ const tmax = tran.maxStep ? parseNumericToken(tran.maxStep.raw) : void 0;
72
+ if (tstep !== void 0) {
73
+ params.tstep = tstep;
74
+ }
75
+ if (tstop !== void 0) {
76
+ params.tstop = tstop;
77
+ }
78
+ if (tstart !== void 0) {
79
+ params.tstart = tstart;
80
+ }
81
+ if (tmax !== void 0) {
82
+ params.tmax = tmax;
83
+ }
84
+ if (tran.uic) {
85
+ params.uic = true;
86
+ }
87
+ return params;
105
88
  };
106
89
 
107
90
  // lib/rewrite-pspice-compatibility-syntax.ts
@@ -170,149 +153,407 @@ var rewritePspiceValueBooleanCarets = (spiceString) => {
170
153
  var rewritePspiceCompatibilitySyntax = (spiceString) => rewritePspiceValueBooleanCarets(rewritePspiceResistorTcPairs(spiceString));
171
154
 
172
155
  // 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()}`;
156
+ var getNetName = (spiceVector) => {
157
+ const differentialVoltageMatch = spiceVector.match(
158
+ /^v\(([^,]+),\s*([^)]+)\)$/i
159
+ );
160
+ if (differentialVoltageMatch?.[1] && differentialVoltageMatch?.[2]) {
161
+ return `${differentialVoltageMatch[1].trim()}-${differentialVoltageMatch[2].trim()}`;
177
162
  }
178
- const match = rawName.match(/^v\((.*)\)$/i);
163
+ const match = spiceVector.match(/^v\((.*)\)$/i);
179
164
  if (!match) {
180
- return rawName;
165
+ return spiceVector;
181
166
  }
182
- return match[1] ?? rawName;
167
+ return match[1] ?? spiceVector;
183
168
  };
184
- var getCurrentName = (rawName) => {
185
- const match = rawName.match(/^i\((.*)\)$/i);
169
+ var getCurrentName = (spiceVector) => {
170
+ const match = spiceVector.match(/^i\((.*)\)$/i);
186
171
  if (!match) {
187
- return rawName;
172
+ return spiceVector;
188
173
  }
189
- return match[1] ?? rawName;
174
+ return match[1] ?? spiceVector;
190
175
  };
191
176
  var createVoltageGraphFromRequestedPlot = ({
192
- lowerCaseToken,
193
- originalToken,
194
- timeValues,
195
- voltageDataMap,
196
- voltageProbeMetadata
177
+ normalizedSpiceVector,
178
+ originalSpiceVector,
179
+ timeSeconds,
180
+ voltageSamplesBySpiceVector,
181
+ voltageProbeMetadataBySpiceVector
197
182
  }) => {
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));
183
+ if (!normalizedSpiceVector.startsWith("v(")) return null;
184
+ const differentialVoltageMatch = originalSpiceVector.match(
185
+ /^v\(([^,]+),\s*([^)]+)\)$/i
186
+ );
187
+ let voltageSamples;
188
+ if (differentialVoltageMatch?.[1] && differentialVoltageMatch?.[2]) {
189
+ voltageSamples = voltageSamplesBySpiceVector.get(normalizedSpiceVector);
190
+ if (!voltageSamples) {
191
+ const positiveNodeName = differentialVoltageMatch[1].trim();
192
+ const referenceNodeName = differentialVoltageMatch[2].trim();
193
+ const positiveVoltageSamples = voltageSamplesBySpiceVector.get(
194
+ `v(${positiveNodeName.toLowerCase()})`
195
+ );
196
+ const referenceVoltageSamples = voltageSamplesBySpiceVector.get(
197
+ `v(${referenceNodeName.toLowerCase()})`
198
+ );
199
+ if (positiveVoltageSamples && referenceVoltageSamples) {
200
+ voltageSamples = positiveVoltageSamples.map(
201
+ (positiveVoltage, sampleIndex) => positiveVoltage - (referenceVoltageSamples[sampleIndex] ?? 0)
202
+ );
210
203
  }
211
204
  }
212
205
  } else {
213
- voltage = voltageDataMap.get(lowerCaseToken);
206
+ voltageSamples = voltageSamplesBySpiceVector.get(normalizedSpiceVector);
214
207
  }
215
- if (!voltage) return null;
216
- const metadata = voltageProbeMetadata.get(lowerCaseToken);
208
+ if (!voltageSamples) return null;
209
+ const probeMetadata = voltageProbeMetadataBySpiceVector.get(
210
+ normalizedSpiceVector
211
+ );
217
212
  const voltageGraph = {
218
213
  graphType: "voltage",
219
- netName: metadata?.name ?? getNetName(originalToken),
220
- time: timeValues,
221
- voltage,
222
- probeMetadata: metadata
214
+ analysisType: "transient",
215
+ netName: probeMetadata?.name ?? getNetName(originalSpiceVector),
216
+ time: timeSeconds,
217
+ voltage: voltageSamples,
218
+ probeMetadata
223
219
  };
224
220
  return voltageGraph;
225
221
  };
226
222
  var createCurrentGraphFromRequestedPlot = ({
227
- lowerCaseToken,
228
- originalToken,
229
- timeValues,
230
- currentDataMap,
231
- currentProbeMetadata
223
+ normalizedSpiceVector,
224
+ originalSpiceVector,
225
+ timeSeconds,
226
+ currentSamplesBySpiceVector,
227
+ currentProbeMetadataBySpiceVector
232
228
  }) => {
233
- if (!lowerCaseToken.startsWith("i(")) return null;
234
- const current = currentDataMap.get(lowerCaseToken);
235
- if (!current) return null;
236
- const metadata = currentProbeMetadata.get(lowerCaseToken);
229
+ if (!normalizedSpiceVector.startsWith("i(")) return null;
230
+ const currentSamples = currentSamplesBySpiceVector.get(normalizedSpiceVector);
231
+ if (!currentSamples) return null;
232
+ const probeMetadata = currentProbeMetadataBySpiceVector.get(
233
+ normalizedSpiceVector
234
+ );
237
235
  const currentGraph = {
238
236
  graphType: "current",
239
- currentName: metadata?.name ?? getCurrentName(originalToken),
240
- time: timeValues,
241
- current,
242
- probeMetadata: metadata
237
+ analysisType: "transient",
238
+ currentName: probeMetadata?.name ?? getCurrentName(originalSpiceVector),
239
+ time: timeSeconds,
240
+ current: currentSamples,
241
+ probeMetadata
243
242
  };
244
243
  return currentGraph;
245
244
  };
246
245
 
247
246
  // lib/extract-probe-metadata.ts
248
- var normalizeSpiceVector = (value) => value.toLowerCase().replace(/\s/g, "");
247
+ var normalizeSpiceVector = (spiceVector) => spiceVector.toLowerCase().replace(/\s/g, "");
249
248
  var extractVoltageProbeMetadata = (spiceString) => {
250
- const metadata = /* @__PURE__ */ new Map();
249
+ const voltageProbeMetadataBySpiceVector = /* @__PURE__ */ new Map();
251
250
  for (const line of spiceString.split(/\r?\n/)) {
252
251
  const match = line.match(/^\s*\*\s*tscircuit_probe\s+(.+)\s*$/);
253
252
  if (!match?.[1]) continue;
254
253
  try {
255
- const parsed = JSON.parse(match[1]);
256
- if (typeof parsed.simulation_voltage_probe_id !== "string" || typeof parsed.spice_vector !== "string" || typeof parsed.source_node_name !== "string") {
254
+ const parsedProbeMetadata = JSON.parse(match[1]);
255
+ if (typeof parsedProbeMetadata !== "object" || parsedProbeMetadata === null || !("simulation_voltage_probe_id" in parsedProbeMetadata) || typeof parsedProbeMetadata.simulation_voltage_probe_id !== "string" || !("spice_vector" in parsedProbeMetadata) || typeof parsedProbeMetadata.spice_vector !== "string" || !("source_node_name" in parsedProbeMetadata) || typeof parsedProbeMetadata.source_node_name !== "string") {
257
256
  continue;
258
257
  }
259
- const normalizedSpiceVector = normalizeSpiceVector(parsed.spice_vector);
258
+ const normalizedSpiceVector = normalizeSpiceVector(
259
+ parsedProbeMetadata.spice_vector
260
+ );
260
261
  const voltageProbeMetadata = {
261
- simulation_voltage_probe_id: parsed.simulation_voltage_probe_id,
262
- name: typeof parsed.name === "string" ? parsed.name : void 0,
263
- spice_vector: parsed.spice_vector,
264
- source_node_name: parsed.source_node_name,
265
- reference_node_name: typeof parsed.reference_node_name === "string" ? parsed.reference_node_name : void 0
262
+ simulation_voltage_probe_id: parsedProbeMetadata.simulation_voltage_probe_id,
263
+ name: "name" in parsedProbeMetadata && typeof parsedProbeMetadata.name === "string" ? parsedProbeMetadata.name : void 0,
264
+ spice_vector: parsedProbeMetadata.spice_vector,
265
+ source_node_name: parsedProbeMetadata.source_node_name,
266
+ reference_node_name: "reference_node_name" in parsedProbeMetadata && typeof parsedProbeMetadata.reference_node_name === "string" ? parsedProbeMetadata.reference_node_name : void 0
266
267
  };
267
- metadata.set(normalizedSpiceVector, voltageProbeMetadata);
268
+ voltageProbeMetadataBySpiceVector.set(
269
+ normalizedSpiceVector,
270
+ voltageProbeMetadata
271
+ );
268
272
  } catch {
269
273
  }
270
274
  }
271
- return metadata;
275
+ return voltageProbeMetadataBySpiceVector;
272
276
  };
273
277
  var extractCurrentProbeMetadata = (spiceString) => {
274
- const metadata = /* @__PURE__ */ new Map();
278
+ const currentProbeMetadataBySpiceVector = /* @__PURE__ */ new Map();
275
279
  for (const line of spiceString.split(/\r?\n/)) {
276
280
  const match = line.match(/^\s*\*\s*tscircuit_current_probe\s+(.+)\s*$/);
277
281
  if (!match?.[1]) continue;
278
282
  try {
279
- const parsed = JSON.parse(match[1]);
280
- if (typeof parsed.simulation_current_probe_id !== "string" || typeof parsed.spice_vector !== "string") {
283
+ const parsedProbeMetadata = JSON.parse(match[1]);
284
+ if (typeof parsedProbeMetadata !== "object" || parsedProbeMetadata === null || !("simulation_current_probe_id" in parsedProbeMetadata) || typeof parsedProbeMetadata.simulation_current_probe_id !== "string" || !("spice_vector" in parsedProbeMetadata) || typeof parsedProbeMetadata.spice_vector !== "string") {
281
285
  continue;
282
286
  }
283
- const normalizedSpiceVector = normalizeSpiceVector(parsed.spice_vector);
287
+ const normalizedSpiceVector = normalizeSpiceVector(
288
+ parsedProbeMetadata.spice_vector
289
+ );
284
290
  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
291
+ simulation_current_probe_id: parsedProbeMetadata.simulation_current_probe_id,
292
+ name: "name" in parsedProbeMetadata && typeof parsedProbeMetadata.name === "string" ? parsedProbeMetadata.name : void 0,
293
+ spice_vector: parsedProbeMetadata.spice_vector,
294
+ source_component_id: "source_component_id" in parsedProbeMetadata && typeof parsedProbeMetadata.source_component_id === "string" ? parsedProbeMetadata.source_component_id : void 0,
295
+ source_trace_id: "source_trace_id" in parsedProbeMetadata && typeof parsedProbeMetadata.source_trace_id === "string" ? parsedProbeMetadata.source_trace_id : void 0
290
296
  };
291
- metadata.set(normalizedSpiceVector, currentProbeMetadata);
297
+ currentProbeMetadataBySpiceVector.set(
298
+ normalizedSpiceVector,
299
+ currentProbeMetadata
300
+ );
292
301
  } catch {
293
302
  }
294
303
  }
295
- return metadata;
304
+ return currentProbeMetadataBySpiceVector;
296
305
  };
297
306
 
298
307
  // lib/extract-requested-plots.ts
308
+ import { Print, parseSpiceNetlist as parseSpiceNetlist2 } from "spicets";
299
309
  var extractRequestedPlots = (spiceString) => {
300
- const match = spiceString.match(/\.print\s+tran\s+(.*)/i);
301
- if (!match?.[1]) {
310
+ const supportedAnalyses = /* @__PURE__ */ new Set(["tran", "op", "dc", "ac"]);
311
+ const print = parseSpiceNetlist2(spiceString, {
312
+ dialect: "ngspice"
313
+ }).directives.find(
314
+ (directive) => directive instanceof Print && supportedAnalyses.has(directive.analysis?.toLowerCase() ?? "")
315
+ );
316
+ if (!(print instanceof Print)) {
302
317
  return null;
303
318
  }
304
- const tokens = match[1].match(/[VI]\s*\([^)]+\)/gi);
319
+ const tokens = print.getString().match(/[VI]\s*\([^)]+\)/gi);
305
320
  if (!tokens) {
306
321
  return null;
307
322
  }
308
- const plotMap = /* @__PURE__ */ new Map();
323
+ const requestedPlotByNormalizedSpiceVector = /* @__PURE__ */ new Map();
309
324
  for (const token of tokens) {
310
- const lowerCaseToken = token.toLowerCase().replace(/\s/g, "");
311
- if (!plotMap.has(lowerCaseToken)) {
312
- plotMap.set(lowerCaseToken, token);
325
+ const normalizedSpiceVector = token.toLowerCase().replace(/\s/g, "");
326
+ if (!requestedPlotByNormalizedSpiceVector.has(normalizedSpiceVector)) {
327
+ requestedPlotByNormalizedSpiceVector.set(normalizedSpiceVector, token);
328
+ }
329
+ }
330
+ return requestedPlotByNormalizedSpiceVector;
331
+ };
332
+
333
+ // lib/non-transient-result-helpers.ts
334
+ var getRequestedPlotByNormalizedSpiceVector = ({
335
+ spiceString,
336
+ simulationOutputs
337
+ }) => {
338
+ const requestedPlotByNormalizedSpiceVector = extractRequestedPlots(spiceString);
339
+ if (requestedPlotByNormalizedSpiceVector) {
340
+ return requestedPlotByNormalizedSpiceVector;
341
+ }
342
+ return new Map(
343
+ simulationOutputs.filter(
344
+ (simulationOutput) => simulationOutput.type === "voltage" || simulationOutput.type === "current"
345
+ ).map((simulationOutput) => [
346
+ normalizeSpiceVector(simulationOutput.name),
347
+ simulationOutput.name
348
+ ])
349
+ );
350
+ };
351
+ var getRealSampleMaps = (simulationOutputs) => {
352
+ const voltageSamplesBySpiceVector = new Map(
353
+ simulationOutputs.filter((simulationOutput) => simulationOutput.type === "voltage").map((simulationOutput) => [
354
+ normalizeSpiceVector(simulationOutput.name),
355
+ simulationOutput.values
356
+ ])
357
+ );
358
+ const currentSamplesBySpiceVector = new Map(
359
+ simulationOutputs.filter((simulationOutput) => simulationOutput.type === "current").map((simulationOutput) => [
360
+ normalizeSpiceVector(simulationOutput.name),
361
+ simulationOutput.values
362
+ ])
363
+ );
364
+ return { voltageSamplesBySpiceVector, currentSamplesBySpiceVector };
365
+ };
366
+ var getComplexSampleMaps = (simulationOutputs) => {
367
+ const voltageSamplesBySpiceVector = new Map(
368
+ simulationOutputs.filter((simulationOutput) => simulationOutput.type === "voltage").map((simulationOutput) => [
369
+ normalizeSpiceVector(simulationOutput.name),
370
+ simulationOutput.values
371
+ ])
372
+ );
373
+ const currentSamplesBySpiceVector = new Map(
374
+ simulationOutputs.filter((simulationOutput) => simulationOutput.type === "current").map((simulationOutput) => [
375
+ normalizeSpiceVector(simulationOutput.name),
376
+ simulationOutput.values
377
+ ])
378
+ );
379
+ return { voltageSamplesBySpiceVector, currentSamplesBySpiceVector };
380
+ };
381
+ var getRealVoltageSamples = ({
382
+ normalizedSpiceVector,
383
+ originalSpiceVector,
384
+ voltageSamplesBySpiceVector
385
+ }) => {
386
+ const directVoltageSamples = voltageSamplesBySpiceVector.get(
387
+ normalizedSpiceVector
388
+ );
389
+ if (directVoltageSamples) return directVoltageSamples;
390
+ const differentialVoltageMatch = originalSpiceVector.match(
391
+ /^v\(([^,]+),\s*([^)]+)\)$/i
392
+ );
393
+ if (!differentialVoltageMatch?.[1] || !differentialVoltageMatch[2]) {
394
+ return void 0;
395
+ }
396
+ const positiveVoltageSamples = voltageSamplesBySpiceVector.get(
397
+ normalizeSpiceVector(`v(${differentialVoltageMatch[1]})`)
398
+ );
399
+ const negativeVoltageSamples = voltageSamplesBySpiceVector.get(
400
+ normalizeSpiceVector(`v(${differentialVoltageMatch[2]})`)
401
+ );
402
+ if (!positiveVoltageSamples || !negativeVoltageSamples) return void 0;
403
+ return positiveVoltageSamples.map(
404
+ (positiveVoltage, sampleIndex) => positiveVoltage - (negativeVoltageSamples[sampleIndex] ?? 0)
405
+ );
406
+ };
407
+ var getComplexVoltageSamples = ({
408
+ normalizedSpiceVector,
409
+ originalSpiceVector,
410
+ voltageSamplesBySpiceVector
411
+ }) => {
412
+ const directVoltageSamples = voltageSamplesBySpiceVector.get(
413
+ normalizedSpiceVector
414
+ );
415
+ if (directVoltageSamples) return directVoltageSamples;
416
+ const differentialVoltageMatch = originalSpiceVector.match(
417
+ /^v\(([^,]+),\s*([^)]+)\)$/i
418
+ );
419
+ if (!differentialVoltageMatch?.[1] || !differentialVoltageMatch[2]) {
420
+ return void 0;
421
+ }
422
+ const positiveVoltageSamples = voltageSamplesBySpiceVector.get(
423
+ normalizeSpiceVector(`v(${differentialVoltageMatch[1]})`)
424
+ );
425
+ const negativeVoltageSamples = voltageSamplesBySpiceVector.get(
426
+ normalizeSpiceVector(`v(${differentialVoltageMatch[2]})`)
427
+ );
428
+ if (!positiveVoltageSamples || !negativeVoltageSamples) return void 0;
429
+ return positiveVoltageSamples.map((positiveVoltage, sampleIndex) => ({
430
+ real: positiveVoltage.real - (negativeVoltageSamples[sampleIndex]?.real ?? 0),
431
+ img: positiveVoltage.img - (negativeVoltageSamples[sampleIndex]?.img ?? 0)
432
+ }));
433
+ };
434
+ var toCircuitJsonComplexSamples = (complexSamples) => complexSamples.map(({ real, img }) => ({ re: real, im: img }));
435
+
436
+ // lib/ac-sweep-result-to-graphs.ts
437
+ var acSweepResultToGraphs = ({
438
+ eecircuitResult,
439
+ spiceString
440
+ }) => {
441
+ const frequencyOutput = eecircuitResult.data.find(
442
+ (simulationOutput) => simulationOutput.type === "frequency"
443
+ );
444
+ if (!frequencyOutput) return [];
445
+ const simulationOutputs = eecircuitResult.data.filter(
446
+ (simulationOutput) => simulationOutput !== frequencyOutput
447
+ );
448
+ const { voltageSamplesBySpiceVector, currentSamplesBySpiceVector } = getComplexSampleMaps(simulationOutputs);
449
+ const frequenciesHz = frequencyOutput.values.map(({ real }) => real);
450
+ const voltageProbeMetadataBySpiceVector = extractVoltageProbeMetadata(spiceString);
451
+ const currentProbeMetadataBySpiceVector = extractCurrentProbeMetadata(spiceString);
452
+ const simulationGraphs = [];
453
+ for (const [
454
+ normalizedSpiceVector,
455
+ originalSpiceVector
456
+ ] of getRequestedPlotByNormalizedSpiceVector({
457
+ spiceString,
458
+ simulationOutputs
459
+ })) {
460
+ if (normalizedSpiceVector.startsWith("v(")) {
461
+ const complexVoltageSamples = getComplexVoltageSamples({
462
+ normalizedSpiceVector,
463
+ originalSpiceVector,
464
+ voltageSamplesBySpiceVector
465
+ });
466
+ if (!complexVoltageSamples) continue;
467
+ const probeMetadata2 = voltageProbeMetadataBySpiceVector.get(
468
+ normalizedSpiceVector
469
+ );
470
+ simulationGraphs.push({
471
+ graphType: "voltage",
472
+ analysisType: "ac_sweep",
473
+ netName: probeMetadata2?.name ?? getNetName(originalSpiceVector),
474
+ frequenciesHz,
475
+ complexVoltages: toCircuitJsonComplexSamples(complexVoltageSamples),
476
+ probeMetadata: probeMetadata2
477
+ });
478
+ continue;
313
479
  }
480
+ const complexCurrentSamples = currentSamplesBySpiceVector.get(
481
+ normalizedSpiceVector
482
+ );
483
+ if (!complexCurrentSamples) continue;
484
+ const probeMetadata = currentProbeMetadataBySpiceVector.get(
485
+ normalizedSpiceVector
486
+ );
487
+ simulationGraphs.push({
488
+ graphType: "current",
489
+ analysisType: "ac_sweep",
490
+ currentName: probeMetadata?.name ?? getCurrentName(originalSpiceVector),
491
+ frequenciesHz,
492
+ complexCurrents: toCircuitJsonComplexSamples(complexCurrentSamples),
493
+ probeMetadata
494
+ });
314
495
  }
315
- return plotMap;
496
+ return simulationGraphs;
497
+ };
498
+
499
+ // lib/dc-sweep-result-to-graphs.ts
500
+ var dcSweepResultToGraphs = ({
501
+ eecircuitResult,
502
+ spiceString,
503
+ sweepUnit
504
+ }) => {
505
+ const [sweepCoordinateOutput, ...simulationOutputs] = eecircuitResult.data;
506
+ if (!sweepCoordinateOutput) return [];
507
+ const { voltageSamplesBySpiceVector, currentSamplesBySpiceVector } = getRealSampleMaps(simulationOutputs);
508
+ const voltageProbeMetadataBySpiceVector = extractVoltageProbeMetadata(spiceString);
509
+ const currentProbeMetadataBySpiceVector = extractCurrentProbeMetadata(spiceString);
510
+ const simulationGraphs = [];
511
+ for (const [
512
+ normalizedSpiceVector,
513
+ originalSpiceVector
514
+ ] of getRequestedPlotByNormalizedSpiceVector({
515
+ spiceString,
516
+ simulationOutputs
517
+ })) {
518
+ if (normalizedSpiceVector.startsWith("v(")) {
519
+ const voltageSamples = getRealVoltageSamples({
520
+ normalizedSpiceVector,
521
+ originalSpiceVector,
522
+ voltageSamplesBySpiceVector
523
+ });
524
+ if (!voltageSamples) continue;
525
+ const probeMetadata2 = voltageProbeMetadataBySpiceVector.get(
526
+ normalizedSpiceVector
527
+ );
528
+ simulationGraphs.push({
529
+ graphType: "voltage",
530
+ analysisType: "dc_sweep",
531
+ netName: probeMetadata2?.name ?? getNetName(originalSpiceVector),
532
+ sweepValues: sweepCoordinateOutput.values,
533
+ sweepUnit,
534
+ voltage: voltageSamples,
535
+ probeMetadata: probeMetadata2
536
+ });
537
+ continue;
538
+ }
539
+ const currentSamples = currentSamplesBySpiceVector.get(
540
+ normalizedSpiceVector
541
+ );
542
+ if (!currentSamples) continue;
543
+ const probeMetadata = currentProbeMetadataBySpiceVector.get(
544
+ normalizedSpiceVector
545
+ );
546
+ simulationGraphs.push({
547
+ graphType: "current",
548
+ analysisType: "dc_sweep",
549
+ currentName: probeMetadata?.name ?? getCurrentName(originalSpiceVector),
550
+ sweepValues: sweepCoordinateOutput.values,
551
+ sweepUnit,
552
+ current: currentSamples,
553
+ probeMetadata
554
+ });
555
+ }
556
+ return simulationGraphs;
316
557
  };
317
558
 
318
559
  // lib/linear-interpolate.ts
@@ -340,77 +581,182 @@ var linearInterpolate = (targetX, xPoints, yPoints) => {
340
581
  return y1 + (y2 - y1) * (targetX - x1) / (x2 - x1);
341
582
  };
342
583
 
584
+ // lib/operating-point-result-to-graphs.ts
585
+ var operatingPointResultToGraphs = ({
586
+ eecircuitResult,
587
+ spiceString
588
+ }) => {
589
+ const simulationOutputs = eecircuitResult.data;
590
+ const { voltageSamplesBySpiceVector, currentSamplesBySpiceVector } = getRealSampleMaps(simulationOutputs);
591
+ const voltageProbeMetadataBySpiceVector = extractVoltageProbeMetadata(spiceString);
592
+ const currentProbeMetadataBySpiceVector = extractCurrentProbeMetadata(spiceString);
593
+ const simulationGraphs = [];
594
+ for (const [
595
+ normalizedSpiceVector,
596
+ originalSpiceVector
597
+ ] of getRequestedPlotByNormalizedSpiceVector({
598
+ spiceString,
599
+ simulationOutputs
600
+ })) {
601
+ if (normalizedSpiceVector.startsWith("v(")) {
602
+ const voltage = getRealVoltageSamples({
603
+ normalizedSpiceVector,
604
+ originalSpiceVector,
605
+ voltageSamplesBySpiceVector
606
+ })?.[0];
607
+ if (voltage === void 0) continue;
608
+ const probeMetadata2 = voltageProbeMetadataBySpiceVector.get(
609
+ normalizedSpiceVector
610
+ );
611
+ simulationGraphs.push({
612
+ graphType: "voltage",
613
+ analysisType: "dc_operating_point",
614
+ netName: probeMetadata2?.name ?? getNetName(originalSpiceVector),
615
+ voltage,
616
+ probeMetadata: probeMetadata2
617
+ });
618
+ continue;
619
+ }
620
+ const current = currentSamplesBySpiceVector.get(normalizedSpiceVector)?.[0];
621
+ if (current === void 0) continue;
622
+ const probeMetadata = currentProbeMetadataBySpiceVector.get(
623
+ normalizedSpiceVector
624
+ );
625
+ simulationGraphs.push({
626
+ graphType: "current",
627
+ analysisType: "dc_operating_point",
628
+ currentName: probeMetadata?.name ?? getCurrentName(originalSpiceVector),
629
+ current,
630
+ probeMetadata
631
+ });
632
+ }
633
+ return simulationGraphs;
634
+ };
635
+
636
+ // lib/parse-simulation-analysis.ts
637
+ import { Ac, Dc, Op, parseSpiceNetlist as parseSpiceNetlist3, Tran as Tran2 } from "spicets";
638
+ var parseSimulationAnalysis = (spiceString) => {
639
+ const analyses = parseSpiceNetlist3(spiceString, {
640
+ dialect: "ngspice"
641
+ }).analyses;
642
+ if (analyses.some((analysis) => analysis instanceof Tran2)) {
643
+ return { type: "transient" };
644
+ }
645
+ if (analyses.some((analysis) => analysis instanceof Op)) {
646
+ return { type: "dc_operating_point" };
647
+ }
648
+ const dcSweep = analyses.find((analysis) => analysis instanceof Dc);
649
+ if (dcSweep) {
650
+ const source = dcSweep.sweeps[0]?.source;
651
+ return {
652
+ type: "dc_sweep",
653
+ sweepUnit: source?.toLowerCase().startsWith("i") ? "A" : "V"
654
+ };
655
+ }
656
+ if (analyses.some((analysis) => analysis instanceof Ac)) {
657
+ return { type: "ac_sweep" };
658
+ }
659
+ return null;
660
+ };
661
+
343
662
  // lib/eecircuit-result-to-simulation-graphs.ts
344
663
  var eecircuitResultToSimulationGraphs = (result, spiceString) => {
664
+ const analysis = parseSimulationAnalysis(spiceString);
665
+ if (analysis?.type === "dc_operating_point") {
666
+ return result.dataType === "real" ? operatingPointResultToGraphs({ eecircuitResult: result, spiceString }) : [];
667
+ }
668
+ if (analysis?.type === "dc_sweep") {
669
+ return result.dataType === "real" ? dcSweepResultToGraphs({
670
+ eecircuitResult: result,
671
+ spiceString,
672
+ sweepUnit: analysis.sweepUnit
673
+ }) : [];
674
+ }
675
+ if (analysis?.type === "ac_sweep") {
676
+ return result.dataType === "complex" ? acSweepResultToGraphs({ eecircuitResult: result, spiceString }) : [];
677
+ }
345
678
  if (!result?.data || result.dataType !== "real") {
346
679
  return [];
347
680
  }
348
- const timeData = result.data.find((item) => item.type === "time");
349
- if (!timeData || !Array.isArray(timeData.values)) {
681
+ const timeOutput = result.data.find(
682
+ (simulationOutput) => simulationOutput.type === "time"
683
+ );
684
+ if (!timeOutput || !Array.isArray(timeOutput.values)) {
350
685
  return [];
351
686
  }
352
- const timeValues = timeData.values;
353
- const voltageDataItems = result.data.filter(
354
- (item) => item.type === "voltage" && Array.isArray(item.values)
687
+ const timeSeconds = timeOutput.values;
688
+ const voltageOutputs = result.data.filter(
689
+ (simulationOutput) => simulationOutput.type === "voltage" && Array.isArray(simulationOutput.values)
355
690
  );
356
- const voltageDataMap = /* @__PURE__ */ new Map();
357
- for (const item of voltageDataItems) {
358
- voltageDataMap.set(item.name.toLowerCase(), item.values);
691
+ const voltageSamplesBySpiceVector = /* @__PURE__ */ new Map();
692
+ for (const voltageOutput of voltageOutputs) {
693
+ voltageSamplesBySpiceVector.set(
694
+ normalizeSpiceVector(voltageOutput.name),
695
+ voltageOutput.values
696
+ );
359
697
  }
360
- const currentDataItems = result.data.filter(
361
- (item) => item.type === "current" && Array.isArray(item.values)
698
+ const currentOutputs = result.data.filter(
699
+ (simulationOutput) => simulationOutput.type === "current" && Array.isArray(simulationOutput.values)
362
700
  );
363
- const currentDataMap = /* @__PURE__ */ new Map();
364
- for (const item of currentDataItems) {
365
- currentDataMap.set(normalizeSpiceVector(item.name), item.values);
366
- }
367
- const requestedPlots = extractRequestedPlots(spiceString);
368
- const voltageProbeMetadata = extractVoltageProbeMetadata(spiceString);
369
- const currentProbeMetadata = extractCurrentProbeMetadata(spiceString);
370
- if (!requestedPlots) {
701
+ const currentSamplesBySpiceVector = /* @__PURE__ */ new Map();
702
+ for (const currentOutput of currentOutputs) {
703
+ currentSamplesBySpiceVector.set(
704
+ normalizeSpiceVector(currentOutput.name),
705
+ currentOutput.values
706
+ );
707
+ }
708
+ const requestedPlotByNormalizedSpiceVector = extractRequestedPlots(spiceString);
709
+ const voltageProbeMetadataBySpiceVector = extractVoltageProbeMetadata(spiceString);
710
+ const currentProbeMetadataBySpiceVector = extractCurrentProbeMetadata(spiceString);
711
+ if (!requestedPlotByNormalizedSpiceVector) {
371
712
  return [
372
- ...voltageDataItems.map((item) => {
373
- const metadata = voltageProbeMetadata.get(
374
- normalizeSpiceVector(item.name)
713
+ ...voltageOutputs.map((voltageOutput) => {
714
+ const probeMetadata = voltageProbeMetadataBySpiceVector.get(
715
+ normalizeSpiceVector(voltageOutput.name)
375
716
  );
376
717
  const voltageGraph = {
377
718
  graphType: "voltage",
378
- netName: metadata?.name ?? getNetName(item.name),
379
- time: timeValues,
380
- voltage: item.values,
381
- probeMetadata: metadata
719
+ analysisType: "transient",
720
+ netName: probeMetadata?.name ?? getNetName(voltageOutput.name),
721
+ time: timeSeconds,
722
+ voltage: voltageOutput.values,
723
+ probeMetadata
382
724
  };
383
725
  return voltageGraph;
384
726
  }),
385
- ...currentDataItems.map((item) => {
386
- const metadata = currentProbeMetadata.get(
387
- normalizeSpiceVector(item.name)
727
+ ...currentOutputs.map((currentOutput) => {
728
+ const probeMetadata = currentProbeMetadataBySpiceVector.get(
729
+ normalizeSpiceVector(currentOutput.name)
388
730
  );
389
731
  const currentGraph = {
390
732
  graphType: "current",
391
- currentName: metadata?.name ?? getCurrentName(item.name),
392
- time: timeValues,
393
- current: item.values,
394
- probeMetadata: metadata
733
+ analysisType: "transient",
734
+ currentName: probeMetadata?.name ?? getCurrentName(currentOutput.name),
735
+ time: timeSeconds,
736
+ current: currentOutput.values,
737
+ probeMetadata
395
738
  };
396
739
  return currentGraph;
397
740
  })
398
741
  ];
399
742
  }
400
743
  const graphs = [];
401
- for (const [lowerCaseToken, originalToken] of requestedPlots.entries()) {
744
+ for (const [
745
+ normalizedSpiceVector,
746
+ originalSpiceVector
747
+ ] of requestedPlotByNormalizedSpiceVector) {
402
748
  const graph = createVoltageGraphFromRequestedPlot({
403
- lowerCaseToken,
404
- originalToken,
405
- timeValues,
406
- voltageDataMap,
407
- voltageProbeMetadata
749
+ normalizedSpiceVector,
750
+ originalSpiceVector,
751
+ timeSeconds,
752
+ voltageSamplesBySpiceVector,
753
+ voltageProbeMetadataBySpiceVector
408
754
  }) ?? createCurrentGraphFromRequestedPlot({
409
- lowerCaseToken,
410
- originalToken,
411
- timeValues,
412
- currentDataMap,
413
- currentProbeMetadata
755
+ normalizedSpiceVector,
756
+ originalSpiceVector,
757
+ timeSeconds,
758
+ currentSamplesBySpiceVector,
759
+ currentProbeMetadataBySpiceVector
414
760
  });
415
761
  if (graph) graphs.push(graph);
416
762
  }
@@ -449,50 +795,123 @@ var eecircuitResultToSimulationGraphs = (result, spiceString) => {
449
795
  };
450
796
  var eecircuitResultToVGraphs = (result, spiceString) => {
451
797
  return eecircuitResultToSimulationGraphs(result, spiceString).filter(
452
- (graph) => graph.graphType === "voltage"
798
+ (graph) => graph.graphType === "voltage" && graph.analysisType === "transient"
453
799
  );
454
800
  };
455
801
 
456
802
  // lib/simulation-graphs-to-circuit-json.ts
803
+ var simulationExperimentId = "placeholder_simulation_experiment_id";
457
804
  var simulationGraphsToCircuitJson = (graphs, spiceString) => {
458
805
  const tranParams = parseTranParams(spiceString);
459
806
  return graphs.map((graph, index) => {
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,
807
+ if (graph.analysisType === "transient") {
808
+ if (graph.graphType === "voltage") {
809
+ const graphIdSource2 = graph.probeMetadata?.simulation_voltage_probe_id ?? `${index}_${graph.netName}`;
810
+ const graphElement2 = {
811
+ type: "simulation_transient_voltage_graph",
812
+ simulation_experiment_id: simulationExperimentId,
813
+ simulation_transient_voltage_graph_id: `simulation_graph_${graphIdSource2}`,
814
+ name: graph.netName,
815
+ voltage_levels: graph.voltage,
816
+ timestamps_ms: graph.time.map((timePoint) => timePoint * 1e3),
817
+ start_time_ms: (tranParams?.tstart ?? 0) * 1e3,
818
+ time_per_step: (tranParams?.tstep ?? 0) * 1e3,
819
+ end_time_ms: (tranParams?.tstop ?? 0) * 1e3,
820
+ source_probe_id: graph.probeMetadata?.simulation_voltage_probe_id,
821
+ source_probe_name: graph.probeMetadata?.name,
822
+ source_node_name: graph.probeMetadata?.source_node_name,
823
+ reference_node_name: graph.probeMetadata?.reference_node_name
824
+ };
825
+ return graphElement2;
826
+ }
827
+ const graphIdSource = graph.probeMetadata?.simulation_current_probe_id ?? `${index}_${graph.currentName}`;
828
+ const graphElement = {
829
+ type: "simulation_transient_current_graph",
830
+ simulation_experiment_id: simulationExperimentId,
831
+ simulation_transient_current_graph_id: `simulation_graph_${graphIdSource}`,
832
+ name: graph.currentName,
833
+ current_levels: graph.current,
468
834
  timestamps_ms: graph.time.map((timePoint) => timePoint * 1e3),
469
835
  start_time_ms: (tranParams?.tstart ?? 0) * 1e3,
470
836
  time_per_step: (tranParams?.tstep ?? 0) * 1e3,
471
837
  end_time_ms: (tranParams?.tstop ?? 0) * 1e3,
472
- source_probe_id: graph.probeMetadata?.simulation_voltage_probe_id,
838
+ source_probe_id: graph.probeMetadata?.simulation_current_probe_id,
473
839
  source_probe_name: graph.probeMetadata?.name,
474
- source_node_name: graph.probeMetadata?.source_node_name,
475
- reference_node_name: graph.probeMetadata?.reference_node_name
840
+ source_component_id: graph.probeMetadata?.source_component_id,
841
+ source_trace_id: graph.probeMetadata?.source_trace_id
842
+ };
843
+ return graphElement;
844
+ }
845
+ if (graph.analysisType === "dc_operating_point") {
846
+ if (graph.graphType === "voltage") {
847
+ const probeId3 = graph.probeMetadata?.simulation_voltage_probe_id ?? `simulation_voltage_probe_${index}_${graph.netName}`;
848
+ return {
849
+ type: "simulation_dc_operating_point_voltage",
850
+ simulation_dc_operating_point_voltage_id: `simulation_dc_operating_point_voltage_${probeId3}`,
851
+ simulation_experiment_id: simulationExperimentId,
852
+ simulation_voltage_probe_id: probeId3,
853
+ voltage: graph.voltage,
854
+ name: graph.netName
855
+ };
856
+ }
857
+ const probeId2 = graph.probeMetadata?.simulation_current_probe_id ?? `simulation_current_probe_${index}_${graph.currentName}`;
858
+ return {
859
+ type: "simulation_dc_operating_point_current",
860
+ simulation_dc_operating_point_current_id: `simulation_dc_operating_point_current_${probeId2}`,
861
+ simulation_experiment_id: simulationExperimentId,
862
+ simulation_current_probe_id: probeId2,
863
+ current: graph.current,
864
+ name: graph.currentName
476
865
  };
477
- return graphElement2;
478
866
  }
479
- const graphIdSource = graph.probeMetadata?.simulation_current_probe_id ?? `${index}_${graph.currentName}`;
480
- const graphElement = {
481
- type: "simulation_transient_current_graph",
482
- simulation_experiment_id: "placeholder_simulation_experiment_id",
483
- simulation_transient_current_graph_id: `simulation_graph_${graphIdSource}`,
484
- name: graph.currentName,
485
- current_levels: graph.current,
486
- timestamps_ms: graph.time.map((timePoint) => timePoint * 1e3),
487
- start_time_ms: (tranParams?.tstart ?? 0) * 1e3,
488
- time_per_step: (tranParams?.tstep ?? 0) * 1e3,
489
- end_time_ms: (tranParams?.tstop ?? 0) * 1e3,
490
- source_probe_id: graph.probeMetadata?.simulation_current_probe_id,
491
- source_probe_name: graph.probeMetadata?.name,
492
- source_component_id: graph.probeMetadata?.source_component_id,
493
- source_trace_id: graph.probeMetadata?.source_trace_id
867
+ if (graph.analysisType === "dc_sweep") {
868
+ if (graph.graphType === "voltage") {
869
+ const probeId3 = graph.probeMetadata?.simulation_voltage_probe_id ?? `simulation_voltage_probe_${index}_${graph.netName}`;
870
+ return {
871
+ type: "simulation_dc_sweep_voltage_graph",
872
+ simulation_dc_sweep_voltage_graph_id: `simulation_dc_sweep_voltage_graph_${probeId3}`,
873
+ simulation_experiment_id: simulationExperimentId,
874
+ simulation_voltage_probe_id: probeId3,
875
+ sweep_values: graph.sweepValues,
876
+ sweep_unit: graph.sweepUnit,
877
+ voltage_levels: graph.voltage,
878
+ name: graph.netName
879
+ };
880
+ }
881
+ const probeId2 = graph.probeMetadata?.simulation_current_probe_id ?? `simulation_current_probe_${index}_${graph.currentName}`;
882
+ return {
883
+ type: "simulation_dc_sweep_current_graph",
884
+ simulation_dc_sweep_current_graph_id: `simulation_dc_sweep_current_graph_${probeId2}`,
885
+ simulation_experiment_id: simulationExperimentId,
886
+ simulation_current_probe_id: probeId2,
887
+ sweep_values: graph.sweepValues,
888
+ sweep_unit: graph.sweepUnit,
889
+ current_levels: graph.current,
890
+ name: graph.currentName
891
+ };
892
+ }
893
+ if (graph.graphType === "voltage") {
894
+ const probeId2 = graph.probeMetadata?.simulation_voltage_probe_id ?? `simulation_voltage_probe_${index}_${graph.netName}`;
895
+ return {
896
+ type: "simulation_ac_sweep_voltage_graph",
897
+ simulation_ac_sweep_voltage_graph_id: `simulation_ac_sweep_voltage_graph_${probeId2}`,
898
+ simulation_experiment_id: simulationExperimentId,
899
+ simulation_voltage_probe_id: probeId2,
900
+ frequencies_hz: graph.frequenciesHz,
901
+ complex_voltages: graph.complexVoltages,
902
+ name: graph.netName
903
+ };
904
+ }
905
+ const probeId = graph.probeMetadata?.simulation_current_probe_id ?? `simulation_current_probe_${index}_${graph.currentName}`;
906
+ return {
907
+ type: "simulation_ac_sweep_current_graph",
908
+ simulation_ac_sweep_current_graph_id: `simulation_ac_sweep_current_graph_${probeId}`,
909
+ simulation_experiment_id: simulationExperimentId,
910
+ simulation_current_probe_id: probeId,
911
+ frequencies_hz: graph.frequenciesHz,
912
+ complex_currents: graph.complexCurrents,
913
+ name: graph.currentName
494
914
  };
495
- return graphElement;
496
915
  });
497
916
  };
498
917
 
@@ -517,13 +936,7 @@ var simulate = async (spiceString) => {
517
936
  const simulation = await getSimulation();
518
937
  const simulationSpiceString = rewritePspiceCompatibilitySyntax(spiceString);
519
938
  simulation.setNetList(simulationSpiceString);
520
- let result;
521
- try {
522
- result = await simulation.runSim();
523
- } catch (error) {
524
- console.error(error);
525
- throw error;
526
- }
939
+ const result = await simulation.runSim();
527
940
  if (!result) {
528
941
  return { simulationResultCircuitJson: [] };
529
942
  }
@@ -549,6 +962,7 @@ export {
549
962
  index_default as default,
550
963
  eecircuitResultToSimulationGraphs,
551
964
  eecircuitResultToVGraphs,
965
+ parseSimulationAnalysis,
552
966
  parseTranParams,
553
967
  rewritePspiceCompatibilitySyntax,
554
968
  simulationGraphsToCircuitJson
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/ngspice-spice-engine",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "description": "A tscircuit-compatible SPICE engine using ngspice.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,19 +17,21 @@
17
17
  "typecheck": "tsc --noEmit"
18
18
  },
19
19
  "devDependencies": {
20
- "@tscircuit/props": "^0.0.551",
20
+ "@tscircuit/props": "^0.0.592",
21
21
  "bun-match-svg": "^0.0.14",
22
- "circuit-json": "^0.0.437",
23
- "circuit-to-svg": "^0.0.357",
22
+ "circuit-json": "^0.0.454",
23
+ "circuit-to-svg": "^0.0.393",
24
24
  "format-si-unit": "^0.0.7",
25
25
  "@biomejs/biome": "^2.2.7",
26
26
  "@types/bun": "latest",
27
+ "spicets": "^0.0.4",
27
28
  "tscircuit": "^0.0.805",
28
29
  "tsup": "^8.5.0"
29
30
  },
30
31
  "peerDependencies": {
31
32
  "typescript": "^5",
32
33
  "circuit-json": "*",
33
- "@tscircuit/props": "*"
34
+ "@tscircuit/props": "*",
35
+ "spicets": "*"
34
36
  }
35
37
  }