こんな悩みはありませんか?
前回の記事で、GHSは 「測定値の意味(ACOM)」と「運び方(GATT)」を分離し、種別の違いは MDCコードで表す——という話をしました。
でも、こう思いませんでしたか。
「ACOMって、結局どんなデータの形をしているの?」
今回はそこを開けます。結論から言うと、ACOMの正体は 「Observation(オブザベーション)」という1つの箱です。血圧も体温もSpO₂も、すべてこの同じ箱に入ります。
この記事を読めば、次の3つがクリアになります。
- ACOMの中心にある Observation が何を表すオブジェクトなのか
- その中に何が入っているのか(実データ例と、GATTを流れる実際のバイト列で確認)
- なぜ同じ箱で、あらゆるセンサー種別を表せるのか
GHSの全体像がまだの方は、先に 医療センサーBLEの新規格「GHS」とは? を読むとスムーズです。
ACOMとは何か
ACOM(abstract and generic information content model)は、IEEE 11073-10206 が定義する「測定値の意味を表す抽象モデル」です。日本語にすると「抽象的で汎用的な、情報内容のモデル」。要するに、“測定値をどう表すか”の共通ルールです。
出自も押さえておくと理解が深まります。ACOMは、従来のパーソナルヘルスデバイス標準 IEEE 11073-20601 のモデルを簡素化・更新した版です。つまりまったくの新顔ではなく、PHD(Personal Health Device)標準の系譜に連なるものです。
GHSがやっているのは、この ACOM を BLE の GATT に載せて運ぶこと。だからこそ、まず ACOM の形を知ることが、GHS理解の近道になります。
ACOMの主役は「Observation」
ACOMの中心にあるオブジェクトが Observation です。ひとことで言えば、「1回の測定を表す箱」。
血圧を測っても、体温を測っても、SpO₂を測っても、出てくるのはすべて「Observation」という同じ器です。そして、その箱の中の「これは何の測定か」を決めるのが、前回登場した MDCコード(IEEE 11073-10101) です。
ACOMのクラス図(UML)では、Observationは基底クラスとして、type(何の測定か=MDCコード)、time-stamp(時刻)、id(接続中の一意ID)、derived-from/has-member(他の測定との関連)といった共通の属性を持つものとして定義されています。

Observationの中身を、実データで見る
抽象的な説明だけだとピンとこないので、パルスオキシメータのSpO₂測定を例に、Observationのフィールドに何が入るかを見てみます(Bluetooth SIGの実装ガイドの例より)。
| Observationのフィールド | 意味 | 実例(SpO₂測定) |
|---|---|---|
| Class Type | どの型の測定か | Numeric(数値) |
| Type | 測定の種類(MDCコード) | MDC_PULS_OXIM_SAT_O2(code 150456) |
| Unit | 単位(MDCコード) | MDC_DIM_PERCENT(%) |
| Value | 測定値 | 89.0 |
| Time Stamp | 測定時刻 | 2017-09-04 16:30:00 +1:00 |
ここで大事なのは、「89.0」という数字だけでは、医療データとして意味をなさないということです。
- それが SpO₂の値であること(Type)
- 単位が % であること(Unit)
- いつ測ったのか(Time Stamp)
これらが揃って、初めて「2017年9月4日16時30分、SpO₂ 89.0%」という意味のあるデータになります。ACOMは、この“意味の同梱”を標準化しているわけです。
ちなみに、この「MDCコード」はACOMのモデル上 Term という型で表され、partition(区分)と term-code(コード)という2つの数値でできています。SpO₂の 2::19384 は、partition=2/term-code=19384 という意味です(上の表にあった 150456 は、この2つを1つの数値にまとめた表記で、2 × 65536 + 19384 の値です)。Observationの「何の測定か(type)」も「単位(unit)」も、同じ Term で表されます。
Observationはこのほかにも、測定ステータス・患者/ユーザID・補足情報・参照といったフィールドを持ちますが、まずは「値だけでなく意味がセットで入る箱」というイメージを掴めば十分です。
実物チラ見せ:GATTを流れるObservationのバイト列
ここまで見てきたObservationは、GATT上では実際に1本のバイト列として流れます。全フィールドの詳しい解読はここではしません(それは次回のテーマです)。まずは 「こういうものだ」と目で見るのが目的です。
構造は大きく、「1オクテットの Segmentation Header」+「Health Observation Body」 に分かれます。

Segmentation Header(1オクテット)
| ビット | フィールド | 意味 |
|---|---|---|
| 0 | First Segment | 最初のセグメントか |
| 1 | Last Segment | 最後のセグメントか |
| 2–7 | Rolling Segment Counter | セグメント番号(0〜63でロールオーバー) |
なぜ「セグメント」なのか。1回のNotify/Indicationで送れるサイズ(ATT MTU)には上限があるため、長い測定値はそこに収まりません。そこでGHSは、Observationを複数のセグメントに分割して送り、各セグメントの先頭にこのヘッダを付けます。受信側は First / Last / カウンタを見て、分割されたデータを元通りに組み立てます。
Health Observation Body(本体)
ヘッダの後ろに、Observation本体のフィールドが次の順で並びます。
| フィールド | サイズ(オクテット) | 要否 |
|---|---|---|
| Observation Class Type | 1 | 必須 |
| Length | 2 | 必須 |
| Flags | 2 | 必須 |
| Observation Type(=MDCコード) | 4 | 任意 |
| Time Stamp | 9 | 任意 |
| Measurement Duration | 4 | 任意 |
| Measurement Status | 2 | 任意 |
| Observation Id | 4 | 任意 |
| Patient | 1 | 任意 |
| Supplemental Information | 可変 | 任意 |
| Derived From | 可変 | 任意 |
| Is Member Of | 可変 | 任意 |
| TLVs | 可変 | 任意 |
| Observation Value | 可変 | 必須 |
注目してほしいのは、さっき表で見た抽象フィールド(Class Type、Type=MDCコード、Time Stamp、Value…)が、そのまま実バイトのフィールドとして並んでいることです。どの「任意」フィールドを含むかは、先頭近くの Flags が決めます。
ビット単位の意味やエンコード規則にはここでは踏み込みませんが、「抽象モデルのObservationが、実際にはこういう生データになる」という感覚さえ持ち帰れれば、この節は十分です。
Observationには8つの型(Class Type)がある
SpO₂のような単純な数値だけでなく、状態・文字列・波形なども、同じObservationの枠組みで表せます。ACOMの実装ガイドのクラス図(UML)では、これらは Observation を親とするサブクラスとして整理されていて、たとえば数値は NumericObservation(unit: Term と value: FLOAT を持つ)、波形は SampleArrayObservation という具合です。型は全部で次の8つです。
| # | Observation Class Type | 用途の例 |
|---|---|---|
| 1 | Numeric | SpO₂・体温などの単一数値 |
| 2 | Simple discrete | 状態コードなど |
| 3 | String | 文字列 |
| 4 | Sample array | 波形(ECGなど) |
| 5 | Compound discrete event | 複合イベント |
| 6 | Compound state/event | 複合状態 |
| 7 | Compound | 複数値を1測定に(例:血圧=収縮期/拡張期/平均) |
| 8 | TLV-encoded | TLV符号化 |
入門としては、基本は「1 Numeric」と覚えておけば十分です。血圧のように複数の値を1回の測定にまとめたいときは「7 Compound」を使う、という程度を押さえておきましょう。
なぜ同じ箱で、あらゆる種別を表せるのか
ここまで来ると、前回の「答え合わせ」ができます。
種別ごとに変わるのは、Typeに入るMDCコードと、Valueの中身だけ。Observationという箱の構造そのものは共通です。

だからこそ、デバイス種別が増えてもデータの表し方を作り直す必要がない。前回お伝えした「GHSは通信を共通化する」の正体は、この共通の箱=Observationにあったわけです。
ACOMのその先:2つの出口
最後に、Observationがこの先どこへ向かうかを押さえておきます。出口は2つあります。
- BLEに載せる出口:先ほど見たように、ObservationはSegmentation Header+Bodyのバイト列としてGATTを流れます。そのビット単位の詳細が、次回のテーマです。
- 電子カルテに載せる出口:ACOM Observationは、医療データ標準の FHIR Observation に素直に変換できます。TypeはFHIRの
codeに、ValueはvalueQuantityに……という形で、フィールドがほぼ1対1で対応します。
つまりObservationは、BLEでもカルテでも通用する共通の器として設計されている、というわけです。
まとめ
3行でまとめます。
- ACOMの中心は Observation=1回の測定を「Type(MDCコード)+Value+単位+時刻…」でひとまとめにする共通の箱
- GATT上では Segmentation Header + Body のバイト列として流れ、長い測定値は分割して送られる
- 種別で変わるのは中身(MDCコードと値)だけ。箱は共通だから種別追加に強く、FHIRにも素直に乗る
「値だけでなく意味がセットで運ばれる」——この設計が、GHSが種別に縛られず、かつ医療システムと繋がれる理由です。
参考(一次資料)
- Bluetooth SIG『Generic Health Sensor Service(GHSS)』v1.0 §3.2 Live Health Observations(Segmentation Header / Health Observation Body)
- Bluetooth SIG『Generic Health Sensor Design and Implementation Guide』v2(Appendix A: ACOM UMLモデル/§8 FHIRマッピング)
- IEEE 11073-10206(ACOM)/ IEEE 11073-10101(MDC nomenclature)/ IEEE 11073-20601(PHD)
- HL7 FHIR / FHIR PHD Implementation Guide(R4)
この記事はBluetooth SIGの公開仕様・実装ガイド、およびIEEE/HL7の公開情報をもとに構成しています。


コメント