돌아가기 시계열 어노테이터 스키마
## 용어 정의

| 용어 | 의미 | 예시 |
|---|---|---|
| **트랙 (track)** | 하나의 차트에 함께 표시되는 채널들의 그룹. 서로 다른 센서의 채널을 자유롭게 조합할 수 있다. | GPS 고도 + 기압 고도 + EKF 고도를 하나의 차트에 표시 |
| **채널 (channel)** | 하나의 값 배열을 가진 개별 데이터 시리즈. timestamps와 동일한 길이의 숫자 배열이다. | `battery_status__voltage_v` |
| **채널 메타 (channelMeta)** | 채널의 표시 정보 (이름, 단위, 색상, 차트 타입). | `{ name: "전압", unit: "V", color: "#ab47bc", chartType: "line" }` |

:::tip[PX4 ULog와의 관계]
ULog의 **토픽(topic)** 은 여러 필드를 가진 메시지 타입이고, dm_schema의 **채널(channel)** 은 토픽의 개별 필드에 대응합니다.
하나의 토픽이 여러 인스턴스를 가질 수 있으며(예: `sensor_accel[0]`, `sensor_accel[1]`), 각 인스턴스의 필드가 개별 채널이 됩니다.
트랙은 PX4에 없는 개념으로, 어떤 토픽의 어떤 필드든 자유롭게 조합하여 하나의 차트로 묶을 수 있습니다.

| PX4 ULog | dm_schema | 관계 |
|---|---|---|
| topic (예: `battery_status`) | — | 직접 대응 없음 (채널의 출처) |
| topic.field (예: `battery_status.voltage_v`) | channel | 1:1 대응 |
| — | track | PX4에 없는 개념 (사용자 정의 그룹) |
:::

---

## 프로젝트 카테고리

| `project.category` |
| --- |
| `time_series_annotation` |

## 지원 도구

| `project.annotation_types[]` | 설명 |
| --- | --- |
| `time_range` | 시간 범위 어노테이션 |

---

:::warning[초안]
⬇️ ⬇️ 아래 **데이터 유닛** 섹션부터 문서 끝까지는 작성 중인 내용으로, 확정되지 않았습니다.
:::

---

## 데이터 유닛

시계열 데이터 유닛은 동일한 시간 범위를 공유하는 센서 채널들의 집합입니다.

### task.data_unit.files

```jsonc
{
  "timeSeriesData": {
    "url": "https://storage.example.com/timeseries-data.json",
    "is_primary": true,
    "file_type": "json",
    "meta": {
      "channels": {
        "채널ID": {
          "name": "채널 표시 이름",
          "unit": "단위 (예: m/s², deg)",
          "color": "#3b82f6",
          "chartType": "line", // → ChartType
          "sampleRate": 100
        }
      },
      "timeRange": {
        "start": 1704067200000, // epoch_ms
        "end": 1704069600000,  // epoch_ms
        "unit": "epoch_ms"
      }
    }
  }
}
```

### url이 가리키는 시계열 데이터 JSON

ULG(ULog) 형식을 차용합니다.

`timestamps` 및 `meta.startTime` / `endTime`은 **Unix Epoch 기준 밀리초(epoch_ms)** 를 사용합니다.
`timeAxis.origin`으로 timestamps의 기준을 명시하며, 컨버터를 통해 다른 기준으로 변환할 수 있습니다.
화면 표시 형식은 `timeAxis.format`으로 지정합니다.

```jsonc
{
  "meta": {
    "startTime": 1613693139891, // epoch_ms
    "endTime": 1613693426291,   // epoch_ms
    "duration": 286.4,          // 초(s)
    "sampleRate": 10,           // Hz
    "nSamples": 2865,
    "timeAxis": {
      "origin": "absolute", // → TimeAxisOrigin
      "format": "HH:mm"     // → TimeAxisFormat
    }
  },
  "timestamps": [1613693139891, 1613693139991, "..."], // epoch_ms 배열
  "tracks": [
    {
      "id": "altitude-estimate", // 임의의 문자열 (kebab-case 권장)
      "name": "트랙 이름",
      "chartType": "line", // → ChartType
      "channels": ["채널ID_1", "채널ID_2"],
      "yRange": { "min": -30, "max": 30 },           // Y축 클리핑 (선택)
      "thresholds": [                                  // 배경색 구간 (선택)
        { "max": 4.905, "color": "rgba(34,197,94,0.15)", "label": "Good" },
        { "min": 4.905, "max": 9.81, "color": "rgba(253,203,110,0.15)", "label": "Warning" }
      ]
    }
  ],
  "channels": {
    "채널ID_1": [0.1, 0.2, "..."], // timestamps와 길이 동일
    "채널ID_2": [1.0, 1.1, "..."]
  },
  "channelMeta": {
    "채널ID_1": {
      "name": "채널 표시 이름",
      "unit": "m/s²",
      "color": "#cc6600",
      "chartType": "line" // → ChartType
    }
  }
}
```

## 타입 상세

### ChartType

| 값 | 설명 |
| --- | --- |
| `line` | 라인 차트 |
| `scatter` | 산점도 |
| `psd` | Power Spectral Density |
| `fft` | Fast Fourier Transform |

### TimeAxisOrigin

timestamps의 기준점을 지정합니다.

**프로그램은 `absolute` 기준으로만 동작합니다.** 다른 origin의 데이터는 별도 컨버터를 통해 `absolute`로 변환한 후 사용해야 합니다.

| 값 | 설명 |
| --- | --- |
| `absolute` | Unix Epoch 기준 밀리초 (**프로그램 기본 작동 기준**) |
| `relative` | 시작 시간으로부터의 경과 밀리초 (컨버터 필요) |
| `boot` | 시스템 부팅 시간 기준 밀리초 (컨버터 필요) |

### ChannelThreshold

트랙의 Y축에 표시되는 배경색 구간입니다. `tracks[].thresholds` 배열의 각 요소입니다.

| 필드 | 타입 | 필수 | 설명 |
| --- | --- | --- | --- |
| `color` | `string` | O | 배경색 (rgba 권장) |
| `label` | `string` | X | 구간 라벨 |
| `min` | `number` | X | Y축 최소값 (미지정 시 -∞) |
| `max` | `number` | X | Y축 최대값 (미지정 시 +∞) |

### YRange

트랙의 Y축 표시 범위를 고정합니다. `tracks[].yRange` 객체입니다.

| 필드 | 타입 | 필수 | 설명 |
| --- | --- | --- | --- |
| `min` | `number` | O | Y축 하한 |
| `max` | `number` | O | Y축 상한 |

### TimeAxisFormat

화면에 표시할 시간 형식을 지정합니다. [Day.js 포맷](https://day.js.org/docs/en/display/format) 문자열을 사용합니다.

| 예시 | 출력 |
| --- | --- |
| `HH:mm:ss` | 14:05:32 |
| `HH:mm` | 14:05 |
| `s.SSS` | 5.320 |
| `MM-DD HH:mm` | 02-18 14:05 |