@tscircuit/props 0.0.590 → 0.0.592

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.
@@ -0,0 +1,85 @@
1
+ import { frequency } from "circuit-json"
2
+ import { expectTypesMatch } from "lib/typecheck"
3
+ import { z } from "zod"
4
+ import {
5
+ analogAnalysisSimulationBaseProps,
6
+ type AnalogAnalysisSimulationBaseProps,
7
+ } from "./analogsimulation"
8
+
9
+ export interface AnalogAcSweepSimulationProps
10
+ extends AnalogAnalysisSimulationBaseProps {
11
+ /** Frequency spacing used by the AC analysis. */
12
+ sweepType: "linear" | "decade" | "octave"
13
+ /** First positive frequency. Raw numbers are hertz. */
14
+ startFrequency: number | string
15
+ /** Last frequency, which must be greater than startFrequency. Raw numbers are hertz. */
16
+ stopFrequency: number | string
17
+ /** Samples per decade or octave; required for non-linear sweeps. */
18
+ samplesPerInterval?: number
19
+ /** Total samples; required for linear sweeps. */
20
+ sampleCount?: number
21
+ }
22
+
23
+ export const analogAcSweepSimulationProps = z
24
+ .object({
25
+ ...analogAnalysisSimulationBaseProps,
26
+ sweepType: z.enum(["linear", "decade", "octave"]),
27
+ startFrequency: frequency.refine(
28
+ (startFrequencyHz) => startFrequencyHz > 0,
29
+ "startFrequency must be positive",
30
+ ),
31
+ stopFrequency: frequency.refine(
32
+ (stopFrequencyHz) => stopFrequencyHz > 0,
33
+ "stopFrequency must be positive",
34
+ ),
35
+ samplesPerInterval: z.number().int().positive().optional(),
36
+ sampleCount: z.number().int().positive().optional(),
37
+ })
38
+ .superRefine((simulation, context) => {
39
+ if (simulation.stopFrequency <= simulation.startFrequency) {
40
+ context.addIssue({
41
+ code: z.ZodIssueCode.custom,
42
+ path: ["stopFrequency"],
43
+ message: "stopFrequency must be greater than startFrequency",
44
+ })
45
+ }
46
+
47
+ if (simulation.sweepType === "linear") {
48
+ if (simulation.sampleCount === undefined) {
49
+ context.addIssue({
50
+ code: z.ZodIssueCode.custom,
51
+ path: ["sampleCount"],
52
+ message: "sampleCount is required for a linear AC sweep",
53
+ })
54
+ }
55
+ if (simulation.samplesPerInterval !== undefined) {
56
+ context.addIssue({
57
+ code: z.ZodIssueCode.custom,
58
+ path: ["samplesPerInterval"],
59
+ message:
60
+ "samplesPerInterval is only valid for decade or octave sweeps",
61
+ })
62
+ }
63
+ return
64
+ }
65
+
66
+ if (simulation.samplesPerInterval === undefined) {
67
+ context.addIssue({
68
+ code: z.ZodIssueCode.custom,
69
+ path: ["samplesPerInterval"],
70
+ message: "samplesPerInterval is required for decade or octave sweeps",
71
+ })
72
+ }
73
+ if (simulation.sampleCount !== undefined) {
74
+ context.addIssue({
75
+ code: z.ZodIssueCode.custom,
76
+ path: ["sampleCount"],
77
+ message: "sampleCount is only valid for a linear sweep",
78
+ })
79
+ }
80
+ })
81
+
82
+ expectTypesMatch<
83
+ AnalogAcSweepSimulationProps,
84
+ z.input<typeof analogAcSweepSimulationProps>
85
+ >(true)
@@ -0,0 +1,18 @@
1
+ import { expectTypesMatch } from "lib/typecheck"
2
+ import { z } from "zod"
3
+ import {
4
+ analogAnalysisSimulationBaseProps,
5
+ type AnalogAnalysisSimulationBaseProps,
6
+ } from "./analogsimulation"
7
+
8
+ export type AnalogDcOperatingPointSimulationProps =
9
+ AnalogAnalysisSimulationBaseProps
10
+
11
+ export const analogDcOperatingPointSimulationProps = z.object({
12
+ ...analogAnalysisSimulationBaseProps,
13
+ })
14
+
15
+ expectTypesMatch<
16
+ AnalogDcOperatingPointSimulationProps,
17
+ z.input<typeof analogDcOperatingPointSimulationProps>
18
+ >(true)
@@ -0,0 +1,50 @@
1
+ import { current, voltage } from "circuit-json"
2
+ import { expectTypesMatch } from "lib/typecheck"
3
+ import { z } from "zod"
4
+ import {
5
+ analogAnalysisSimulationBaseProps,
6
+ type AnalogAnalysisSimulationBaseProps,
7
+ } from "./analogsimulation"
8
+
9
+ export interface AnalogDcSweepSimulationProps
10
+ extends AnalogAnalysisSimulationBaseProps {
11
+ /** Selector for the independent voltage or current source being swept. */
12
+ sweepSource: string
13
+ /** First source level. Raw numbers use volts or amperes according to the source. */
14
+ sweepStart: number | string
15
+ /** Last source level. Raw numbers use volts or amperes according to the source. */
16
+ sweepStop: number | string
17
+ /** Nonzero increment directed from sweepStart toward sweepStop. */
18
+ sweepStep: number | string
19
+ }
20
+
21
+ const dcSweepQuantity = z.union([voltage, current])
22
+
23
+ export const analogDcSweepSimulationProps = z
24
+ .object({
25
+ ...analogAnalysisSimulationBaseProps,
26
+ sweepSource: z.string().min(1),
27
+ sweepStart: dcSweepQuantity,
28
+ sweepStop: dcSweepQuantity,
29
+ sweepStep: dcSweepQuantity.refine(
30
+ (sweepStep) => sweepStep !== 0,
31
+ "sweepStep must be nonzero",
32
+ ),
33
+ })
34
+ .superRefine((simulation, context) => {
35
+ if (
36
+ Math.sign(simulation.sweepStop - simulation.sweepStart) !==
37
+ Math.sign(simulation.sweepStep)
38
+ ) {
39
+ context.addIssue({
40
+ code: z.ZodIssueCode.custom,
41
+ path: ["sweepStep"],
42
+ message: "sweepStep must move from sweepStart toward sweepStop",
43
+ })
44
+ }
45
+ })
46
+
47
+ expectTypesMatch<
48
+ AnalogDcSweepSimulationProps,
49
+ z.input<typeof analogDcSweepSimulationProps>
50
+ >(true)
@@ -1,6 +1,7 @@
1
1
  import { ms } from "circuit-json"
2
2
  import type { AutocompleteString } from "lib/common/autocomplete"
3
3
  import { expectTypesMatch } from "lib/typecheck"
4
+ import type { ReactNode } from "react"
4
5
  import { z } from "zod"
5
6
 
6
7
  export interface AnalogSimulationProps {
@@ -32,6 +33,27 @@ const spiceOptions = z.object({
32
33
  vntol: z.union([z.number(), z.string()]).optional(),
33
34
  })
34
35
 
36
+ export interface AnalogAnalysisSimulationBaseProps {
37
+ /** Stable identity for the simulation experiment. */
38
+ name?: string
39
+ /** SPICE implementation used to run this analysis. */
40
+ spiceEngine?: AutocompleteString<"spicey" | "ngspice">
41
+ /** Numerical solver settings forwarded to the selected SPICE engine. */
42
+ spiceOptions?: SpiceOptions
43
+ /** Render each probe with an independent vertical graph scale. */
44
+ graphIndependentAxes?: boolean
45
+ /** Optional nested sweep parameter for repeated analysis runs. */
46
+ children?: ReactNode
47
+ }
48
+
49
+ export const analogAnalysisSimulationBaseProps = {
50
+ name: z.string().optional(),
51
+ spiceEngine: spiceEngine.optional(),
52
+ spiceOptions: spiceOptions.optional(),
53
+ graphIndependentAxes: z.boolean().optional(),
54
+ children: z.custom<ReactNode>().optional(),
55
+ }
56
+
35
57
  export const analogSimulationProps = z.object({
36
58
  name: z.string().optional(),
37
59
  simulationType: z
@@ -0,0 +1,213 @@
1
+ import {
2
+ capacitance,
3
+ current,
4
+ inductance,
5
+ resistance,
6
+ voltage,
7
+ } from "circuit-json"
8
+ import { expectTypesMatch } from "lib/typecheck"
9
+ import { z } from "zod"
10
+
11
+ interface AnalogSweepCoordinatesProps {
12
+ /** Stable identity for this sweep parameter. */
13
+ name?: string
14
+ /** Explicit parameter coordinates. Cannot be combined with start/stop/step. */
15
+ values?: Array<number | string>
16
+ /** First generated parameter coordinate. Requires stop and step. */
17
+ start?: number | string
18
+ /** Last generated parameter coordinate. Requires start and step. */
19
+ stop?: number | string
20
+ /** Nonzero parameter increment directed from start toward stop. */
21
+ step?: number | string
22
+ }
23
+
24
+ export interface AnalogResistanceSweepParameterProps
25
+ extends AnalogSweepCoordinatesProps {
26
+ parameterType: "resistance"
27
+ /** Selector for the resistor whose simulation-only resistance is swept. */
28
+ resistorRef: string
29
+ }
30
+
31
+ export interface AnalogCapacitanceSweepParameterProps
32
+ extends AnalogSweepCoordinatesProps {
33
+ parameterType: "capacitance"
34
+ /** Selector for the capacitor whose simulation-only capacitance is swept. */
35
+ capacitorRef: string
36
+ }
37
+
38
+ export interface AnalogInductanceSweepParameterProps
39
+ extends AnalogSweepCoordinatesProps {
40
+ parameterType: "inductance"
41
+ /** Selector for the inductor whose simulation-only inductance is swept. */
42
+ inductorRef: string
43
+ }
44
+
45
+ export interface AnalogVoltageSweepParameterProps
46
+ extends AnalogSweepCoordinatesProps {
47
+ parameterType: "voltage"
48
+ /** Net whose simulation-only voltage is swept. */
49
+ net: string
50
+ }
51
+
52
+ export interface AnalogCurrentSweepParameterProps
53
+ extends AnalogSweepCoordinatesProps {
54
+ parameterType: "current"
55
+ /** Selector for the current source whose simulation-only current is swept. */
56
+ currentSourceRef: string
57
+ }
58
+
59
+ const resistanceSweepQuantity = resistance.pipe(z.number())
60
+ const capacitanceSweepQuantity = capacitance.pipe(z.number())
61
+ const inductanceSweepQuantity = inductance.pipe(z.number())
62
+ const voltageSweepQuantity = voltage.pipe(z.number())
63
+ const currentSweepQuantity = current.pipe(z.number())
64
+
65
+ const createAnalogSweepCoordinateProps = (
66
+ sweepQuantity: z.ZodType<number, z.ZodTypeDef, number | string>,
67
+ ) => ({
68
+ name: z.string().optional(),
69
+ values: z.array(sweepQuantity).min(1).optional(),
70
+ start: sweepQuantity.optional(),
71
+ stop: sweepQuantity.optional(),
72
+ step: sweepQuantity.optional(),
73
+ })
74
+
75
+ export const analogResistanceSweepParameterProps = z
76
+ .object({
77
+ ...createAnalogSweepCoordinateProps(resistanceSweepQuantity),
78
+ parameterType: z.literal("resistance"),
79
+ resistorRef: z.string().min(1),
80
+ })
81
+ .strict()
82
+
83
+ export const analogCapacitanceSweepParameterProps = z
84
+ .object({
85
+ ...createAnalogSweepCoordinateProps(capacitanceSweepQuantity),
86
+ parameterType: z.literal("capacitance"),
87
+ capacitorRef: z.string().min(1),
88
+ })
89
+ .strict()
90
+
91
+ export const analogInductanceSweepParameterProps = z
92
+ .object({
93
+ ...createAnalogSweepCoordinateProps(inductanceSweepQuantity),
94
+ parameterType: z.literal("inductance"),
95
+ inductorRef: z.string().min(1),
96
+ })
97
+ .strict()
98
+
99
+ export const analogVoltageSweepParameterProps = z
100
+ .object({
101
+ ...createAnalogSweepCoordinateProps(voltageSweepQuantity),
102
+ parameterType: z.literal("voltage"),
103
+ net: z.string().min(1),
104
+ })
105
+ .strict()
106
+
107
+ export const analogCurrentSweepParameterProps = z
108
+ .object({
109
+ ...createAnalogSweepCoordinateProps(currentSweepQuantity),
110
+ parameterType: z.literal("current"),
111
+ currentSourceRef: z.string().min(1),
112
+ })
113
+ .strict()
114
+
115
+ interface ParsedAnalogSweepCoordinates {
116
+ values?: number[]
117
+ start?: number
118
+ stop?: number
119
+ step?: number
120
+ }
121
+
122
+ const validateAnalogSweepCoordinates = (
123
+ sweepCoordinates: ParsedAnalogSweepCoordinates,
124
+ context: z.RefinementCtx,
125
+ ) => {
126
+ const hasExplicitSweepCoordinates = sweepCoordinates.values !== undefined
127
+ const rangeCoordinateCount = [
128
+ sweepCoordinates.start,
129
+ sweepCoordinates.stop,
130
+ sweepCoordinates.step,
131
+ ].filter((rangeCoordinate) => rangeCoordinate !== undefined).length
132
+ const hasRangeCoordinates = rangeCoordinateCount > 0
133
+
134
+ if (hasExplicitSweepCoordinates === hasRangeCoordinates) {
135
+ context.addIssue({
136
+ code: z.ZodIssueCode.custom,
137
+ message: "Provide either values or start/stop/step",
138
+ })
139
+ return
140
+ }
141
+
142
+ if (rangeCoordinateCount !== 0 && rangeCoordinateCount !== 3) {
143
+ context.addIssue({
144
+ code: z.ZodIssueCode.custom,
145
+ message: "start, stop, and step must be provided together",
146
+ })
147
+ return
148
+ }
149
+
150
+ if (sweepCoordinates.step === 0) {
151
+ context.addIssue({
152
+ code: z.ZodIssueCode.custom,
153
+ path: ["step"],
154
+ message: "step must be nonzero",
155
+ })
156
+ }
157
+
158
+ if (
159
+ sweepCoordinates.start !== undefined &&
160
+ sweepCoordinates.stop !== undefined &&
161
+ sweepCoordinates.step !== undefined &&
162
+ Math.sign(sweepCoordinates.stop - sweepCoordinates.start) !==
163
+ Math.sign(sweepCoordinates.step)
164
+ ) {
165
+ context.addIssue({
166
+ code: z.ZodIssueCode.custom,
167
+ path: ["step"],
168
+ message: "step must move from start toward stop",
169
+ })
170
+ }
171
+ }
172
+
173
+ export type AnalogSweepParameterProps =
174
+ | AnalogResistanceSweepParameterProps
175
+ | AnalogCapacitanceSweepParameterProps
176
+ | AnalogInductanceSweepParameterProps
177
+ | AnalogVoltageSweepParameterProps
178
+ | AnalogCurrentSweepParameterProps
179
+
180
+ export const analogSweepParameterProps = z
181
+ .discriminatedUnion("parameterType", [
182
+ analogResistanceSweepParameterProps,
183
+ analogCapacitanceSweepParameterProps,
184
+ analogInductanceSweepParameterProps,
185
+ analogVoltageSweepParameterProps,
186
+ analogCurrentSweepParameterProps,
187
+ ])
188
+ .superRefine(validateAnalogSweepCoordinates)
189
+
190
+ expectTypesMatch<
191
+ AnalogResistanceSweepParameterProps,
192
+ z.input<typeof analogResistanceSweepParameterProps>
193
+ >(true)
194
+ expectTypesMatch<
195
+ AnalogCapacitanceSweepParameterProps,
196
+ z.input<typeof analogCapacitanceSweepParameterProps>
197
+ >(true)
198
+ expectTypesMatch<
199
+ AnalogInductanceSweepParameterProps,
200
+ z.input<typeof analogInductanceSweepParameterProps>
201
+ >(true)
202
+ expectTypesMatch<
203
+ AnalogVoltageSweepParameterProps,
204
+ z.input<typeof analogVoltageSweepParameterProps>
205
+ >(true)
206
+ expectTypesMatch<
207
+ AnalogCurrentSweepParameterProps,
208
+ z.input<typeof analogCurrentSweepParameterProps>
209
+ >(true)
210
+ expectTypesMatch<
211
+ AnalogSweepParameterProps,
212
+ z.input<typeof analogSweepParameterProps>
213
+ >(true)
@@ -0,0 +1,47 @@
1
+ import { ms } from "circuit-json"
2
+ import { expectTypesMatch } from "lib/typecheck"
3
+ import { z } from "zod"
4
+ import {
5
+ analogAnalysisSimulationBaseProps,
6
+ type AnalogAnalysisSimulationBaseProps,
7
+ } from "./analogsimulation"
8
+
9
+ export interface AnalogTransientSimulationProps
10
+ extends AnalogAnalysisSimulationBaseProps {
11
+ /** Simulation duration. Raw numbers are milliseconds. Defaults to 10ms. */
12
+ duration?: number | string
13
+ /** Time at which recording starts. Raw numbers are milliseconds. Defaults to 0ms. */
14
+ startTime?: number | string
15
+ /** Maximum simulation timestep. Raw numbers are milliseconds. Defaults to 0.01ms. */
16
+ timePerStep?: number | string
17
+ }
18
+
19
+ const positiveMilliseconds = ms.refine(
20
+ (milliseconds) => milliseconds > 0,
21
+ "Time must be positive",
22
+ )
23
+
24
+ export const analogTransientSimulationProps = z
25
+ .object({
26
+ ...analogAnalysisSimulationBaseProps,
27
+ duration: positiveMilliseconds.default("10ms"),
28
+ startTime: ms.default("0ms"),
29
+ timePerStep: positiveMilliseconds.default("0.01ms"),
30
+ })
31
+ .superRefine((simulation, context) => {
32
+ if (
33
+ simulation.startTime < 0 ||
34
+ simulation.startTime > simulation.duration
35
+ ) {
36
+ context.addIssue({
37
+ code: z.ZodIssueCode.custom,
38
+ path: ["startTime"],
39
+ message: "startTime must be between zero and duration",
40
+ })
41
+ }
42
+ })
43
+
44
+ expectTypesMatch<
45
+ AnalogTransientSimulationProps,
46
+ z.input<typeof analogTransientSimulationProps>
47
+ >(true)
@@ -21,6 +21,10 @@ export interface CurrentSourceProps<PinLabel extends string = string>
21
21
  waveShape?: WaveShape
22
22
  phase?: number | string
23
23
  dutyCycle?: number | string
24
+ /** Small-signal AC magnitude. Raw numbers are amperes. */
25
+ acMagnitude?: number | string
26
+ /** Small-signal AC phase. Raw numbers are degrees. */
27
+ acPhase?: number | string
24
28
  connections?: Connections<CurrentSourcePinLabels>
25
29
  }
26
30
 
@@ -49,6 +53,8 @@ export const currentSourceProps = commonComponentProps.extend({
49
53
  waveShape: z.enum(["sinewave", "square", "triangle", "sawtooth"]).optional(),
50
54
  phase: rotation.optional(),
51
55
  dutyCycle: percentage.optional(),
56
+ acMagnitude: current.optional(),
57
+ acPhase: rotation.optional(),
52
58
  connections: createConnectionsProp(currentSourcePinLabels).optional(),
53
59
  })
54
60
 
@@ -0,0 +1,59 @@
1
+ import { rotation } from "circuit-json"
2
+ import { connectionTarget } from "lib/common/connectionsProp"
3
+ import { distance, type Distance } from "lib/common/distance"
4
+ import { expectTypesMatch } from "lib/typecheck"
5
+ import type { Connections } from "lib/utility-types/connections-and-selectors"
6
+ import { z } from "zod"
7
+
8
+ /**
9
+ * Places a named schematic-symbol representation of an existing physical
10
+ * component. The connection keys are labels exposed by `symbolName`; each
11
+ * value selects the corresponding port on the component referenced by
12
+ * `chipRef`.
13
+ *
14
+ * This is a schematic-only projection, so it accepts only the identity,
15
+ * connection, and schematic placement props it needs.
16
+ */
17
+ export interface SchematicSymbolProps {
18
+ /** Stable name for this representation, such as `A` or `B`. */
19
+ name: string
20
+ /** Optional human-facing name shown in the schematic. */
21
+ displayName?: string
22
+ /** Selector for the physical component represented by this symbol. */
23
+ chipRef?: string
24
+ /** Name of the symbol from the schematic-symbol library. */
25
+ symbolName: string
26
+ /** Maps symbol port labels to physical component port selectors. */
27
+ connections?: Connections
28
+ schX?: Distance
29
+ schY?: Distance
30
+ schRotation?: number | string
31
+ schSectionName?: string
32
+ schSheetName?: string
33
+ }
34
+
35
+ const schematicSymbolConnections = z
36
+ .custom<Connections>()
37
+ .pipe(z.record(z.string(), connectionTarget))
38
+ .refine((value) => Object.keys(value).length > 0, {
39
+ message: "connections must map at least one schematic symbol port",
40
+ })
41
+
42
+ export const schematicSymbolProps = z.object({
43
+ name: z.string().min(1),
44
+ displayName: z.string().optional(),
45
+ chipRef: z.string().min(1).optional(),
46
+ symbolName: z.string().min(1),
47
+ connections: schematicSymbolConnections.optional(),
48
+ schX: distance.optional(),
49
+ schY: distance.optional(),
50
+ schRotation: rotation.optional(),
51
+ schSectionName: z.string().optional(),
52
+ schSheetName: z.string().optional(),
53
+ })
54
+
55
+ export type InferredSchematicSymbolProps = z.input<typeof schematicSymbolProps>
56
+
57
+ expectTypesMatch<SchematicSymbolProps, z.input<typeof schematicSymbolProps>>(
58
+ true,
59
+ )
@@ -27,6 +27,10 @@ export interface VoltageSourceProps<PinLabel extends string = string>
27
27
  fallTime?: number | string
28
28
  pulseWidth?: number | string
29
29
  period?: number | string
30
+ /** Small-signal AC magnitude. Raw numbers are volts. */
31
+ acMagnitude?: number | string
32
+ /** Small-signal AC phase. Raw numbers are degrees. */
33
+ acPhase?: number | string
30
34
  connections?: Connections<VoltageSourcePinLabels>
31
35
  }
32
36
 
@@ -60,6 +64,8 @@ export const voltageSourceProps = commonComponentProps.extend({
60
64
  fallTime: ms.optional(),
61
65
  pulseWidth: ms.optional(),
62
66
  period: ms.optional(),
67
+ acMagnitude: voltage.optional(),
68
+ acPhase: rotation.optional(),
63
69
  connections: createConnectionsProp(voltageSourcePinLabels).optional(),
64
70
  })
65
71
 
package/lib/index.ts CHANGED
@@ -69,6 +69,11 @@ export * from "./components/netlabel"
69
69
  export * from "./components/push-button"
70
70
  export * from "./components/subcircuit"
71
71
  export * from "./components/analogsimulation"
72
+ export * from "./components/analogtransientsimulation"
73
+ export * from "./components/analogdcoperatingpointsimulation"
74
+ export * from "./components/analogdcsweepsimulation"
75
+ export * from "./components/analogacsweepsimulation"
76
+ export * from "./components/analogsweepparameter"
72
77
  export * from "./components/autoroutingphase"
73
78
  export * from "./components/spicemodel"
74
79
  export * from "./manual-edits"
@@ -104,6 +109,7 @@ export * from "./components/ammeter"
104
109
  export * from "./components/schematic-arc"
105
110
  export * from "./components/toolingrail"
106
111
  export * from "./components/schematic-box"
112
+ export * from "./components/schematic-symbol"
107
113
  export * from "./components/schematic-circle"
108
114
  export * from "./components/schematic-rect"
109
115
  export * from "./components/schematic-line"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/props",
3
- "version": "0.0.590",
3
+ "version": "0.0.592",
4
4
  "description": "Props for tscircuit builtin component types",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",