Designing a cyclic pressure test programme requires more than just "pressurise and depressurise repeatedly." Ramp rate, hold time, and cycle count interact with the specific fatigue mechanism being investigated. Here's the implementation approach.
Pressure Profile State Machine
from enum import Enum
import time
class TestState(Enum):
IDLE = 0
FILLING = 1
RAMPING_UP = 2
HOLDING = 3
DEPRESSURIZING = 4
CYCLE_COMPLETE = 5
TEST_COMPLETE = 6
FAULT = 7
class CyclicPressureTest:
def __init__(self, target_pressure_bar, ramp_time_s,
hold_time_s, total_cycles, depress_time_s=30):
self.target_pressure = target_pressure_bar
self.ramp_time = ramp_time_s
self.hold_time = hold_time_s
self.total_cycles = total_cycles
self.depress_time = depress_time_s
self.current_cycle = 0
self.state = TestState.IDLE
self.cycle_log = []
def calculate_ramp_setpoint(self, elapsed_s):
"""Linear ramp profile — could substitute s-curve for gentler loading"""
if elapsed_s >= self.ramp_time:
return self.target_pressure
return (elapsed_s / self.ramp_time) * self.target_pressure
def run_cycle(self, pressure_sensor_read_fn, valve_control_fn):
"""
Execute one complete pressure cycle.
pressure_sensor_read_fn: callback returning current pressure
valve_control_fn: callback to set valve position/PID output
"""
cycle_start = time.time()
cycle_data = {'cycle_num': self.current_cycle + 1, 'pressures': [], 'timestamps': []}
# RAMP UP phase
self.state = TestState.RAMPING_UP
ramp_start = time.time()
while (time.time() - ramp_start) < self.ramp_time:
elapsed = time.time() - ramp_start
setpoint = self.calculate_ramp_setpoint(elapsed)
valve_control_fn(setpoint)
actual = pressure_sensor_read_fn()
cycle_data['pressures'].append(actual)
cycle_data['timestamps'].append(time.time() - cycle_start)
time.sleep(0.1) # 10Hz sampling
# HOLD phase
self.state = TestState.HOLDING
hold_start = time.time()
while (time.time() - hold_start) < self.hold_time:
valve_control_fn(self.target_pressure)
actual = pressure_sensor_read_fn()
cycle_data['pressures'].append(actual)
cycle_data['timestamps'].append(time.time() - cycle_start)
# Check for sudden pressure drop = potential failure
if len(cycle_data['pressures']) > 5:
recent_drop = cycle_data['pressures'][-5] - actual
if recent_drop > self.target_pressure * 0.05: # 5% sudden drop
self.state = TestState.FAULT
return {'status': 'FAULT', 'reason': 'Sudden pressure drop detected',
'cycle': self.current_cycle, 'data': cycle_data}
time.sleep(0.1)
# DEPRESSURIZE phase
self.state = TestState.DEPRESSURIZING
valve_control_fn(0)
time.sleep(self.depress_time)
self.current_cycle += 1
self.cycle_log.append(cycle_data)
if self.current_cycle >= self.total_cycles:
self.state = TestState.TEST_COMPLETE
return {'status': 'TEST_COMPLETE', 'cycles_run': self.current_cycle}
self.state = TestState.CYCLE_COMPLETE
return {'status': 'CYCLE_OK', 'cycle': self.current_cycle}
Fatigue Data Analysis After Test Completion
import numpy as np
def analyze_cycle_consistency(cycle_log):
"""
Check if peak pressure and ramp time drift over the course of the test —
drift can indicate developing leaks or actuator degradation.
"""
peak_pressures = []
ramp_durations = []
for cycle in cycle_log:
peak_pressures.append(max(cycle['pressures']))
# Find time to reach 95% of target (proxy for ramp performance)
target_95 = max(cycle['pressures']) * 0.95
ramp_idx = next((i for i, p in enumerate(cycle['pressures']) if p >= target_95), None)
if ramp_idx:
ramp_durations.append(cycle['timestamps'][ramp_idx])
return {
'peak_pressure_trend': {
'mean': np.mean(peak_pressures),
'std': np.std(peak_pressures),
'first_10_mean': np.mean(peak_pressures[:10]),
'last_10_mean': np.mean(peak_pressures[-10:]),
'drift_pct': (np.mean(peak_pressures[-10:]) - np.mean(peak_pressures[:10]))
/ np.mean(peak_pressures[:10]) * 100
},
'ramp_time_trend': {
'mean_s': np.mean(ramp_durations),
'std_s': np.std(ramp_durations)
}
}
def generate_fatigue_report(component_id, cycle_log, target_pressure,
total_cycles_completed, standard='Customer-specified'):
consistency = analyze_cycle_consistency(cycle_log)
report = {
'component_id': component_id,
'test_standard': standard,
'target_pressure_bar': target_pressure,
'cycles_completed': total_cycles_completed,
'cycles_log_summary': {
'total_recorded': len(cycle_log)
},
'consistency_analysis': consistency,
'result': 'PASS' if abs(consistency['peak_pressure_trend']['drift_pct']) < 5
else 'REVIEW REQUIRED — Pressure drift detected'
}
return report
The Neometrix PLC Controlled Autoclave Pressure Tester implements this state-machine architecture for automated, unattended cyclic pressure testing with full data logging for fatigue qualification programmes.
→ https://neometrixgroup.com/products/PLC-controlled-autoclave-pressure-tester


























