設計データの単位を壊さない設計|valueとunitを分離するJSON・CSV・Python変換

「設計データの単位を壊さない設計|valueとunitを分離するJSON・CSV・Python変換」の内容を表す技術イラスト

圧力の14は14 Pa、14 MPa、14 barのどれでしょうか。単位を取り違えると、計算結果、部品選定、検査判定まで誤る可能性があります。設計データをAPI、CSV、DB、CAD、Pythonの間で再利用するため、value、unit、quantityを分け、検証から保存までを壊れにくい契約にします。

目次

単位付きデータが解決する問題

単位付きの量は、最低でも次の3要素で表せます。

  • value:大きさを表す数値
  • unit:MPa、mm、Nなどの単位
  • quantity:圧力、長さ、力など、何を測った値か

最小のJSON例は次のとおりです。

{
  "quantity": "pressure",
  "value": 14.0,
  "unit": "MPa"
}

valueというkeyのvalueは数値型、unitとquantityは文字列型です。JSON全体はobjectで、複数の測定値ならobjectをarrayに格納します。

unitだけでなくquantityも必要なのは、同じ単位を使える別の物理量があるためです。圧力と応力はどちらもPaで表せますが、設計上の意味は同じではありません。単位の次元が一致することと、業務上交換可能であることは分けて考えます。

表示名に単位を埋め込むだけでは足りない

次のようなデータは、一見分かりやすく見えます。

{
  "pressure_mpa": 14.0
}

常にMPaを使う内部システムなら有効ですが、bar入力の機器やPa保存のDBを接続すると暗黙換算が生じます。

内部DBをPa固定にするならpressure_paでも契約は明確です。外部入力の単位が変わる境界では、最初のJSON例のようにvalueとunitを分離し、保存時に基準単位へ正規化します。

入力から出力までの流れ

単位変換は、数値に係数を掛ける処理だけではありません。処理を次の段階に分けます。

外部入力
  ↓
構造・型を検証
  ↓
quantityとunitの組み合わせを検証
  ↓
基準単位へ1回だけ変換
  ↓
基準値と元データを保存
  ↓
利用先の表示単位へ変換して出力

たとえば圧力の基準単位をPaと決めると、14 MPaは14,000,000 Paとして比較・計算できます。一般的な線形変換は次式です。xtarget=axsource+bx_{target}=a x_{source}+b

圧力や長さの多くは$b=0$ですが、温度の摂氏とケルビンのようにオフセットを持つ変換があります。すべてを単純な倍率表だけで処理できると考えると誤ります。

単位コードと表示文字列を分ける

UCUM(Unified Code for Units of Measure)は、科学・工学・ビジネスで使われる単位を曖昧なく電子交換するためのコード体系です。仕様には大文字・小文字を区別する表現もあるため、受信値を無条件に小文字化してはいけません。

実務では次を分けて持つと安全です。

  • unit_code:機械判定に使う正規コード
  • unit_label:画面や帳票に表示する文字列
  • quantity:物理量の種類

独自一覧でも入力別名から正規コードへの対応表を版管理し、未知の単位は推測せず隔離します。

JSON Schemaで構造を検証する

JSON Schema Draft 2020-12のValidation仕様では、type、enum、required、数値範囲などを使ってJSONの構造を検証できます。

圧力入力をMPa、kPa、barに限定する最小例です。

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["quantity", "value", "unit"],
  "properties": {
    "quantity": {
      "const": "pressure"
    },
    "value": {
      "type": "number",
      "minimum": 0,
      "maximum": 1000
    },
    "unit": {
      "type": "string",
      "enum": ["MPa", "kPa", "bar"]
    }
  },
  "additionalProperties": false
}

maximumは元の単位へ評価されます。構造検証の後に基準単位へ変換し、装置ごとの業務上限も確認します。

正常系と異常系を、少なくとも次のように用意します。

正常: {"quantity":"pressure","value":14.0,"unit":"MPa"}
正常: {"quantity":"pressure","value":140,"unit":"bar"}
異常: {"quantity":"pressure","value":"14","unit":"MPa"}  # 型違反
異常: {"quantity":"length","value":14.0,"unit":"MPa"}      # 量と単位が不整合
異常: {"quantity":"pressure","value":null,"unit":"MPa"}   # null非許容
異常: {"quantity":"pressure","value":14.0,"unit":"mpa"}   # 未定義コード

ゼロは測定値ですが、nullは値がない状態です。ゼロ、欠損、未測定、測定不能を同じ値にまとめないことが重要です。

CSVでは値列と単位列を対応させる

CSVにはobjectや数値型という仕組みがないため、対応関係を列名で表します。

record_id,pressure_value,pressure_unit
test-001,14.0,MPa
test-002,140,bar

データ辞書には型、必須条件、許可単位、基準単位、丸め規則を記載します。14 MPaのように一セルへ連結すると数値抽出が必要です。数値列と単位列を分け、小数点記号、指数表記、文字コードも交換仕様へ含めます。

Pythonで基準単位へ正規化する

次の例は、許可した圧力単位だけをPaへ変換します。任意の式をeval()するのではなく、明示的な変換表を使います。

from decimal import Decimal, InvalidOperation


PRESSURE_TO_PA = {
    "Pa": Decimal("1"),
    "kPa": Decimal("1000"),
    "MPa": Decimal("1000000"),
    "bar": Decimal("100000"),
}


def normalize_pressure(data: dict) -> dict:
    if data.get("quantity") != "pressure":
        raise ValueError("quantityはpressureである必要があります")

    unit = data.get("unit")
    if unit not in PRESSURE_TO_PA:
        raise ValueError("未対応の圧力単位です")

    value = data.get("value")
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        raise TypeError("valueは数値型である必要があります")

    try:
        decimal_value = Decimal(str(value))
    except InvalidOperation as exc:
        raise ValueError("valueの数値形式が不正です") from exc

    if not decimal_value.is_finite() or decimal_value < 0:
        raise ValueError("valueは有限の0以上である必要があります")

    value_pa = decimal_value * PRESSURE_TO_PA[unit]

    return {
        "quantity": "pressure",
        "value_pa": str(value_pa),
        "source_value": str(decimal_value),
        "source_unit": unit,
        "conversion_version": 1,
    }

Pythonのdecimal公式ドキュメントが説明するように、Decimalは1.1のような十進数を正確に表現できます。DBやJSONへ保存する型は契約で固定します。基準値は計算と検索、元データは監査や再変換に使います。

冪等性と二重換算を設計する

同じデータの再処理で、Paへ変換済みの値へ再び100万を掛けるとデータが壊れます。

防止策は次のとおりです。

  • 受信した元値と基準値を別fieldにする
  • 基準値のfield名またはメタデータで単位を固定する
  • conversion_versionを保存する
  • 同一レコードは安定したIDでUPSERTする
  • 再処理では必ず元値から基準値を再生成する
{
  "measurement_id": "test-001-pressure",
  "source": {"value": 14.0, "unit": "MPa"},
  "canonical": {"value": "14000000.0", "unit": "Pa"},
  "conversion_version": 1
}

正規化済みかを数値の大きさから推測せず、再実行しても同じIDと基準値へ収束させます。

数値精度と丸めを契約に含める

JSON Schemaの仕様上、JSONの数値に精度上限はありませんが、言語、DB、表計算ソフトには制約があります。

設計時には次を決めます。

  • 入力はJSON numberか十進文字列か
  • DBは整数、浮動小数点、DECIMALのどれか
  • 有効桁数と小数桁数
  • 丸めを変換前と変換後のどちらで行うか
  • 比較に使う許容差

換算で測定精度が増えたように見せず、保存値と表示用の丸め値を分けます。

よくある失敗

  • 数値だけを保存する:後から単位を復元できません。運用知識をデータ契約へ移します。
  • 単位を自由入力にする:MPa、Mpa、N/mm2などが増殖します。許可コードへ限定します。
  • 単位が合えば量も同じと考える:圧力と応力のような例があるため、quantityも検証します。
  • 変換後の値で元データを上書きする:監査できません。元値、基準値、変換版を残します。
  • 浮動小数点を完全一致で比べる:Decimal、整数化、許容差から用途に合う方法を選びます。

セキュリティと異常値対策

単位変換APIには、未知の単位、極端な数、NaN、無限大が送られる可能性があります。

  • 許可するquantityとunitを列挙する
  • 数値の上限・下限と有限性を検証する
  • 単位文字列からコードや式を実行しない
  • エラー行を正常データと分離する
  • API keyや機密の装置情報を測定データへ混在させない

公開用データでは、値そのものが設備能力や製造条件を推測させないかも確認します。単位変換とアクセス制御は別の責務です。

CAD・DB・APIへ再利用する設計

単位契約を共通部品にすると、CAD属性、部品表、試験結果、計算APIへ同じ規則を展開できます。

quantity: pressure
canonical_unit: Pa
accepted_units:
  - Pa
  - kPa
  - MPa
  - bar
value_type: decimal
nullable: false
minimum_canonical: 0
conversion_version: 1
retain_source: true

BIPMのSI Brochureを基礎資料とし、交換用コード、許可単位、換算規則を仕様として固定します。CAD固有の内部単位も、抽出直後に共通構造へ変換します。

まとめ

単位付きデータは、数値へ単位ラベルを添えるだけでは不十分です。何の量か、どの単位か、どの規則で基準値へ変換したかを機械が判断できる必要があります。

  • value、unit、quantityを分離する
  • 交換境界で構造、型、量と単位の組み合わせを検証する
  • 内部計算用の基準単位を決める
  • 元値と基準値を分けて保持する
  • 単位コードと人向け表示を分離する
  • 変換版を記録し、再実行は元値から行う
  • nullとゼロ、十進精度、丸め規則を契約に含める

この形を共通スキーマにすれば、API、CSV、DB、Python、CADの間で値の意味を保ち、将来の自動計算や設計データ資産にも安全につなげられます。

参考情報

参考になったらシェアしてください
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

機械設計・油圧・CAD・Python・AIなど、ものづくりに関わる技術を扱っています。工学知識を整理・構造化し、設計や自動化に再利用できる形へ変えていくことを目指しています。

目次