circuit-json-to-spice 0.0.25 → 0.0.27

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.
@@ -3,6 +3,7 @@ import { SpiceComponent } from "./spice-classes/SpiceComponent"
3
3
  import { ResistorCommand } from "./spice-commands/ResistorCommand"
4
4
  import { CapacitorCommand } from "./spice-commands/CapacitorCommand"
5
5
  import { VoltageSourceCommand } from "./spice-commands/VoltageSourceCommand"
6
+ import { BJTCommand } from "./spice-commands/BJTCommand"
6
7
  import { DiodeCommand } from "./spice-commands/DiodeCommand"
7
8
  import { InductorCommand } from "./spice-commands/InductorCommand"
8
9
  import { VoltageControlledSwitchCommand } from "./spice-commands/VoltageControlledSwitchCommand"
@@ -119,12 +120,23 @@ export function circuitJsonToSpice(
119
120
  if (simulationProbes.length > 0) {
120
121
  for (const probe of simulationProbes) {
121
122
  if (!probe.name) continue
123
+
124
+ if (
125
+ probe.reference_input_source_port_id ||
126
+ probe.reference_input_source_net_id
127
+ ) {
128
+ continue
129
+ }
130
+
122
131
  let net: string | undefined | null
123
- if (probe.source_port_id) {
124
- net = connMap.getNetConnectedToId(probe.source_port_id)
125
- } else if (probe.source_net_id) {
132
+ const signal_port_id = probe.signal_input_source_port_id
133
+ const signal_net_id = probe.signal_input_source_net_id
134
+
135
+ if (signal_port_id) {
136
+ net = connMap.getNetConnectedToId(signal_port_id)
137
+ } else if (signal_net_id) {
126
138
  const trace = sourceTraces.find((t) =>
127
- t.connected_source_net_ids.includes(probe.source_net_id!),
139
+ t.connected_source_net_ids.includes(signal_net_id!),
128
140
  )
129
141
  if (trace && trace.connected_source_port_ids.length > 0) {
130
142
  const portId = trace.connected_source_port_ids[0]
@@ -136,10 +148,10 @@ export function circuitJsonToSpice(
136
148
  if (!netToNodeName.has(net)) {
137
149
  netToNodeName.set(net, probe.name)
138
150
  }
139
- } else if (probe.source_port_id && probe.name) {
151
+ } else if (signal_port_id && probe.name) {
140
152
  // It's a floating port with a probe, so we map it directly. This port
141
153
  // will now be skipped in the second-pass for unconnected ports.
142
- nodeMap.set(probe.source_port_id, probe.name)
154
+ nodeMap.set(signal_port_id, probe.name)
143
155
  }
144
156
  }
145
157
  }
@@ -368,6 +380,59 @@ export function circuitJsonToSpice(
368
380
  }
369
381
  break
370
382
  }
383
+ case "simple_transistor": {
384
+ if ("name" in component) {
385
+ const collectorPort = componentPorts.find(
386
+ (p) =>
387
+ p.name?.toLowerCase() === "collector" ||
388
+ p.port_hints?.includes("collector"),
389
+ )
390
+ const basePort = componentPorts.find(
391
+ (p) =>
392
+ p.name?.toLowerCase() === "base" ||
393
+ p.port_hints?.includes("base"),
394
+ )
395
+ const emitterPort = componentPorts.find(
396
+ (p) =>
397
+ p.name?.toLowerCase() === "emitter" ||
398
+ p.port_hints?.includes("emitter"),
399
+ )
400
+
401
+ if (!collectorPort || !basePort || !emitterPort) {
402
+ throw new Error(
403
+ `Transistor ${component.name} is missing required ports (collector, base, emitter)`,
404
+ )
405
+ }
406
+
407
+ const collectorNode =
408
+ nodeMap.get(collectorPort.source_port_id) || "0"
409
+ const baseNode = nodeMap.get(basePort.source_port_id) || "0"
410
+ const emitterNode = nodeMap.get(emitterPort.source_port_id) || "0"
411
+
412
+ const transistor_type = (component as any).transistor_type ?? "npn"
413
+ const modelName = transistor_type.toUpperCase()
414
+ if (!netlist.models.has(modelName)) {
415
+ netlist.models.set(
416
+ modelName,
417
+ `.MODEL ${modelName} ${transistor_type.toUpperCase()}`,
418
+ )
419
+ }
420
+
421
+ const bjtCmd = new BJTCommand({
422
+ name: component.name,
423
+ collector: collectorNode,
424
+ base: baseNode,
425
+ emitter: emitterNode,
426
+ model: modelName,
427
+ })
428
+ spiceComponent = new SpiceComponent(component.name, bjtCmd, [
429
+ collectorNode,
430
+ baseNode,
431
+ emitterNode,
432
+ ])
433
+ }
434
+ break
435
+ }
371
436
  }
372
437
 
373
438
  if (spiceComponent) {
@@ -486,22 +551,46 @@ export function circuitJsonToSpice(
486
551
  if (simulationProbes.length > 0) {
487
552
  const nodesToProbe = new Set<string>()
488
553
 
554
+ const getPortIdFromNetId = (netId: string) => {
555
+ const trace = sourceTraces.find((t) =>
556
+ t.connected_source_net_ids.includes(netId),
557
+ )
558
+ return trace?.connected_source_port_ids[0]
559
+ }
560
+
489
561
  for (const probe of simulationProbes) {
490
- let nodeName: string | undefined
491
- if (probe.source_port_id) {
492
- nodeName = nodeMap.get(probe.source_port_id)
493
- } else if (probe.source_net_id) {
494
- const trace = sourceTraces.find((t) =>
495
- t.connected_source_net_ids.includes(probe.source_net_id!),
496
- )
497
- if (trace && trace.connected_source_port_ids.length > 0) {
498
- const portId = trace.connected_source_port_ids[0]
499
- nodeName = nodeMap.get(portId)
562
+ let signalPortId = probe.signal_input_source_port_id
563
+ if (!signalPortId) {
564
+ const signalNetId = probe.signal_input_source_net_id
565
+ if (signalNetId) {
566
+ signalPortId = getPortIdFromNetId(signalNetId)
500
567
  }
501
568
  }
502
569
 
503
- if (nodeName && nodeName !== "0") {
504
- nodesToProbe.add(`V(${nodeName})`)
570
+ if (!signalPortId) continue
571
+
572
+ const signalNodeName = nodeMap.get(signalPortId)
573
+ if (!signalNodeName) continue
574
+
575
+ let referencePortId = probe.reference_input_source_port_id
576
+ if (!referencePortId && probe.reference_input_source_net_id) {
577
+ referencePortId = getPortIdFromNetId(
578
+ probe.reference_input_source_net_id,
579
+ )
580
+ }
581
+
582
+ if (referencePortId) {
583
+ const referenceNodeName = nodeMap.get(referencePortId)
584
+ if (referenceNodeName && referenceNodeName !== "0") {
585
+ nodesToProbe.add(`V(${signalNodeName},${referenceNodeName})`)
586
+ } else if (signalNodeName !== "0") {
587
+ nodesToProbe.add(`V(${signalNodeName})`)
588
+ }
589
+ } else {
590
+ // Single-ended probe
591
+ if (signalNodeName !== "0") {
592
+ nodesToProbe.add(`V(${signalNodeName})`)
593
+ }
505
594
  }
506
595
  }
507
596
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "circuit-json-to-spice",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.25",
4
+ "version": "0.0.27",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "tsup-node ./lib/index.ts --dts --format esm --sourcemap inline -d dist",
@@ -16,9 +16,9 @@
16
16
  "@tscircuit/circuit-json-util": "^0.0.72",
17
17
  "@types/bun": "^1.2.15",
18
18
  "bun-match-svg": "^0.0.13",
19
- "circuit-json": "^0.0.309",
19
+ "circuit-json": "^0.0.322",
20
20
  "eecircuit-engine": "^1.5.2",
21
- "tscircuit": "^0.0.900",
21
+ "tscircuit": "^0.0.936",
22
22
  "tsup": "^8.4.0"
23
23
  },
24
24
  "peerDependencies": {