Skip to main content

fail_safe_boundaries/
fail_safe_boundaries.rs

1//! Fail-safe boundary sides on a static firmware correction map.
2//!
3//! Reject uncharacterized low operating codes (`Error`) and hold the last
4//! characterized high edge (`Clamp`). All four sides are named. X is resolved
5//! before Y, so an X error wins when both inputs are invalid, and a clamped X
6//! still lets Y error. Clamp never extrapolates: it evaluates the endpoint
7//! cell. See the interpolation walkthrough (not packaged):
8//! <https://github.com/photon-circus/ph-surfaces/blob/v0.1.0/docs/interpolation-walkthrough.md>.
9//!
10//! Host `main` is an assertion harness. Declarations are `static` and
11//! `core`-compatible.
12
13use ph_surfaces::{BilinearSurface, Boundary, BoundaryPolicy, SurfaceError};
14
15static X: [u16; 2] = [100, 200];
16static Y: [u16; 2] = [10, 30];
17static VALUES: [[i32; 2]; 2] = [
18    [0, 100],  // Y = 10
19    [40, 180], // Y = 30
20];
21
22static STRICT: BilinearSurface<2, 2> = BilinearSurface::new(&X, &Y, &VALUES);
23
24static FAIL_SAFE: BilinearSurface<2, 2> = BilinearSurface::new(&X, &Y, &VALUES).with_policy(
25    BoundaryPolicy::new()
26        .with_x_below(Boundary::Error)
27        .with_x_above(Boundary::Clamp)
28        .with_y_below(Boundary::Error)
29        .with_y_above(Boundary::Clamp),
30);
31
32fn main() {
33    assert_eq!(FAIL_SAFE.policy().x_below(), Boundary::Error);
34    assert_eq!(FAIL_SAFE.policy().x_above(), Boundary::Clamp);
35    assert_eq!(FAIL_SAFE.policy().y_below(), Boundary::Error);
36    assert_eq!(FAIL_SAFE.policy().y_above(), Boundary::Clamp);
37
38    // In-domain: policy is idle.
39    assert_eq!(FAIL_SAFE.evaluate(125, 20), Ok(50));
40    assert_eq!(FAIL_SAFE.evaluate(125, 20), STRICT.evaluate(125, 20));
41
42    // Reject uncharacterized low codes.
43    assert_eq!(
44        FAIL_SAFE.evaluate(0, 20),
45        Err(SurfaceError::XBelow {
46            coordinate: 0,
47            bound: 100
48        })
49    );
50    assert_eq!(
51        FAIL_SAFE.evaluate(125, 0),
52        Err(SurfaceError::YBelow {
53            coordinate: 0,
54            bound: 10
55        })
56    );
57
58    // Hold the last characterized high edge; nothing is extrapolated.
59    assert_eq!(FAIL_SAFE.evaluate(4_000, 20), FAIL_SAFE.evaluate(200, 20));
60    assert_eq!(FAIL_SAFE.evaluate(125, 4_000), FAIL_SAFE.evaluate(125, 30));
61    assert_eq!(FAIL_SAFE.evaluate(4_000, 20), Ok(140));
62    assert_eq!(FAIL_SAFE.evaluate(125, 4_000), Ok(75));
63
64    // Both outside Error sides: X wins and Y is not reported.
65    assert_eq!(
66        STRICT.evaluate(0, 0),
67        Err(SurfaceError::XBelow {
68            coordinate: 0,
69            bound: 100
70        })
71    );
72    // X clamps, Y still errors.
73    assert_eq!(
74        FAIL_SAFE.evaluate(4_000, 0),
75        Err(SurfaceError::YBelow {
76            coordinate: 0,
77            bound: 10
78        })
79    );
80}