자동차·데이터 실무

자동차 시험 데이터의 km/h, m/s, g, m/s² 단위를 변환하고 검증하기

합성 차량 속도와 가속도 데이터를 일관된 SI 단위로 변환한 뒤 역변환하여 계산을 확인합니다. 원본 CSV는 그대로 유지하고 변환된 데이터는 새 출력 폴더에 저장합니다.

목차 보기

이런 분께 맞아요속도와 가속도 단위가 섞인 차량 또는 시험 데이터를 분석하기 전에 간단한 단위 변환과 검증을 수행하려는 사람을 위한 안내입니다.

준비할 것
  • Python 3.12와 해당 버전을 실행하는 터미널 명령이 준비되어 있어야 합니다.
  • UTF-8 CSV와 Python 파일을 저장할 수 있는 텍스트 편집기가 필요합니다.
  • 스크립트가 outputs 아래에 새 폴더를 만들 수 있는 작업 폴더가 필요합니다.
  • Python 표준 라이브러리인 csv, math, pathlib만 사용합니다.

01데이터를 처리하기 전에 변환식부터 정하기

이 예제에서는 속도를 m/s, 가속도를 m/s²로 통일합니다. 1 km는 1000 m이고 1시간은 3600초이므로 km/h 값을 3.6으로 나누면 m/s가 됩니다. 반대로 m/s에 3.6을 곱하면 km/h가 됩니다.

가속도는 관례적인 표준중력 값 g0 = 9.80665 m/s²를 사용합니다. g 단위의 값에 9.80665를 곱하면 m/s²가 됩니다. 반대로 m/s²를 9.80665로 나누면 g 단위가 됩니다.

변환계산식
km/h → m/skm/h ÷ 3.6
m/s → km/hm/s × 3.6
g → m/s²g × 9.80665
m/s² → gm/s² ÷ 9.80665

02작은 합성 시험 데이터 만들기

아래 데이터는 이 글을 위해 작성한 합성 데이터입니다. unit_test_data.csv로 저장하세요. 속도는 손으로 변환하기 쉬운 값을 사용하고, 가속도에는 양수, 음수, 소수 g 값을 포함했습니다.

csv
sample_id,speed_kmh,accel_g
T001,0,0
T002,36,1
T003,72,-0.5
T004,90,0.25
T005,108,-1.25

레코드는 5개입니다. 음수 가속도는 변환 후에도 음수로 유지됩니다. 단위 변환은 단위만 바꾸며 부호를 바꾸지 않습니다. 이 데이터는 수치 예제일 뿐 특정 차량 거동이나 센서를 나타내는 값이 아닙니다.

03예상 변환값을 손으로 계산하기

속도 변환은 직접 계산할 수 있습니다. 예를 들어 72 km/h ÷ 3.6 = 20 m/s이고, 90 km/h ÷ 3.6 = 25 m/s입니다. 다시 변환하면 20 × 3.6 = 72 km/h, 25 × 3.6 = 90 km/h가 됩니다.

가속도는 1 g가 9.80665 m/s²입니다. -0.5 g는 -4.903325 m/s², 0.25 g는 2.4516625 m/s², -1.25 g는 -12.2583125 m/s²가 됩니다.

sample_idspeed_kmh예상 speed_m_saccel_g예상 accel_m_s2
T00100.00000000.000000
T0023610.00000019.806650
T0037220.000000-0.5-4.903325
T0049025.0000000.252.451663
T00510830.000000-1.25-12.258313

표의 가속도 값은 소수점 이하 6자리로 표시했습니다. 실제 계산에서는 이미 반올림된 출력 문자열을 다시 사용하지 말고 9.80665의 전체 값을 사용해야 합니다.

04CSV를 변환하고 역변환으로 확인하기

다음 스크립트를 unit_conversion_check.py로 저장하세요. 원본 값을 읽고 두 종류의 정방향 변환을 수행한 뒤 다시 원래 단위로 역변환하여 작은 수치 허용오차 안에서 일치하는지 확인합니다. 원본 CSV는 다시 저장하지 않습니다.

python
import csv
import math
from pathlib import Path

SOURCE = Path("unit_test_data.csv")
OUTPUT_DIR = Path("outputs") / "unit_conversion_result"
OUTPUT = OUTPUT_DIR / "converted_test_data.csv"
STANDARD_GRAVITY = 9.80665
TOLERANCE = 1e-12


def kmh_to_ms(value: float) -> float:
    return value / 3.6


def ms_to_kmh(value: float) -> float:
    return value * 3.6


def g_to_ms2(value: float) -> float:
    return value * STANDARD_GRAVITY


def ms2_to_g(value: float) -> float:
    return value / STANDARD_GRAVITY


def main() -> None:
    if not SOURCE.is_file():
        raise FileNotFoundError(f"Source CSV not found: {SOURCE}")
    if OUTPUT_DIR.exists():
        raise FileExistsError(f"Output folder already exists: {OUTPUT_DIR}")

    output_rows = []
    with SOURCE.open("r", encoding="utf-8-sig", newline="") as stream:
        reader = csv.DictReader(stream)
        required = {"sample_id", "speed_kmh", "accel_g"}
        if reader.fieldnames is None or not required.issubset(reader.fieldnames):
            raise ValueError("CSV is missing a required column.")

        seen_ids = set()
        for row in reader:
            sample_id = row["sample_id"].strip()
            if not sample_id:
                raise ValueError("sample_id must not be blank.")
            if sample_id in seen_ids:
                raise ValueError(f"Duplicate sample_id: {sample_id}")
            seen_ids.add(sample_id)

            speed_kmh = float(row["speed_kmh"])
            accel_g = float(row["accel_g"])
            speed_ms = kmh_to_ms(speed_kmh)
            accel_ms2 = g_to_ms2(accel_g)
            speed_roundtrip = ms_to_kmh(speed_ms)
            accel_roundtrip = ms2_to_g(accel_ms2)

            speed_ok = math.isclose(
                speed_kmh, speed_roundtrip,
                rel_tol=TOLERANCE, abs_tol=TOLERANCE
            )
            accel_ok = math.isclose(
                accel_g, accel_roundtrip,
                rel_tol=TOLERANCE, abs_tol=TOLERANCE
            )
            if not speed_ok or not accel_ok:
                raise RuntimeError(f"Round-trip check failed: {sample_id}")

            output_rows.append({
                "sample_id": sample_id,
                "speed_kmh": f"{speed_kmh:g}",
                "speed_m_s": f"{speed_ms:.6f}",
                "speed_roundtrip_kmh": f"{speed_roundtrip:.6f}",
                "accel_g": f"{accel_g:g}",
                "accel_m_s2": f"{accel_ms2:.6f}",
                "accel_roundtrip_g": f"{accel_roundtrip:.6f}",
                "roundtrip_check": "PASS",
            })

    OUTPUT_DIR.parent.mkdir(parents=True, exist_ok=True)
    OUTPUT_DIR.mkdir()
    fields = [
        "sample_id", "speed_kmh", "speed_m_s", "speed_roundtrip_kmh",
        "accel_g", "accel_m_s2", "accel_roundtrip_g", "roundtrip_check"
    ]
    with OUTPUT.open("x", encoding="utf-8", newline="") as stream:
        writer = csv.DictWriter(stream, fieldnames=fields)
        writer.writeheader()
        writer.writerows(output_rows)

    print(f"Converted records: {len(output_rows)}.")
    print(f"Round-trip checks passed: {len(output_rows)}.")
    print(f"Standard gravity used: {STANDARD_GRAVITY} m/s^2.")
    print(f"Output: {OUTPUT.as_posix()}")


if __name__ == "__main__":
    main()

05예상 변환 파일과 비교하기

모든 행은 역변환 후 원래 속도와 가속도로 돌아와야 합니다. 아래에는 소수점 이하 6자리로 표시한 예상 결과가 있습니다. 내부 계산은 문자열로 서식화하기 전의 부동소수점 값을 사용합니다.

csv
sample_id,speed_kmh,speed_m_s,speed_roundtrip_kmh,accel_g,accel_m_s2,accel_roundtrip_g,roundtrip_check
T001,0,0.000000,0.000000,0,0.000000,0.000000,PASS
T002,36,10.000000,36.000000,1,9.806650,1.000000,PASS
T003,72,20.000000,72.000000,-0.5,-4.903325,-0.500000,PASS
T004,90,25.000000,90.000000,0.25,2.451663,0.250000,PASS
T005,108,30.000000,108.000000,-1.25,-12.258313,-1.250000,PASS

아래 예상 콘솔 출력은 합성 데이터와 스크립트를 바탕으로 손으로 도출한 결과이며 실제 실행 로그가 아닙니다.

text
Converted records: 5.
Round-trip checks passed: 5.
Standard gravity used: 9.80665 m/s^2.
Output: outputs/unit_conversion_result/converted_test_data.csv

06독립적으로 확인하고 자주 발생하는 오류 찾기

  • 36 km/h를 직접 확인합니다. 36 ÷ 3.6 = 10 m/s입니다.
  • 108 km/h를 직접 확인합니다. 108 ÷ 3.6 = 30 m/s입니다.
  • -0.5 g를 직접 확인합니다. -0.5 × 9.80665 = -4.903325 m/s²입니다.
  • 단위 변환 과정에서 부호가 그대로 유지되는지 확인합니다.
  • 5개 행 모두 roundtrip_check가 PASS인지 확인합니다.
  • OUTPUT_DIR을 바꾸지 않고 다시 실행합니다. 기존 결과를 교체하지 않고 FileExistsError로 중단되어야 합니다.
문제확인할 사항
속도가 약 3.6배 차이남m/s 값을 km/h로 잘못 처리했거나 그 반대인지 확인하세요.
가속도가 약 9.8배 차이남g와 m/s²를 혼동했는지 확인하세요.
음수 가속도가 양수로 바뀜분석에서 크기만 필요한 경우가 아니라면 절댓값을 적용하지 마세요.
예상하지 못한 반올림 차이계산에는 충분한 정밀도를 유지하고 표시나 내보내기 단계에서만 반올림하세요.
역변환은 통과하지만 원본 단위 라벨이 틀림수학적으로 가역적인 변환은 원본의 잘못된 단위 표기를 탐지할 수 없습니다.

07실제 시험 데이터에 적용하기 전 한계 이해하기

단위 변환이 정상적으로 끝났다는 것은 계산과 선언된 단위가 내부적으로 일관된다는 뜻일 뿐입니다. 원본 센서가 제대로 교정되었는지, 단위 라벨이 정확했는지, 기록된 값이 의도한 물리량을 나타내는지는 증명하지 않습니다.

여기서는 g 변환에 관례적인 표준중력 9.80665 m/s²를 사용합니다. 실제 지역의 중력가속도는 이 관례적인 기준과 다를 수 있습니다. 많은 공학 데이터에서는 g를 정규화된 가속도 단위로 사용하므로 어떤 기준을 사용했는지 문서화해야 합니다.

실제 차량 시험 데이터에는 휠 속도, 차량 속도, 회전속도, 힘, 압력, 온도 등 여러 단위가 함께 있을 수 있습니다. 각 채널의 물리 차원을 데이터 사전에 기록하고 그에 맞게 변환하세요. 숫자의 크기만 보고 단위를 추정해서는 안 됩니다.

실행·검증 기록

2026-09-20 · 예제 수동 검토 · 대상: Python 3.12 · 표준 라이브러리: csv, math, pathlib · 실행하지 않음

  • 5개의 속도를 각각 0, 10, 20, 25, 30 m/s로 수동 변환했습니다.
  • 가속도 값은 1 g = 9.80665 m/s²를 사용해 수동 계산했습니다.
  • -0.5 g = -4.903325 m/s², 0.25 g = 2.4516625 m/s², -1.25 g = -12.2583125 m/s²임을 표시 반올림 전에 확인했습니다.
  • 속도 역변환은 m/s에 3.6을 곱해 원래 값으로 돌아오는지 수동 확인했습니다.
  • 필수 열, 중복 sample_id, 역변환 비교, 출력 충돌 방지, 원본 CSV 보존 로직을 코드로 검토했습니다.
  • 예상 CSV와 콘솔 출력을 손으로 도출했습니다.
검증 한계
  • 이 응답의 작성자는 코드를 실행하지 않았으며, 변환 CSV를 실제로 만들지 않았습니다.
  • 센서 교정, 메타데이터 정확성, 실제 지역 중력가속도, 계측 시스템의 단위 라벨은 시험하지 않았습니다.
  • 이 예제에서는 km/h, m/s, g, m/s²만 다룹니다.
  • 공식 문서 URL은 알려진 문서 위치를 사용했지만 실시간으로 접속해 확인하지 않았습니다.

사이트 전체 작성·검증 원칙

참고 출처

설명과 예제는 직접 작성했습니다. 관련 동작과 개념은 아래 공식 자료에서 확인할 수 있습니다.