Skip to content

Commit 4d7739e

Browse files
feat: implement Stability Indicator subsystem and bump version to 3.3.0
- Bumped version to 3.3.0 across all configs, headers, and docs. - Added `include/raps/safety/stability_indicator.hpp` implementing S_u, hysteresis, and maneuver-aware thresholds. - Added SIL unit tests for stability indicator and version consistency. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent fb27130 commit 4d7739e

12 files changed

Lines changed: 370 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ All notable changes to HLV-RAPS are documented in this file.
2424
- Fix broken include paths in `advanced_propulsion_control_unit.hpp`
2525

2626
### Maintainability
27-
- Add `VERSION` file (`3.2.0`)
27+
- Add `VERSION` file (`3.3.0`)
2828
- Add `CHANGELOG.md`
2929
- Add `RAPSVersion` namespace constants to `raps_core_types.hpp`
3030
- Update REST API health endpoint to use `RAPSVersion::STRING`

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.2.0
1+
3.3.0

docs/TELEMETRY_DASHBOARD.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Future v3.3+ may add a richer HTML visualization, but only after trust is earned
9191

9292
---
9393

94-
# RAPS v3.2.0 — Telemetry & Observability Layer
94+
# RAPS v3.3.0 — Telemetry & Observability Layer
9595

9696
This release introduces a **production-hardened, read-only telemetry layer** for RAPS.
9797

docs/contracts/TELEMETRY_STORAGE_CONTRACT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ Before deployment, verify:
235235

236236
This contract is versioned and maintained alongside RAPS releases.
237237

238-
**Current version**: 1.0 (RAPS v3.2.0)
238+
**Current version**: 1.0 (RAPS v3.3.0)
239239

240240
**Change policy**:
241241
- Breaking changes require major version bump

examples/hil/hil_main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ int main() {
123123
telemetry_sink.open((run_dir + "/telemetry.jsonl").c_str());
124124

125125
raps::telemetry::TelemetryMetadata meta;
126-
meta.raps_version = "2.3.0";
126+
meta.raps_version = "3.3.0";
127127
meta.telemetry_schema = "1.0";
128128
meta.build_type = "HIL";
129129
meta.notes = "HIL loopback bring-up";

examples/sil/sil_main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ int main() {
3838
telemetry_sink.open((run_dir + "/telemetry.jsonl").c_str());
3939

4040
raps::telemetry::TelemetryMetadata meta;
41-
meta.raps_version = "2.3.0";
41+
meta.raps_version = "3.3.0";
4242
meta.telemetry_schema = "1.0";
4343
meta.build_type = "SIL";
4444
meta.notes = "SIL deterministic timing harness";

include/raps/core/raps_core_types.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ struct RollbackPlan {
133133
// =====================================================
134134

135135
namespace RAPSVersion {
136-
constexpr uint32_t MAJOR = 2;
137-
constexpr uint32_t MINOR = 4;
136+
constexpr uint32_t MAJOR = 3;
137+
constexpr uint32_t MINOR = 3;
138138
constexpr uint32_t PATCH = 0;
139-
constexpr const char* STRING = "2.4.0";
139+
constexpr const char* STRING = "3.3.0";
140140
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#pragma once
2+
3+
#include <cmath>
4+
#include <cstdint>
5+
#include <iostream>
6+
7+
// =====================================================
8+
// HLV-RAPS Stability Indicator Upgrade (v3.3.0)
9+
// =====================================================
10+
11+
namespace StabilityConfig {
12+
13+
enum class ManeuverClass {
14+
CRUISE,
15+
MILD_MANEUVER,
16+
AGGRESSIVE_MANEUVER
17+
};
18+
19+
struct Thresholds {
20+
double S_u_min;
21+
double S_u_warn;
22+
double S_u_rate_limit;
23+
};
24+
25+
constexpr Thresholds CRUISE_THRESHOLDS = {0.82, 0.86, 0.015};
26+
constexpr Thresholds MILD_THRESHOLDS = {0.78, 0.83, 0.025};
27+
constexpr Thresholds AGGRESSIVE_THRESHOLDS = {0.72, 0.78, 0.040};
28+
29+
inline constexpr Thresholds get_thresholds(ManeuverClass mclass) {
30+
switch (mclass) {
31+
case ManeuverClass::MILD_MANEUVER:
32+
return MILD_THRESHOLDS;
33+
case ManeuverClass::AGGRESSIVE_MANEUVER:
34+
return AGGRESSIVE_THRESHOLDS;
35+
case ManeuverClass::CRUISE:
36+
default:
37+
return CRUISE_THRESHOLDS;
38+
}
39+
}
40+
41+
} // namespace StabilityConfig
42+
43+
// =====================================================
44+
// DSM Integration
45+
// =====================================================
46+
47+
enum class DSMFlagType {
48+
NONE = 0,
49+
SU_LOW = 1,
50+
SU_RATE_VIOLATION = 2,
51+
SU_HYSTERESIS_TRANSITION = 3
52+
};
53+
54+
struct DSMEvent {
55+
uint32_t timestamp;
56+
StabilityConfig::ManeuverClass maneuver_class;
57+
double S_u;
58+
double dS_u_dt;
59+
DSMFlagType flag_type;
60+
};
61+
62+
// =====================================================
63+
// Stability Indicator Core
64+
// =====================================================
65+
66+
class StabilityIndicator {
67+
public:
68+
StabilityIndicator()
69+
: last_S_u_(1.0),
70+
last_timestamp_(0),
71+
is_safe_mode_(true),
72+
initialized_(false) {}
73+
74+
// Pure mathematical computation of S_u
75+
// S_u = 1 / (1 + phi^2 + chi^3)
76+
static double compute_Su(double phi, double chi) {
77+
double phi_sq = phi * phi;
78+
double chi_cu = chi * chi * chi;
79+
return 1.0 / (1.0 + phi_sq + chi_cu);
80+
}
81+
82+
// Logging hook (purely deterministic and side-effect free besides console out for simulation)
83+
static DSMEvent emit_dsm_event(
84+
uint32_t timestamp,
85+
StabilityConfig::ManeuverClass mclass,
86+
double S_u,
87+
double dS_u_dt,
88+
DSMFlagType flag_type) {
89+
90+
DSMEvent event = {timestamp, mclass, S_u, dS_u_dt, flag_type};
91+
// In a real system, this might push to a queue. For now, it returns the struct.
92+
return event;
93+
}
94+
95+
// Stateful wrapper
96+
DSMEvent update_stability_state(
97+
uint32_t timestamp,
98+
StabilityConfig::ManeuverClass mclass,
99+
double phi,
100+
double chi) {
101+
102+
double current_S_u = compute_Su(phi, chi);
103+
double dS_u_dt = 0.0;
104+
105+
auto thresholds = StabilityConfig::get_thresholds(mclass);
106+
DSMFlagType flag_out = DSMFlagType::NONE;
107+
108+
if (initialized_ && timestamp > last_timestamp_) {
109+
double dt = static_cast<double>(timestamp - last_timestamp_);
110+
dS_u_dt = (current_S_u - last_S_u_) / dt;
111+
112+
if (std::abs(dS_u_dt) > thresholds.S_u_rate_limit) {
113+
flag_out = DSMFlagType::SU_RATE_VIOLATION;
114+
}
115+
}
116+
117+
// Hysteresis State Machine
118+
// EnterSafe: S_u >= S_u_warn
119+
// ExitSafe: S_u <= S_u_min
120+
bool transitioned = false;
121+
if (!is_safe_mode_) {
122+
if (current_S_u >= thresholds.S_u_warn) {
123+
is_safe_mode_ = true;
124+
transitioned = true;
125+
}
126+
} else {
127+
if (current_S_u <= thresholds.S_u_min) {
128+
is_safe_mode_ = false;
129+
transitioned = true;
130+
}
131+
}
132+
133+
if (transitioned && flag_out == DSMFlagType::NONE) {
134+
flag_out = DSMFlagType::SU_HYSTERESIS_TRANSITION;
135+
}
136+
137+
if (!is_safe_mode_ && flag_out == DSMFlagType::NONE) {
138+
// If we are currently unsafe but haven't triggered another flag,
139+
// we emit SU_LOW to indicate pre-safing boundary violation.
140+
if (current_S_u <= thresholds.S_u_min) {
141+
flag_out = DSMFlagType::SU_LOW;
142+
}
143+
}
144+
145+
// State update
146+
last_S_u_ = current_S_u;
147+
last_timestamp_ = timestamp;
148+
initialized_ = true;
149+
150+
return emit_dsm_event(timestamp, mclass, current_S_u, dS_u_dt, flag_out);
151+
}
152+
153+
bool is_safe() const { return is_safe_mode_; }
154+
155+
private:
156+
double last_S_u_;
157+
uint32_t last_timestamp_;
158+
bool is_safe_mode_;
159+
bool initialized_;
160+
};

include/raps/telemetry/telemetry_metadata.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ inline void json_escape(FILE* f, const char* s) noexcept {
8383
// All fields are optional; empty strings are omitted.
8484
//
8585
struct TelemetryMetadata final {
86-
std::string raps_version; // e.g. "2.3.0"
86+
std::string raps_version; // e.g. "3.3.0"
8787
std::string telemetry_schema; // e.g. "1.0"
8888
std::string git_commit; // optional
8989
std::string build_type; // Debug / Release

tests/sil/CMakeLists.txt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,37 @@ add_test(
129129
NAME raps_sil_rollback_test
130130
COMMAND raps_sil_rollback_tests
131131
)
132+
133+
# ------------------------------------------------------------
134+
# Version Tests
135+
# ------------------------------------------------------------
136+
add_executable(raps_sil_version_tests
137+
test_version.cpp
138+
)
139+
140+
target_include_directories(raps_sil_version_tests PRIVATE
141+
${PROJECT_SOURCE_DIR}/../../include
142+
${PROJECT_SOURCE_DIR}/../../src
143+
)
144+
145+
add_test(
146+
NAME raps_sil_version_test
147+
COMMAND raps_sil_version_tests
148+
)
149+
150+
# ------------------------------------------------------------
151+
# Stability Indicator Tests
152+
# ------------------------------------------------------------
153+
add_executable(raps_sil_stability_tests
154+
test_stability_indicator.cpp
155+
)
156+
157+
target_include_directories(raps_sil_stability_tests PRIVATE
158+
${PROJECT_SOURCE_DIR}/../../include
159+
${PROJECT_SOURCE_DIR}/../../src
160+
)
161+
162+
add_test(
163+
NAME raps_sil_stability_test
164+
COMMAND raps_sil_stability_tests
165+
)

0 commit comments

Comments
 (0)