← 포트폴리오로 돌아가기

BLACK BOX TESTING ARTIFACTS

CANoe/CAPL 기반 차량 ECU Black Box Testing

CANoe 시뮬레이션 기반 IVS Black Box 교육 과제입니다. 제공된 요구사항을 시험 조건으로 바꾸고, 입력 환경 구성과 CAPL 자동화, 결함 분석을 수행했습니다. 실차·HIL 검증 결과로 제시하지 않습니다.

유형
개인 교육 프로젝트
기간
2026.03.19–2026.03.23
팀 규모
1명
대상
IVS 교육용 검증 대상
환경
CANoe · CAPL · CANdb

01 / 프로젝트 역할

검증 전 과정 전담

교육기관의 검증 대상·요구사항을 바탕으로 CANdb·주변 노드·Panel 구성, 테스트 설계, CAPL 작성과 결과 분석을 담당했습니다. 대상 제어 로직 자체를 개발한 프로젝트는 아닙니다.

02 / 트러블슈팅

수동·자동 검증의 판정 불일치 해결

대표 문제 해결 — Fresh Frame 동기화

  1. 증상메시지 송신 방식 변경 후 이전 프레임을 기준으로 타이머가 시작돼 Detection 시점 판정이 흔들렸습니다.
  2. 원인 분석CAN Trace Timestamp와 CAPL Flag 전환 시점을 비교해 최신 Reference Frame 수신 전 측정이 시작됨을 확인했습니다.
  3. 수정waitBattReference·waitIGNReference에서 TestWaitForMessage로 최신 수신 프레임을 확인한 뒤 setTimerCyclic으로 1ms 타이머를 시작하도록 변경했습니다.
  4. 재검증경계값·Timing 시나리오를 다시 실행한 기록을 정리했습니다. 수정 전후 비교 로그가 없어 false pass/false fail의 방향과 오차 감소량은 확정하지 않았습니다.

시험 대상의 동작과 테스트 오라클(기대값·시간을 판정하는 로직)을 구분했습니다. 최신 프레임에 시작점을 맞춘 변경은 확인되지만, ±10ms 경계 판정의 정확도를 입증한 것으로 확대하지 않습니다.

보관 코드와 개선 설계 확인 →

OVERVIEW

테스트 수행 흐름

요구사항 분석 → CANdb·CANoe·Panel 환경 구성 → 수동 검증 → CAPL 자동 검증 → 정적·동적 검증 → 결함 분석 및 재확인

CODE

교육 당시 CAPL 원본 발췌와 한계

최신 수신 프레임을 확인한 뒤에 측정 타이머를 시작하도록 동기화 유틸리티를 분리했습니다. 아래는 보관된 Battery_Percent_Low.can 발췌입니다. 무한 대기 가능성, timeout 무기록 종료, 9ms 보정과 주석 불일치를 포함한 교육 당시 코드입니다.

기준 프레임 동기화 — 기대한 신호 값이 실제로 수신된 것을 확인한 뒤에만 1ms 주기 타이머를 기동합니다.

void waitBattReference(int timeoutMs , int data)
{
  if (TestWaitForMessage(BATT_01_10ms, timeoutMs) == 1)
  {
    TestGetWaitEventMsgData(battRef_msg);
    if (battRef_msg.Batt_Percent == data){
      testWaitForTimeout(9);
      setTimerCyclic(t_1ms ,1);
    }
    else{
      while(1){
        if (TestWaitForMessage(BATT_01_10ms, timeoutMs) == 1){
              TestGetWaitEventMsgData(battRef_msg);
              if (battRef_msg.Batt_Percent == data){
                testWaitForTimeout(9);
                setTimerCyclic(t_1ms ,1);
                break;
              }
        }
      }
    }
  }
}

전수 조합 판정 — Batt_Percent 0~100 × Ignition 0/1 × Engine 0/1을 모두 돌면서, 검출을 기대하는 조합과 기대하지 않는 조합을 각각 다른 기준으로 판정합니다.

/* 14,15 + IGN=1 + ENG=1 일 때만 fault level 2 기대 */
expectFault = (i == 1 && j == 1 && battPercent <= 15);

waitBattReference(20, battPercent);

while(time_cnt_ms <= 5100)
{
  @sysvar::UDS::Send_msg = 1;
  if(TestWaitForMessage(Fault_sts_Rsp, 20) == 1)
  {
    TestGetWaitEventMsgData(faultRsp_msg);

    if(expectFault)
    {
      if(faultRsp_msg.BATT_Percent_Err_sts == 2)
      {
        if(time_cnt_ms >= 4900 && time_cnt_ms <= 5100)
        {
          faultDetectedInWindow = 1;
          break;
        }
        else
        {
          timingError = 1;
          TestStepFail("1.4",
                       "Fault detected out of time window when IGN=%d, ENG=%d, Batt_Percent=%d, time=%dms",
                       i, j, battPercent, time_cnt_ms);
          break;
        }
      }
    }
    else
    {
      /* fault를 기대하지 않는 모든 경우는 0 유지가 정상 */
      if(faultRsp_msg.BATT_Percent_Err_sts != 0)
      {
        unexpectedStateDetected = 1;
        TestStepFail("1.5",
                     "Unexpected state detected when IGN=%d, ENG=%d, Batt_Percent=%d, Err_sts=%d, time=%dms",
                     i, j, battPercent, faultRsp_msg.BATT_Percent_Err_sts, time_cnt_ms);
        break;
      }
    }
  }
}

대기 실패와 측정 기준을 분리하는 개선 설계

원본 저장소에 기록한 후속 설계입니다. 아래는 의사코드이며 CAPL 컴파일·CANoe 실행 검증 전입니다.

deadline = monotonicNow + totalTimeout
while monotonicNow < deadline:
    frame = waitMessage(deadline - monotonicNow)
    if frame is timeout: return TIMEOUT
    if frame.value == expected: return OK(frame.timestamp)
return TIMEOUT

reference = waitReference(expected, totalTimeout)
if reference is TIMEOUT:
    record TEST_ERROR("기준 프레임 미수신")
    stop current case

if no valid status response before deadline:
    record TEST_ERROR("상태 응답 미수신")
    stop current case
elapsed = firstFaultResponse.timestamp - reference.timestamp

전체 대기시간을 제한하고 성공·실패를 반환합니다. 무응답을 정상 미검출로 판정하지 않습니다. 원본의 “14,15일 때만” 주석은 Batt_Percent ≤ 15 조건과 다르므로 수정 대상입니다.

시간 측정의 범위

Steering 소스에도 9ms 대기(주석: IVS controller 보정값)와 최대 20ms 응답 대기가 있습니다. 보정의 교정 근거와 전체 측정 불확도는 확보하지 못했습니다. 1ms 카운터 분해능과 986~993ms의 관측 산포는 측정 정확도 보증이 아닙니다.

후속 검증에서는 자극 프레임과 첫 상태 2 응답의 시각 차이를 기록하고, 요청·응답 관측 지연을 별도로 평가해야 합니다. 50±10ms 경계의 합격 판정은 이 검증 이후에 가능합니다.

TEST

4건정적 검토 항목
11건동적 결함
CAPL입력 조합 반복 시험
대표 테스트와 실제 판정
테스트요구 기준실제 결과판정
Batt Percent 경계값15% 조건 반영15%에서 Fault 미검출FAIL
IGN Cycle50 Cycle 경계Off-by-One 동작 확인FAIL
Steering Timing50±10ms986~993msFAIL

대표 검출 결과

결함별 실제 판정 화면

동적 결함 11건 가운데 10건은 CAPL 테스트 리포트의 판정 행을 그대로 남겼습니다. 각 행에는 입력 조건과 관측값이 함께 기록됩니다. Brake·Accel·Vehicle 독립 검출 결함 1건은 캡처가 없어 문서로만 정리했습니다.

DOCUMENT

원본 저장소의 요구사항 요약·시험 코드·결함 문서를 대조해 2026-09-28에 추적표와 대표 결함 보고서를 보완했습니다. 아래 ID는 사후 정리용이며 교육기관 원본 ID나 당시 리포트 ID가 아닙니다.

요구사항 → 테스트 → 판정 → 결함

원본 추적표의 대표 5건 (전체 합격률·커버리지 지표 아님)
요구 ID조건시험 ID기대 결과실제 결과결함·증거
BB-REQ-01Batt 15% / IGN=1 / ENG=1BB-TC-014900~5100ms 내 상태 2FAIL — 미검출BB-DEF-D01 · 판정 화면
BB-REQ-02회복 상태에서 IGN 50 cycleBB-TC-0250회 도달 시 ClearFAIL — 49회에서 ClearBB-DEF-D02 · 판정 화면
BB-REQ-03Batt 80% / IGN=1 / ENG=1 / Chg=1BB-TC-03고장 검출FAIL — 미검출BB-DEF-D03 · 판정 화면
BB-REQ-06고장 확정 후 전압≤15VBB-TC-06상태 1 회복FAIL — raw 14400~15000 회복 실패BB-DEF-D06 · 판정 화면
BB-REQ-11Steering 검출 조건 성립BB-TC-1150±10ms 내 상태 2FAIL — 관측 986~993msBB-DEF-D11 · 판정 화면

BB-DEF-D02 · IGN Clear 경계 불일치

재현 조건: 고장 검출 후 상태 1(Fixed)로 회복시킨 뒤 IGN Off→On을 반복하고 각 cycle의 상태 응답을 기록했습니다.

기대 / 실제: 요구 50 cycle에 대해 리포트는 Cycle_cnt=49에서 Clear를 기록했습니다. 대상 판정은 FAIL입니다.

영향도 / 원인: 고장 이력이 요구보다 일찍 삭제될 수 있습니다. 계수 기준이나 초기 상태의 off-by-one이 원인 후보이며 내부 구현 원인을 확정한 것은 아닙니다.

후속 확인: 초기 IGN 상태와 계수 기준을 대조하고 48·49·50·51 cycle을 재시험해야 합니다. 대상 수정 완료로 표시하지 않습니다.

결함 보고서의 실제 판정 근거 →

정적 검토 예시

BB-DEF-S01: Ignition의 Off/On/Error 세 상태를 1bit로 정의해 상태 수와 표현 범위가 충돌했습니다. 최소 2bit가 필요합니다. BB-DEF-S04: Brake_Err_sts 설명이 Accel을 지칭해 신호명과 설명이 불일치했습니다. 원본 요구사항 이미지는 교육 자료 보호를 위해 재게시하지 않습니다.

6개 스크립트 / 7개 모듈 / 24 testcase의 관계

보관된 스크립트별 testcase 선언은 Batt Percent 5개, Charging 6개, Voltage 7개, Ignition 1개, Engine 1개, Steering 4개로 합계 24개입니다. 화면에는 Brake_Error를 포함해 7개 모듈이 있지만 해당 모듈의 소스는 보관 자료에 없습니다. 24개는 함수 선언 수이며 입력 조합 수와 다릅니다.

DEMO

실제 CANoe 프로젝트 구성과 자동화 시험, Panel·Trace, 결함 결과 화면입니다.