circuitjson-toolkit 1.0.2 → 1.0.10

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,132 @@
1
+ /**
2
+ * Normalizes simulator time-series rows to transient directive timing.
3
+ */
4
+ export class SpiceTimeSeriesNormalizer {
5
+ static #EPSILON = 1e-12
6
+
7
+ /**
8
+ * Resamples graph models onto the transient analysis time grid.
9
+ * @param {object[]} graphs Graph models with time and values arrays.
10
+ * @param {{ tstep?: number, tstop?: number, tstart?: number } | null} tran Transient timing parameters.
11
+ * @returns {object[]}
12
+ */
13
+ static resampleGraphs(graphs, tran) {
14
+ const targetTime = SpiceTimeSeriesNormalizer.#targetTimeValues(tran)
15
+ if (!targetTime) return graphs
16
+
17
+ return graphs.map((graph) => ({
18
+ ...graph,
19
+ time: targetTime,
20
+ values: SpiceTimeSeriesNormalizer.#interpolateValues(
21
+ graph.time,
22
+ graph.values,
23
+ targetTime
24
+ )
25
+ }))
26
+ }
27
+
28
+ /**
29
+ * Builds the target transient time grid in seconds.
30
+ * @param {{ tstep?: number, tstop?: number, tstart?: number } | null} tran Transient timing parameters.
31
+ * @returns {number[] | null}
32
+ */
33
+ static #targetTimeValues(tran) {
34
+ const tstep = Number(tran?.tstep)
35
+ const tstop = Number(tran?.tstop)
36
+ const tstart =
37
+ tran?.tstart === undefined || tran?.tstart === null
38
+ ? 0
39
+ : Number(tran.tstart)
40
+
41
+ if (
42
+ !Number.isFinite(tstep) ||
43
+ !Number.isFinite(tstop) ||
44
+ !Number.isFinite(tstart) ||
45
+ tstep <= 0 ||
46
+ tstop < tstart
47
+ ) {
48
+ return null
49
+ }
50
+
51
+ const times = []
52
+ for (
53
+ let time = tstart;
54
+ time <= tstop + SpiceTimeSeriesNormalizer.#EPSILON;
55
+ time += tstep
56
+ ) {
57
+ times.push(SpiceTimeSeriesNormalizer.#round(time))
58
+ }
59
+
60
+ const lastTime = times.at(-1)
61
+ if (
62
+ lastTime !== undefined &&
63
+ Math.abs(lastTime - tstop) > SpiceTimeSeriesNormalizer.#EPSILON
64
+ ) {
65
+ times.push(SpiceTimeSeriesNormalizer.#round(tstop))
66
+ }
67
+
68
+ return times
69
+ }
70
+
71
+ /**
72
+ * Interpolates source values onto a target time grid.
73
+ * @param {number[]} sourceTime Source timestamps in seconds.
74
+ * @param {number[]} sourceValues Source sample values.
75
+ * @param {number[]} targetTime Target timestamps in seconds.
76
+ * @returns {number[]}
77
+ */
78
+ static #interpolateValues(sourceTime, sourceValues, targetTime) {
79
+ if (!sourceTime.length || !sourceValues.length) return []
80
+
81
+ return targetTime.map((time) =>
82
+ SpiceTimeSeriesNormalizer.#interpolateAt(
83
+ sourceTime,
84
+ sourceValues,
85
+ time
86
+ )
87
+ )
88
+ }
89
+
90
+ /**
91
+ * Interpolates one value at a target timestamp.
92
+ * @param {number[]} sourceTime Source timestamps in seconds.
93
+ * @param {number[]} sourceValues Source sample values.
94
+ * @param {number} targetTime Target timestamp in seconds.
95
+ * @returns {number}
96
+ */
97
+ static #interpolateAt(sourceTime, sourceValues, targetTime) {
98
+ if (targetTime <= sourceTime[0]) return sourceValues[0]
99
+
100
+ const lastIndex = Math.min(sourceTime.length, sourceValues.length) - 1
101
+ if (targetTime >= sourceTime[lastIndex]) {
102
+ return sourceValues[lastIndex]
103
+ }
104
+
105
+ for (let index = 1; index <= lastIndex; index += 1) {
106
+ const currentTime = sourceTime[index]
107
+ if (targetTime > currentTime) continue
108
+
109
+ const previousTime = sourceTime[index - 1]
110
+ const previousValue = sourceValues[index - 1]
111
+ const currentValue = sourceValues[index]
112
+ if (currentTime === previousTime) return currentValue
113
+
114
+ const ratio =
115
+ (targetTime - previousTime) / (currentTime - previousTime)
116
+ return SpiceTimeSeriesNormalizer.#round(
117
+ previousValue + ratio * (currentValue - previousValue)
118
+ )
119
+ }
120
+
121
+ return sourceValues[lastIndex]
122
+ }
123
+
124
+ /**
125
+ * Rounds numeric output to a stable precision.
126
+ * @param {number} value Numeric value.
127
+ * @returns {number}
128
+ */
129
+ static #round(value) {
130
+ return Number(Number(value).toPrecision(12))
131
+ }
132
+ }
package/src/index.mjs CHANGED
@@ -1,4 +1,10 @@
1
1
  export { CircuitJsonDocument } from './core/CircuitJsonDocument.mjs'
2
+ export { CircuitJsonBomBuilder } from './core/CircuitJsonBomBuilder.mjs'
3
+ export { CircuitJsonElementValidator } from './core/CircuitJsonElementValidator.mjs'
2
4
  export { CircuitJsonIndexer } from './core/CircuitJsonIndexer.mjs'
5
+ export { CircuitJsonManufacturingBuilder } from './core/CircuitJsonManufacturingBuilder.mjs'
3
6
  export { CircuitJsonParser } from './core/CircuitJsonParser.mjs'
7
+ export { CircuitJsonSupportMatrixBuilder } from './core/CircuitJsonSupportMatrixBuilder.mjs'
4
8
  export { CircuitJsonUnits } from './core/CircuitJsonUnits.mjs'
9
+ export { SpiceCompatibilityPreprocessor } from './core/spice/SpiceCompatibilityPreprocessor.mjs'
10
+ export { SpiceSimulationService } from './core/spice/SpiceSimulationService.mjs'