{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreidrshihfcklt7cs7mnkcwjiwd7emkthjzwwpk6mv5lcaquqm6zoaa",
"uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3moz7qjroeu72"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreiacnlvas4vhw275zieifa7z3rus2or5advdh72mquydb4v6i53sb4"
},
"mimeType": "image/webp",
"size": 86972
},
"path": "/robinyadav8180/plc-based-cyclic-pressure-test-sequencing-profile-design-and-fatigue-data-analysis-304g",
"publishedAt": "2026-06-24T05:34:36.000Z",
"site": "https://dev.to",
"tags": [
"engineering",
"automation",
"python",
"testing",
"https://neometrixgroup.com/products/PLC-controlled-autoclave-pressure-tester"
],
"textContent": "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.\n\n## Pressure Profile State Machine\n\n\n from enum import Enum\n import time\n\n class TestState(Enum):\n IDLE = 0\n FILLING = 1\n RAMPING_UP = 2\n HOLDING = 3\n DEPRESSURIZING = 4\n CYCLE_COMPLETE = 5\n TEST_COMPLETE = 6\n FAULT = 7\n\n class CyclicPressureTest:\n def __init__(self, target_pressure_bar, ramp_time_s,\n hold_time_s, total_cycles, depress_time_s=30):\n self.target_pressure = target_pressure_bar\n self.ramp_time = ramp_time_s\n self.hold_time = hold_time_s\n self.total_cycles = total_cycles\n self.depress_time = depress_time_s\n self.current_cycle = 0\n self.state = TestState.IDLE\n self.cycle_log = []\n\n def calculate_ramp_setpoint(self, elapsed_s):\n \"\"\"Linear ramp profile ā could substitute s-curve for gentler loading\"\"\"\n if elapsed_s >= self.ramp_time:\n return self.target_pressure\n return (elapsed_s / self.ramp_time) * self.target_pressure\n\n def run_cycle(self, pressure_sensor_read_fn, valve_control_fn):\n \"\"\"\n Execute one complete pressure cycle.\n pressure_sensor_read_fn: callback returning current pressure\n valve_control_fn: callback to set valve position/PID output\n \"\"\"\n cycle_start = time.time()\n cycle_data = {'cycle_num': self.current_cycle + 1, 'pressures': [], 'timestamps': []}\n\n # RAMP UP phase\n self.state = TestState.RAMPING_UP\n ramp_start = time.time()\n while (time.time() - ramp_start) < self.ramp_time:\n elapsed = time.time() - ramp_start\n setpoint = self.calculate_ramp_setpoint(elapsed)\n valve_control_fn(setpoint)\n actual = pressure_sensor_read_fn()\n cycle_data['pressures'].append(actual)\n cycle_data['timestamps'].append(time.time() - cycle_start)\n time.sleep(0.1) # 10Hz sampling\n\n # HOLD phase\n self.state = TestState.HOLDING\n hold_start = time.time()\n while (time.time() - hold_start) < self.hold_time:\n valve_control_fn(self.target_pressure)\n actual = pressure_sensor_read_fn()\n cycle_data['pressures'].append(actual)\n cycle_data['timestamps'].append(time.time() - cycle_start)\n\n # Check for sudden pressure drop = potential failure\n if len(cycle_data['pressures']) > 5:\n recent_drop = cycle_data['pressures'][-5] - actual\n if recent_drop > self.target_pressure * 0.05: # 5% sudden drop\n self.state = TestState.FAULT\n return {'status': 'FAULT', 'reason': 'Sudden pressure drop detected',\n 'cycle': self.current_cycle, 'data': cycle_data}\n time.sleep(0.1)\n\n # DEPRESSURIZE phase\n self.state = TestState.DEPRESSURIZING\n valve_control_fn(0)\n time.sleep(self.depress_time)\n\n self.current_cycle += 1\n self.cycle_log.append(cycle_data)\n\n if self.current_cycle >= self.total_cycles:\n self.state = TestState.TEST_COMPLETE\n return {'status': 'TEST_COMPLETE', 'cycles_run': self.current_cycle}\n\n self.state = TestState.CYCLE_COMPLETE\n return {'status': 'CYCLE_OK', 'cycle': self.current_cycle}\n\n\n## Fatigue Data Analysis After Test Completion\n\n\n import numpy as np\n\n def analyze_cycle_consistency(cycle_log):\n \"\"\"\n Check if peak pressure and ramp time drift over the course of the test ā\n drift can indicate developing leaks or actuator degradation.\n \"\"\"\n peak_pressures = []\n ramp_durations = []\n\n for cycle in cycle_log:\n peak_pressures.append(max(cycle['pressures']))\n # Find time to reach 95% of target (proxy for ramp performance)\n target_95 = max(cycle['pressures']) * 0.95\n ramp_idx = next((i for i, p in enumerate(cycle['pressures']) if p >= target_95), None)\n if ramp_idx:\n ramp_durations.append(cycle['timestamps'][ramp_idx])\n\n return {\n 'peak_pressure_trend': {\n 'mean': np.mean(peak_pressures),\n 'std': np.std(peak_pressures),\n 'first_10_mean': np.mean(peak_pressures[:10]),\n 'last_10_mean': np.mean(peak_pressures[-10:]),\n 'drift_pct': (np.mean(peak_pressures[-10:]) - np.mean(peak_pressures[:10]))\n / np.mean(peak_pressures[:10]) * 100\n },\n 'ramp_time_trend': {\n 'mean_s': np.mean(ramp_durations),\n 'std_s': np.std(ramp_durations)\n }\n }\n\n def generate_fatigue_report(component_id, cycle_log, target_pressure,\n total_cycles_completed, standard='Customer-specified'):\n consistency = analyze_cycle_consistency(cycle_log)\n\n report = {\n 'component_id': component_id,\n 'test_standard': standard,\n 'target_pressure_bar': target_pressure,\n 'cycles_completed': total_cycles_completed,\n 'cycles_log_summary': {\n 'total_recorded': len(cycle_log)\n },\n 'consistency_analysis': consistency,\n 'result': 'PASS' if abs(consistency['peak_pressure_trend']['drift_pct']) < 5\n else 'REVIEW REQUIRED ā Pressure drift detected'\n }\n return report\n\n\nThe 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.\nā https://neometrixgroup.com/products/PLC-controlled-autoclave-pressure-tester",
"title": "PLC-Based Cyclic Pressure Test Sequencing: Profile Design and Fatigue Data Analysis"
}