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.
- package/README.md +21 -2
- package/docs/api.md +50 -4
- package/docs/model-format.md +6 -3
- package/package.json +1 -1
- package/spec/library-scope.md +4 -1
- package/src/core/CircuitJsonBomBuilder.mjs +146 -0
- package/src/core/CircuitJsonDocument.mjs +46 -13
- package/src/core/CircuitJsonElementValidator.mjs +773 -0
- package/src/core/CircuitJsonIndexer.mjs +268 -4
- package/src/core/CircuitJsonManufacturingBuilder.mjs +426 -0
- package/src/core/CircuitJsonParser.mjs +22 -6
- package/src/core/CircuitJsonSupportMatrixBuilder.mjs +259 -0
- package/src/core/CircuitJsonUnits.mjs +133 -8
- package/src/core/spice/SpiceCompatibilityPreprocessor.mjs +139 -0
- package/src/core/spice/SpiceDirectiveParser.mjs +231 -0
- package/src/core/spice/SpiceFallbackSimulationEngine.mjs +168 -0
- package/src/core/spice/SpiceSimulationDiagnostics.mjs +234 -0
- package/src/core/spice/SpiceSimulationGraphBuilder.mjs +421 -0
- package/src/core/spice/SpiceSimulationGraphSummary.mjs +90 -0
- package/src/core/spice/SpiceSimulationService.mjs +92 -0
- package/src/core/spice/SpiceTimeSeriesNormalizer.mjs +132 -0
- package/src/index.mjs +6 -0
|
@@ -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'
|