I have a function that monitors a controlled signal by applying a simple check whether the signal is within a given tolerance band. The function is called is_within_limits
. I have a second function called is_within_expanded_limits
that does the same but applies an expansion factor (widens the tolerance band) to the configured limits beforehand. The limits are configured in monitor.config
by means of a target value and a maximum deviation from that value or lower and upper thresholds. The enumeration monitor.config.monitoring_mode
specifies how the valid range is specified.
Have a look at the code first.
Specification
subtype Float_Signed1000 is Float range -1_000.0 .. 1_000.0;
subtype Float_Signed10000 is Float range -10_000.0 .. 10_000.0;
type Monitor_Config_T is record
monitoring_mode : Monitoring_Mode_T := mean_based;
mean : Float_Signed1000 := 0.0;
maximum_deviation : Float range Float'Small .. 1_000.0 := 100.0e-3;
lower_threshold : Float_Signed1000 := -100.0e-3;
upper_threshold : Float_Signed1000 := 100.0e-3;
settling_tolerance_expansion : Float range (1.0 + Float'Small) .. 2.0 := 1.2;
startup_time : Time_Span := Milliseconds (5);
settling_time : Time_Span := Milliseconds (2);
violation_time : Time_Span := Milliseconds (5);
retry_time : Time_Span := Milliseconds (100);
end record;
type Monitor_T is record
config : Monitor_Config_T;
timer : Time_Span := Milliseconds (0);
current_state : Monitor_State_T := reset;
next_state : Monitor_State_T := reset;
end record;
function is_within_expanded_limits (monitor : in Monitor_T;
signal_value : in Float_Signed1000)
return Boolean
with Pre => (if monitor.config.monitoring_mode = mean_based then
monitor.config.maximum_deviation > 0.0)
and then (if monitor.config.monitoring_mode = threshold_based then
monitor.config.lower_threshold <
monitor.config.upper_threshold)
and then monitor.config.settling_tolerance_expansion > 1.0;
Implementation
function is_within_expanded_limits (monitor : in Monitor_T;
signal_value : in Float_Signed1000)
return Boolean is
within_expanded_limits : Boolean := False;
expanded_lower_threshold : Float Float_Signed10000;
expanded_upper_threshold : Float Float_Signed10000;
begin
case monitor.config.monitoring_mode is
when mean_based =>
if abs (monitor.config.mean - signal_value) <=
(monitor.config.maximum_deviation *
monitor.config.settling_tolerance_expansion) then
within_expanded_limits := True;
end if;
when threshold_based =>
-- Added due to recommendation by Jacob Sparre Andersen
-- Assertion is proved successfully
-- pragma Assert (monitor.config.lower_threshold < monitor.config.upper_threshold);
-- Added due to recommendation by Martin Becker
-- Adding this assumption still causes the assertion to fail
-- pragma Assume (monitor.config.lower_threshold = 10.0);
-- Adding this assumption still causes the assertion to fail
-- pragma Assume (monitor.config.upper_threshold = 11.0);
-- Replacing the assumption with this one results in the assertion being proved
-- pragma Assume (monitor.config.upper_threshold = 20.0);
-- Calculate expanded thresholds
if monitor.config.lower_threshold >= 0.0 then
expanded_lower_threshold := monitor.config.lower_threshold /
monitor.config.settling_tolerance_expansion;
else
expanded_lower_threshold := monitor.config.lower_threshold *
monitor.config.settling_tolerance_expansion;
end if;
if monitor.config.upper_threshold >= 0.0 then
expanded_upper_threshold := monitor.config.upper_threshold *
monitor.config.settling_tolerance_expansion;
else
expanded_upper_threshold := monitor.config.upper_threshold /
monitor.config.settling_tolerance_expansion;
end if;
-- @TODO why does this assertion fail?
pragma Assert (expanded_lower_threshold < expanded_upper_threshold);
-- Check limits with expanded thresholds
if signal_value >= expanded_lower_threshold and signal_value <=
expanded_upper_threshold then
within_expanded_limits := True;
end if;
end case;
return within_expanded_limits;
end is_within_expanded_limits;
My problem is that the assertion pragma Assert (expanded_lower_threshold < expanded_upper_threshold)
is marked as might fail and I don't understand why. I added that assertion to check that my code does nothing weird like inverting the relation of lower and upper threshold but primarily to try out assertions. The precondition monitor.config.lower_threshold < monitor.config.upper_threshold
in conjunction with the code that calculates expanded_lower_threshold
and expanded_upper_threshold
should guarantee that the assertion always holds true. Where is the problem and how can I fix it?