feat: define simulator data contracts
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
# Schemas
|
||||
|
||||
마이크 배열, scene, experiment, result의 versioned JSON Schema를 둡니다.
|
||||
|
||||
JSON Schema Draft 2020-12 형식입니다.
|
||||
|
||||
- `array.schema.json`: 배열 크기, 좌표계, 마이크 위치와 선택적 보정값
|
||||
- `scene.schema.json`: 재현 가능한 음원 recipe, asset 참조와 ground-truth 위치
|
||||
- `experiment.schema.json`: scan plane/grid, 주파수 대역, STFT와 DAS 설정
|
||||
- `result.schema.json`: 실행 환경, timing, peak와 평가 지표 요약
|
||||
|
||||
중복 id, Nyquist, 시간 구간과 참조 무결성은 `packages/contracts/validation.js`에서 추가로 검증합니다.
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://micarrsim.local/schemas/array.schema.json",
|
||||
"title": "micarrsim microphone array",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["schemaVersion", "kind", "id", "name", "units", "coordinateSystem", "aperture", "microphones"],
|
||||
"properties": {
|
||||
"schemaVersion": { "const": "1.0.0" },
|
||||
"kind": { "const": "micarrsim.array" },
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
|
||||
"name": { "type": "string", "minLength": 1, "maxLength": 120 },
|
||||
"description": { "type": "string", "maxLength": 1000 },
|
||||
"units": { "const": "m" },
|
||||
"coordinateSystem": { "$ref": "#/$defs/coordinateSystem" },
|
||||
"aperture": {
|
||||
"type": "object", "additionalProperties": false, "required": ["width", "height"],
|
||||
"properties": {
|
||||
"width": { "type": "number", "exclusiveMinimum": 0, "maximum": 20 },
|
||||
"height": { "type": "number", "exclusiveMinimum": 0, "maximum": 20 }
|
||||
}
|
||||
},
|
||||
"microphones": { "type": "array", "minItems": 1, "maxItems": 1024, "items": { "$ref": "#/$defs/microphone" } }
|
||||
},
|
||||
"$defs": {
|
||||
"coordinateSystem": {
|
||||
"type": "object", "additionalProperties": false,
|
||||
"required": ["handedness", "xAxis", "yAxis", "zAxis"],
|
||||
"properties": {
|
||||
"handedness": { "const": "right" }, "xAxis": { "const": "right" },
|
||||
"yAxis": { "const": "up" }, "zAxis": { "const": "toward-scene" }
|
||||
}
|
||||
},
|
||||
"position": {
|
||||
"type": "array",
|
||||
"prefixItems": [{ "type": "number" }, { "type": "number" }, { "type": "number" }],
|
||||
"items": false, "minItems": 3, "maxItems": 3
|
||||
},
|
||||
"microphone": {
|
||||
"type": "object", "additionalProperties": false, "required": ["id", "position"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "minLength": 1, "maxLength": 64 },
|
||||
"position": { "$ref": "#/$defs/position" },
|
||||
"sensitivityDb": { "type": "number", "minimum": -120, "maximum": 120 },
|
||||
"phaseOffsetDeg": { "type": "number", "minimum": -180, "maximum": 180 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://micarrsim.local/schemas/experiment.schema.json",
|
||||
"title": "micarrsim experiment",
|
||||
"type": "object", "additionalProperties": false,
|
||||
"required": ["schemaVersion", "kind", "id", "name", "arrayId", "sceneId", "scan", "frequencyBands", "stft", "beamforming"],
|
||||
"properties": {
|
||||
"schemaVersion": { "const": "1.0.0" }, "kind": { "const": "micarrsim.experiment" },
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
|
||||
"name": { "type": "string", "minLength": 1, "maxLength": 120 },
|
||||
"arrayId": { "type": "string", "minLength": 1 }, "sceneId": { "type": "string", "minLength": 1 },
|
||||
"scan": {
|
||||
"type": "object", "additionalProperties": false,
|
||||
"required": ["z", "xMin", "xMax", "yMin", "yMax", "columns", "rows"],
|
||||
"properties": {
|
||||
"z": { "type": "number", "exclusiveMinimum": 0 },
|
||||
"xMin": { "type": "number" }, "xMax": { "type": "number" },
|
||||
"yMin": { "type": "number" }, "yMax": { "type": "number" },
|
||||
"columns": { "type": "integer", "minimum": 8, "maximum": 512 },
|
||||
"rows": { "type": "integer", "minimum": 8, "maximum": 512 }
|
||||
}
|
||||
},
|
||||
"frequencyBands": {
|
||||
"type": "array", "minItems": 1, "maxItems": 8,
|
||||
"items": {
|
||||
"type": "object", "additionalProperties": false, "required": ["id", "minHz", "maxHz", "color"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
|
||||
"minHz": { "type": "number", "minimum": 0 }, "maxHz": { "type": "number", "exclusiveMinimum": 0 },
|
||||
"color": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"stft": {
|
||||
"type": "object", "additionalProperties": false, "required": ["fftSize", "hopSize", "window"],
|
||||
"properties": {
|
||||
"fftSize": { "enum": [128, 256, 512, 1024, 2048, 4096] },
|
||||
"hopSize": { "type": "integer", "minimum": 1, "maximum": 4096 }, "window": { "const": "hann" }
|
||||
}
|
||||
},
|
||||
"beamforming": {
|
||||
"type": "object", "additionalProperties": false,
|
||||
"required": ["algorithm", "backend", "minimumDistance", "normalization", "dynamicRangeDb"],
|
||||
"properties": {
|
||||
"algorithm": { "const": "das" }, "backend": { "enum": ["auto", "cpu", "webgpu"] },
|
||||
"minimumDistance": { "type": "number", "exclusiveMinimum": 0, "maximum": 10 },
|
||||
"normalization": { "enum": ["peak", "none"] },
|
||||
"dynamicRangeDb": { "type": "number", "minimum": 6, "maximum": 120 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://micarrsim.local/schemas/result.schema.json",
|
||||
"title": "micarrsim result summary",
|
||||
"type": "object", "additionalProperties": false,
|
||||
"required": ["schemaVersion", "kind", "experimentId", "createdAt", "backend", "inputHash", "timingMs", "bands"],
|
||||
"properties": {
|
||||
"schemaVersion": { "const": "1.0.0" }, "kind": { "const": "micarrsim.result" },
|
||||
"experimentId": { "type": "string", "minLength": 1 },
|
||||
"createdAt": { "type": "string", "format": "date-time" }, "backend": { "enum": ["cpu", "webgpu"] },
|
||||
"inputHash": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
|
||||
"timingMs": {
|
||||
"type": "object", "additionalProperties": false, "required": ["total", "beamforming"],
|
||||
"properties": {
|
||||
"total": { "type": "number", "minimum": 0 },
|
||||
"signalGeneration": { "type": "number", "minimum": 0 },
|
||||
"beamforming": { "type": "number", "minimum": 0 }
|
||||
}
|
||||
},
|
||||
"environment": { "type": "object", "additionalProperties": { "type": ["string", "number", "boolean"] } },
|
||||
"bands": {
|
||||
"type": "array", "minItems": 1,
|
||||
"items": {
|
||||
"type": "object", "additionalProperties": false,
|
||||
"required": ["id", "peakPosition", "peakValue", "metrics"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "minLength": 1 },
|
||||
"peakPosition": {
|
||||
"type": "array", "prefixItems": [{ "type": "number" }, { "type": "number" }, { "type": "number" }],
|
||||
"items": false, "minItems": 3, "maxItems": 3
|
||||
},
|
||||
"peakValue": { "type": "number", "minimum": 0 },
|
||||
"metrics": {
|
||||
"type": "object", "additionalProperties": false,
|
||||
"required": ["localizationErrorM", "peakToSidelobeDb"],
|
||||
"properties": {
|
||||
"localizationErrorM": { "type": "number", "minimum": 0 }, "peakToSidelobeDb": { "type": "number" },
|
||||
"energyInsideTruthRatio": { "type": "number", "minimum": 0, "maximum": 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://micarrsim.local/schemas/scene.schema.json",
|
||||
"title": "micarrsim acoustic scene",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["schemaVersion", "kind", "id", "name", "units", "sampleRate", "duration", "speedOfSound", "seed", "sources"],
|
||||
"properties": {
|
||||
"schemaVersion": { "const": "1.0.0" }, "kind": { "const": "micarrsim.scene" },
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
|
||||
"name": { "type": "string", "minLength": 1, "maxLength": 120 },
|
||||
"description": { "type": "string", "maxLength": 1000 }, "units": { "const": "m" },
|
||||
"sampleRate": { "type": "integer", "minimum": 8000, "maximum": 192000 },
|
||||
"duration": { "type": "number", "exclusiveMinimum": 0, "maximum": 300 },
|
||||
"speedOfSound": { "type": "number", "minimum": 250, "maximum": 400 },
|
||||
"seed": { "type": "integer", "minimum": 0, "maximum": 4294967295 },
|
||||
"image": { "$ref": "#/$defs/image" },
|
||||
"assets": { "type": "array", "maxItems": 128, "items": { "$ref": "#/$defs/asset" } },
|
||||
"sources": { "type": "array", "minItems": 1, "maxItems": 32, "items": { "$ref": "#/$defs/source" } },
|
||||
"ambient": { "type": "array", "maxItems": 8, "items": { "$ref": "#/$defs/ambient" } }
|
||||
},
|
||||
"$defs": {
|
||||
"position": {
|
||||
"type": "array", "prefixItems": [{ "type": "number" }, { "type": "number" }, { "type": "number" }],
|
||||
"items": false, "minItems": 3, "maxItems": 3
|
||||
},
|
||||
"image": {
|
||||
"type": "object", "additionalProperties": false,
|
||||
"required": ["assetId", "widthPixels", "heightPixels", "plane"],
|
||||
"properties": {
|
||||
"assetId": { "type": "string", "minLength": 1 },
|
||||
"widthPixels": { "type": "integer", "minimum": 1, "maximum": 32768 },
|
||||
"heightPixels": { "type": "integer", "minimum": 1, "maximum": 32768 },
|
||||
"plane": {
|
||||
"type": "object", "additionalProperties": false,
|
||||
"required": ["z", "xMin", "xMax", "yMin", "yMax"],
|
||||
"properties": {
|
||||
"z": { "type": "number", "exclusiveMinimum": 0 },
|
||||
"xMin": { "type": "number" }, "xMax": { "type": "number" },
|
||||
"yMin": { "type": "number" }, "yMax": { "type": "number" }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"asset": {
|
||||
"type": "object", "additionalProperties": false, "required": ["id", "kind", "fileName", "mimeType"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
|
||||
"kind": { "enum": ["audio", "image"] }, "fileName": { "type": "string", "minLength": 1, "maxLength": 255 },
|
||||
"mimeType": { "type": "string", "minLength": 3, "maxLength": 100 },
|
||||
"sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
|
||||
}
|
||||
},
|
||||
"signal": {
|
||||
"oneOf": [
|
||||
{ "type": "object", "additionalProperties": false, "required": ["type", "frequency"], "properties": {
|
||||
"type": { "const": "tone" }, "frequency": { "type": "number", "exclusiveMinimum": 0 },
|
||||
"phaseDeg": { "type": "number", "minimum": -360, "maximum": 360 }
|
||||
}},
|
||||
{ "type": "object", "additionalProperties": false, "required": ["type", "color"], "properties": {
|
||||
"type": { "const": "noise" }, "color": { "enum": ["white", "pink"] },
|
||||
"seedOffset": { "type": "integer", "minimum": 0, "maximum": 4294967295 }
|
||||
}},
|
||||
{ "type": "object", "additionalProperties": false, "required": ["type", "assetId"], "properties": {
|
||||
"type": { "const": "asset" }, "assetId": { "type": "string", "minLength": 1 },
|
||||
"channel": { "type": "integer", "minimum": 0, "maximum": 255 }, "loop": { "type": "boolean" }
|
||||
}}
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"type": "object", "additionalProperties": false,
|
||||
"required": ["id", "name", "position", "gainDb", "startTime", "duration", "signal"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
|
||||
"name": { "type": "string", "minLength": 1, "maxLength": 120 }, "position": { "$ref": "#/$defs/position" },
|
||||
"gainDb": { "type": "number", "minimum": -120, "maximum": 24 }, "startTime": { "type": "number", "minimum": 0 },
|
||||
"duration": { "type": "number", "exclusiveMinimum": 0 }, "signal": { "$ref": "#/$defs/signal" }
|
||||
}
|
||||
},
|
||||
"ambient": {
|
||||
"type": "object", "additionalProperties": false, "required": ["id", "gainDb", "signal"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
|
||||
"gainDb": { "type": "number", "minimum": -120, "maximum": 24 }, "signal": { "$ref": "#/$defs/signal" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user