2.3: Implementation with AI

AI-Assisted C Coding (SWE.3)

Setup: GitHub Copilot for Embedded C

Development Environment:

  • IDE: VS Code v1.85
  • Extension: GitHub Copilot v1.145
  • Language: C99 (ISO/IEC 9899:1999)
  • Coding Standard: MISRA C:2012 (mandatory rules enforced)
  • Compiler: Tasking TriCore C Compiler v6.3r1

Copilot Configuration (.vscode/settings.json):

{
  "github.copilot.enable": {
    "*": true,
    "c": true
  },
  "github.copilot.inlineSuggest.enable": true,

  "C_Cpp.cppStandard": "c99",
  "C_Cpp.cStandard": "c99",

  "editor.suggest.snippetsPreventQuickSuggestions": false,
  "editor.inlineSuggest.enabled": true,

  "files.associations": {
    "*.h": "c",
    "*.c": "c"
  }
}

Example 1: AI-Generated PID Controller

Prompt Engineering for Safety-Critical Code

Developer Prompt (to GitHub Copilot):

/**
 * @brief PID controller for ACC distance regulation
 * @implements [SWE-022] Speed Controller
 * @safety ASIL-B (ISO 26262)
 * @standard MISRA C:2012
 *
 * Requirements:
 * - Input: target_distance (meters), actual_distance (meters), dt (seconds)
 * - Output: acceleration command (m/s²), range: [-3.0, +3.0]
 * - Algorithm: PID with anti-windup
 * - Calibration: Kp, Ki, Kd from NvM
 * - Safety: Saturation limits, no division by zero
 */
float ACC_PID_Controller(
    float target_distance_m,
    float actual_distance_m,
    float dt_s
)
{
    // Copilot: Generate MISRA-compliant PID implementation

Copilot Generated Code (80% complete, developer reviews):

float ACC_PID_Controller(
    float target_distance_m,
    float actual_distance_m,
    float dt_s
)
{
    /* Static variables for integral and previous error (MISRA 8.9: declare at function scope) */
    static float integral_term = 0.0f;
    static float previous_error = 0.0f;

    /* Calibration parameters from NvM (ASIL-B: values validated at startup) */
    const float Kp = CAL_PID_Kp;  /* Default: 0.5 */
    const float Ki = CAL_PID_Ki;  /* Default: 0.1 */
    const float Kd = CAL_PID_Kd;  /* Default: 0.2 */

    /* Calculate error (MISRA 10.4: no mixed type operations) */
    float error = target_distance_m - actual_distance_m;

    /* Proportional term (MISRA 12.1: precedence explicit) */
    float proportional = Kp * error;

    /* Integral term with anti-windup (MISRA 14.3: avoid infinite loop) */
    integral_term += (error * dt_s);

    /* Anti-windup: Clamp integral (MISRA 12.5: no side effects in conditional) */
    if (integral_term > 10.0f)
    {
        integral_term = 10.0f;
    }
    else if (integral_term < -10.0f)
    {
        integral_term = -10.0f;
    }
    else
    {
        /* No action needed (MISRA 15.7: all if-else branches must have compound statement) */
    }

    float integral = Ki * integral_term;

    /* Derivative term (MISRA 21.1: avoid division by zero) */
    float derivative = 0.0f;
    if (dt_s > 0.001f)  /* Minimum time step: 1ms */
    {
        derivative = (error - previous_error) / dt_s;
    }
    else
    {
        /* dt too small, skip derivative (MISRA 15.7) */
    }

    float derivative_term = Kd * derivative;

    /* Update previous error for next cycle */
    previous_error = error;

    /* PID output (MISRA 12.1: explicit parentheses) */
    float output = proportional + integral + derivative_term;

    /* Safety saturation (ASIL-B: limit acceleration to ±3 m/s²) */
    if (output > 3.0f)
    {
        output = 3.0f;
    }
    else if (output < -3.0f)
    {
        output = -3.0f;
    }
    else
    {
        /* Output within limits (MISRA 15.7) */
    }

    return output;
}

Developer Review (20% effort):

// [PASS] APPROVED: MISRA compliant, logic correct
// [PASS] Anti-windup implemented
// [PASS] Division by zero check
// [PASS] Safety saturation
// [WARN] MINOR FIX: Add range check on inputs

// Add input validation (ASIL-B defense):
if ((target_distance_m < 0.0f) || (target_distance_m > 200.0f))
{
    return 0.0f;  /* Invalid input, safe default: no acceleration */
}
if ((actual_distance_m < 0.0f) || (actual_distance_m > 200.0f))
{
    return 0.0f;
}

Time Saved: 45 minutes → 10 minutes (78% reduction)


Example 2: Sensor Fusion Kalman Filter

AI-Generated Complex Algorithm

Developer Prompt:

/**
 * @brief Extended Kalman Filter for radar + camera fusion
 * @implements [SWE-023] Sensor Fusion Algorithm
 * @safety ASIL-B
 *
 * State vector: [distance, velocity]
 * Measurements: radar_distance, radar_velocity, camera_distance
 *
 * Requirements:
 * - Prediction step: state = F * prev_state
 * - Update step: Kalman gain, innovation
 * - Covariance propagation
 * - MISRA C:2012 compliant
 */
void EKF_SensorFusion(
    float radar_distance_m,
    float radar_velocity_mps,
    float camera_distance_m,
    bool camera_valid,
    float* fused_distance_m,
    float* fused_velocity_mps,
    float* confidence
)
{
    // Copilot: Generate EKF implementation

Copilot Output (requires significant review for safety):

void EKF_SensorFusion(
    float radar_distance_m,
    float radar_velocity_mps,
    float camera_distance_m,
    bool camera_valid,
    float* fused_distance_m,
    float* fused_velocity_mps,
    float* confidence
)
{
    /* State vector: [distance, velocity] (MISRA 9.1: initialize all variables) */
    static float state[2] = {50.0f, 0.0f};  /* Initial: 50m, 0 m/s */
    static float covariance[2][2] = {{1.0f, 0.0f}, {0.0f, 1.0f}};

    /* System model: state transition matrix (MISRA 8.11: static storage) */
    const float dt = 0.05f;  /* 50ms cycle time */
    const float F[2][2] = {{1.0f, dt}, {0.0f, 1.0f}};

    /* Process noise covariance (tunable) */
    const float Q[2][2] = {{CAL_EKF_Q_Distance, 0.0f},
                            {0.0f, CAL_EKF_Q_Velocity}};

    /* Measurement noise covariance (radar: 1m, camera: 2m) */
    const float R_radar = 1.0f;
    const float R_camera = 2.0f;

    /* --- PREDICTION STEP --- */
    /* Predict state: state_pred = F * state */
    float state_pred[2];
    state_pred[0] = (F[0][0] * state[0]) + (F[0][1] * state[1]);
    state_pred[1] = (F[1][0] * state[0]) + (F[1][1] * state[1]);

    /* Predict covariance: P_pred = F * P * F' + Q */
    float P_pred[2][2];
    /* Simplified calculation (full matrix multiplication omitted for brevity) */
    P_pred[0][0] = covariance[0][0] + Q[0][0];
    P_pred[1][1] = covariance[1][1] + Q[1][1];
    P_pred[0][1] = covariance[0][1];
    P_pred[1][0] = covariance[1][0];

    /* --- UPDATE STEP (RADAR) --- */
    /* Measurement: z_radar = [distance, velocity] */
    float z_radar[2] = {radar_distance_m, radar_velocity_mps};

    /* Measurement matrix H (identity for direct measurement) */
    const float H[2][2] = {{1.0f, 0.0f}, {0.0f, 1.0f}};

    /* Innovation: y = z - H * state_pred */
    float innovation[2];
    innovation[0] = z_radar[0] - state_pred[0];
    innovation[1] = z_radar[1] - state_pred[1];

    /* Innovation covariance: S = H * P_pred * H' + R */
    float S[2][2];
    S[0][0] = P_pred[0][0] + R_radar;
    S[1][1] = P_pred[1][1] + R_radar;
    S[0][1] = P_pred[0][1];
    S[1][0] = P_pred[1][0];

    /* Kalman gain: K = P_pred * H' * S^-1 */
    /* Simplified: K = P_pred / S (scalar approximation for diagonal S) */
    float K[2][2];
    K[0][0] = P_pred[0][0] / S[0][0];
    K[1][1] = P_pred[1][1] / S[1][1];
    K[0][1] = 0.0f;
    K[1][0] = 0.0f;

    /* State update: state = state_pred + K * innovation */
    state[0] = state_pred[0] + (K[0][0] * innovation[0]);
    state[1] = state_pred[1] + (K[1][1] * innovation[1]);

    /* Covariance update: P = (I - K * H) * P_pred */
    covariance[0][0] = (1.0f - K[0][0]) * P_pred[0][0];
    covariance[1][1] = (1.0f - K[1][1]) * P_pred[1][1];

    /* --- CAMERA FUSION (if valid) --- */
    if (camera_valid == true)
    {
        /* Innovation from camera (distance only) */
        float camera_innovation = camera_distance_m - state[0];

        /* Kalman gain for camera */
        float S_camera = covariance[0][0] + R_camera;
        float K_camera = covariance[0][0] / S_camera;

        /* Update state with camera measurement */
        state[0] += K_camera * camera_innovation;

        /* Update covariance */
        covariance[0][0] = (1.0f - K_camera) * covariance[0][0];
    }
    else
    {
        /* Camera invalid, radar-only mode (MISRA 15.7: mandatory else) */
    }

    /* --- OUTPUT --- */
    *fused_distance_m = state[0];
    *fused_velocity_mps = state[1];

    /* Confidence metric: inverse of trace(P) (lower covariance = higher confidence) */
    float trace_P = covariance[0][0] + covariance[1][1];
    if (trace_P > 0.001f)
    {
        *confidence = 1.0f / trace_P;  /* Range: 0-1000 */
    }
    else
    {
        *confidence = 1000.0f;  /* Maximum confidence */
    }
}

Developer Review (30% effort):

  • [PASS] Algorithm structure correct
  • [WARN] FIX NEEDED: Full matrix operations simplified (introduce error)
  • [WARN] FIX NEEDED: Add input validation (range checks)
  • [WARN] FIX NEEDED: Handle matrix inversion for non-diagonal S

Lesson: Copilot excellent for boilerplate, but complex math requires expert review.

AI-Generated Code Review Checklist: For safety-critical code, apply this checklist to AI-generated implementations: (1) Input validation present, (2) Range checks on calculations, (3) Division-by-zero protection, (4) MISRA compliance verified, (5) Safety saturation limits, (6) Documented assumptions. See Chapter 35 for comprehensive review guidance.


MISRA C Compliance with AI

Static Analysis Integration

Tool: LDRA TBvision (MISRA C:2012 checker)

Process:

  1. Developer writes code with Copilot assistance
  2. Pre-commit hook runs MISRA check
  3. Violations flagged, Copilot suggests fixes

Example Violation:

$ ldra_check src/ACC_Control.c

MISRA C:2012 Rule 10.4 Violation:
  Line 45: Operands of arithmetic operation have different essential types
  Code: float output = target_distance_m - actual_distance_m;
                                          ^
  Issue: Mixed float and double (actual_distance_m is double)

AI-Assisted Fix (Copilot suggestion):

// Before (violation)
float output = target_distance_m - actual_distance_m;  // actual_distance_m is double

// After (Copilot fix)
float output = target_distance_m - (float)actual_distance_m;  /* Explicit cast (MISRA 10.4) */

MISRA Compliance Results:

  • Before AI: 12 violations/1000 SLOC (manual coding)
  • After AI + Review: 2 violations/1000 SLOC (83% reduction)
  • Compliance Rate: 99.8% (0.2% = advisory rules, acceptable)

Static Analysis Tool Integration: LDRA TBvision is used in this example, but alternatives include Polyspace (MathWorks), PC-lint Plus (Gimpel), QA-C (Perforce), and Parasoft C/C++test. The key is integrating the tool into your pre-commit or CI workflow for continuous compliance checking.


Unit Test Generation (SWE.4)

AI-Generated Test Cases

Tool: GitHub Copilot + VectorCAST

Prompt:

/**
 * Unit tests for ACC_PID_Controller()
 * Requirements: [SWE-022] Speed Controller
 * Coverage target: 85% branch coverage (ASIL-B)
 *
 * Test scenarios:
 * 1. Normal operation: target > actual (accelerate)
 * 2. Normal operation: target < actual (decelerate)
 * 3. Edge case: target = actual (no change)
 * 4. Boundary: output saturation (+3 m/s²)
 * 5. Boundary: output saturation (-3 m/s²)
 * 6. Invalid input: negative distance
 * 7. Invalid input: distance > 200m
 */
void test_ACC_PID_Controller(void)
{
    // Copilot: Generate test cases

Copilot Generated Tests:

#include "unity.h"  /* Unity test framework */
#include "ACC_Control.h"

/* Test 1: Accelerate scenario */
void test_PID_Accelerate(void)
{
    float target = 60.0f;   /* Target: 60 meters */
    float actual = 50.0f;   /* Actual: 50 meters */
    float dt = 0.05f;       /* 50ms */

    float output = ACC_PID_Controller(target, actual, dt);

    /* Expected: positive output (accelerate to close gap) */
    TEST_ASSERT_GREATER_THAN(0.0f, output);
    TEST_ASSERT_LESS_OR_EQUAL(3.0f, output);  /* Within saturation limit */
}

/* Test 2: Decelerate scenario */
void test_PID_Decelerate(void)
{
    float target = 50.0f;
    float actual = 60.0f;
    float dt = 0.05f;

    float output = ACC_PID_Controller(target, actual, dt);

    /* Expected: negative output (decelerate, increase gap) */
    TEST_ASSERT_LESS_THAN(0.0f, output);
    TEST_ASSERT_GREATER_OR_EQUAL(-3.0f, output);
}

/* Test 3: Steady state */
void test_PID_SteadyState(void)
{
    float target = 55.0f;
    float actual = 55.0f;
    float dt = 0.05f;

    float output = ACC_PID_Controller(target, actual, dt);

    /* Expected: output near zero (no correction needed) */
    TEST_ASSERT_FLOAT_WITHIN(0.1f, 0.0f, output);
}

/* Test 4: Saturation (max acceleration) */
void test_PID_SaturationPositive(void)
{
    float target = 100.0f;  /* Large error */
    float actual = 10.0f;
    float dt = 0.05f;

    float output = ACC_PID_Controller(target, actual, dt);

    /* Expected: saturated at +3 m/s² */
    TEST_ASSERT_EQUAL_FLOAT(3.0f, output);
}

/* Test 5: Saturation (max deceleration) */
void test_PID_SaturationNegative(void)
{
    float target = 10.0f;
    float actual = 100.0f;  /* Large negative error */
    float dt = 0.05f;

    float output = ACC_PID_Controller(target, actual, dt);

    /* Expected: saturated at -3 m/s² */
    TEST_ASSERT_EQUAL_FLOAT(-3.0f, output);
}

/* Test 6: Invalid input (negative distance) */
void test_PID_InvalidInputNegative(void)
{
    float target = -10.0f;  /* Invalid */
    float actual = 50.0f;
    float dt = 0.05f;

    float output = ACC_PID_Controller(target, actual, dt);

    /* Expected: safe default (0 acceleration) */
    TEST_ASSERT_EQUAL_FLOAT(0.0f, output);
}

/* Test 7: Invalid input (distance out of range) */
void test_PID_InvalidInputOutOfRange(void)
{
    float target = 250.0f;  /* > 200m limit */
    float actual = 50.0f;
    float dt = 0.05f;

    float output = ACC_PID_Controller(target, actual, dt);

    /* Expected: safe default */
    TEST_ASSERT_EQUAL_FLOAT(0.0f, output);
}

/* Test suite runner */
int main(void)
{
    UNITY_BEGIN();

    RUN_TEST(test_PID_Accelerate);
    RUN_TEST(test_PID_Decelerate);
    RUN_TEST(test_PID_SteadyState);
    RUN_TEST(test_PID_SaturationPositive);
    RUN_TEST(test_PID_SaturationNegative);
    RUN_TEST(test_PID_InvalidInputNegative);
    RUN_TEST(test_PID_InvalidInputOutOfRange);

    return UNITY_END();
}

Coverage Results (VectorCAST):

Function: ACC_PID_Controller()
  Statement Coverage: 100% (28/28 statements)
  Branch Coverage: 92% (11/12 branches)
  MC/DC Coverage: 88% (ASIL-B requires 85% [PASS])

Uncovered Branch:
  Line 67: else clause for (dt > 0.001f) never executed
  Rationale: dt always 50ms in normal operation, edge case in fault mode
  Action: Add fault injection test for dt=0 scenario

Time Saved: 6 hours (manual test writing) → 1.5 hours (AI + review) = 75% reduction


Summary: AI Productivity Gains

Measured Results (Month 3-8, 25,000 SLOC)

Activity Traditional Time AI-Assisted Time Savings
Function Implementation 200 hours 120 hours 40%
MISRA Compliance 80 hours 30 hours 62%
Unit Test Development 150 hours 40 hours 73%
Code Review 100 hours 80 hours 20%
Documentation (Doxygen) 60 hours 15 hours 75%
Total 590 hours 285 hours 52%

Overall Productivity: 52% time reduction with AI assistance

Quality Impact:

  • Defect density: 1.6 defects/KLOC (better than 2.0 target)
  • MISRA compliance: 99.8% (exceeds 95% target)
  • Unit test coverage: 89% (exceeds 85% ASIL-B requirement)

Next: Verification and validation (25.04).