Pressure Drop Rate Test on Omron CJ2M: Sampling Methods

James Nishida18 min read
CJ/CP SeriesOmronTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Overview

This reference covers the design and implementation of a pressure drop rate test on an Omron CJ2M programmable controller programmed with CX-Programmer (part of the CX-One suite). The functional requirement is the classic "X% drop in Y minutes" acceptance criterion used in hydraulic tube pressure testing and flushing. Three practical implementations are compared: a discrete shift register with point-to-point comparison, a circular buffer feeding a least-squares slope calculation, and a simple time-windowed pass/fail check. Analog scaling on the CJ1W-AD081-V1 (or AD041), signal filtering, EWMA smoothing, and CSV logging to the CJ2M SD card are addressed in detail. CX-Programmer is documented in the CX-Programmer Operation Manual (W446) and the CJ2M is described in the CJ2M CPU Unit Operation Manual (W486).

Applicable Standards and Test Definition

The pressure integrity test is defined by two parameters:

  • Allowable drop X (in percent of start pressure)
  • Time window Y (in minutes)

The test sequence is:

  1. Pressurize the test object to P_test.
  2. Hold at P_test until the system stabilises (pressure within a tolerance band, typically +/-0.5% of P_test, for a configurable dwell of 5-30 s).
  3. Close the fill valve (isolate the test object) and start the test clock.
  4. Sample pressure continuously and compare to the start value over Y minutes.
  5. Pass if pressure never falls below P_test x (1 - X/100). Fail if it does at any time.

Common customer-specific specs encountered on hydraulic tube skids include "1% drop in 5 min", "0.5% drop in 10 min", "2% drop in 15 min", "0.2% drop in 30 min". The corresponding rate-of-change limits are X/Y in %/min. Standards that may be referenced for tube pressure testing include ISO 10770 (hydraulic cylinder test methods), EN 10217 (welded steel tubes for pressure purposes), ASME B31.3 (process piping), DIN 2413 (steel pipelines), and various OEM test specifications. Always confirm the exact X, Y, and any extra dwell requirements from the governing standard or test sheet; figures here are stated as engineering examples and are not a compliance guarantee.

Hardware Selection

Item Recommended part Notes
CPU CJ2M-CPU33 or CJ2M-CPU35 Built-in EtherNet/IP, SD card slot, up to 2560 I/O
Power supply CJ1W-PA205R (5 A) or PA202 RUN output for diagnostics
Analog input CJ1W-AD081-V1 (8 ch) or AD041 (4 ch) 1/8000 resolution, 4-20 mA / 0-10 V / +/-10 V
Pressure transducer 4-20 mA, 0-600 bar, 0.25% FS or better Use lower range if X% criterion is tight
SD option Built-in on CJ2M-CPU3x; CP1W-CIF01/CIF11 for legacy units CSV logging
HMI NB7W or NS-series Trend display, recipe selection, certificate preview

For a 600 bar transducer with 1/8000 resolution, 1 LSB equals 0.075 bar. A 1% drop from a 400 bar test pressure is 4 bar, which is ~53 LSB. This is comfortable above LSB noise but, combined with the 0.25% FS transducer error of 1.5 bar, the total uncertainty is ~38% of the 1% drop budget. If the standard is 1% drop in 5 min, a 0.1% FS transducer is recommended, or the criterion relaxed to 2%.

Sampling Strategy and Anti-Aliasing

The original question proposed "one value per minute, store 5 values". This is too coarse for two reasons:

  1. A sudden leak developing in minute 3 of a 5-minute test will not be visible at the end of minute 5 unless the drop over the full window exceeds X%.
  2. Five samples is statistically insufficient to fit a slope with any confidence.

Recommended sample period T_s:

  • 1 s is a good default. For Y = 5 min the buffer holds 300 entries; for Y = 10 min, 600 entries.
  • 100 ms is preferred when X is small (<1%) and the test object is small-volume (fast pressure response to a leak).

Anti-aliasing: hydraulic pressure signals on accumulator-charged rigs have very limited spectral content above 1 Hz. The CJ1W-AD081-V1 has a built-in digital filter that can be set in the I/O table to averages of 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, or 1024 samples. At the default 1 ms conversion, 128 averages gives ~128 ms time constant, sufficient for most installations. The CJ1W-AD081-V1 Operation Manual lists the full set of averaging options.

Memory Layout in CX-Programmer

Omron memory areas relevant to this application:

Area Symbol Range Use
Data Memory D D0-D32767 Working data, recipe values, ring buffer
Holding Memory H H0-H511 Retained constants (S_x, S_xx, X, Y, P_test)
Work Memory W W0-W511 Bit-level work area, internal relays
Auxiliary Memory A A0-A959 System flags (A200+), conditional flags
Index Registers IR IR0-IR15 (32-bit) Indirect addressing for ring buffer
Task flags TK TK00-TK31 Cyclic / scheduled task control

Allocate the ring buffer in a contiguous block in D-memory, e.g. D10000-D10299 for a 300-sample buffer. Reserve D11000-D11099 for control variables (ring pointer, current sum, slope, drop percent, etc.).

Method 1 - Shift Register with First-vs-Last Comparison

This is the simplest implementation. A shift register of length N = Y / T_s holds the last N seconds of pressure samples. On each clock pulse the new sample is written and the oldest is discarded. At the end of the test, or continuously, the oldest sample is compared to the newest:

drop_pct = (P_oldest - P_newest) * 100.0 / P_test
pass     = drop_pct <= X

CX-Programmer implementation (ladder sketch):

| P_1s (1-second pulse)              --|
|   ++IR0                            --|  Increment ring pointer (IR0 = IR0 + 1)
|   CMP IR0 #N                       --|  If IR0 >= N, reset IR0 to 0
|   <                                 --|
|   MOV 0 IR0                        --|  Wrap-around
|                                    --|
|   DMOV D2000 D10000[IR0]           --|  Write current pressure into ring buffer slot
|                                    --|
|   --(P_oldest is D10000[IR0])       --|  (oldest = newest slot just overwritten)
|   --(P_newest is D2000)             --|
|   SUB D10000[IR0] D2000 D11010     --|  D11010 = P_oldest - P_newest
|   MUL D11010 #100 D11012           --|  D11012 = drop * 100
|   DIV D11012 D11001 D11014         --|  D11014 = drop_pct (D11001 = P_test * 100)
|   CMP D11014 H0                    --|  Compare drop_pct to X (stored in H0)
|   > --(FAIL)                       --|  Set FAIL latch if drop > X

Worked example for X = 1%, Y = 5 min, T_s = 1 s, P_test = 400 bar:

  • N = 300
  • drop_max = 400 x 1 / 100 = 4 bar
  • After 300 s, D10000[IR0] is the oldest sample; difference to newest must be <= 4 bar.

Limitations:

  • Only the endpoints are checked. A short transient dip between samples can be missed.
  • A single noisy sample can corrupt the result.
  • The block-move (XFER) approach of literally shifting all entries takes ~300 word-moves per second; on a CJ2M the XFER instruction handles 1000 words per scan, so a 300-word shift uses ~0.3 ms of scan time. Acceptable for a 100 ms cycle.

Method 2 - Circular Buffer with Least-Squares Slope

To address noise, fit a straight line through the last N samples and compare the slope to the allowed rate X/Y %/min. The least-squares fit naturally smooths outlier samples.

For data points (x_i, y_i), i = 0..N-1 with constant spacing T_s so x_i = i x T_s:

S_x  = sum(x_i)        = T_s * N*(N-1)/2
S_xx = sum(x_i^2)      = T_s^2 * (N-1)*N*(2N-1)/6
S_y  = sum(y_i)        (running sum)
S_xy = sum(x_i * y_i)  (running sum)

slope m      = (N*S_xy - S_x*S_y) / (N*S_xx - S_x^2)
intercept b  = (S_y - m*S_x) / N

rate_pct_min = -m * 100 / P_test * 60
pass         = rate_pct_min <= X / Y

Because T_s is constant, S_x and S_xx are precomputed constants stored in H-memory:

  • For N = 300, T_s = 1.0: S_x = 44850, S_xx = 4 474 550
  • For N = 600, T_s = 1.0: S_x = 179700, S_xx = 7.197 x 10^7

Running sum updates on each new sample y_new replacing y_old:

S_y  = S_y  + y_new - y_old
S_xy = S_xy + (newest_index * T_s) * y_new - (oldest_index * T_s) * y_old

Slope calculation per sample: ~10 FP operations. On a CJ2M, single-precision FP multiply takes ~1 us, division ~5 us. The full update fits in <50 us, well within a 1 s sample period. Use the REAL data type and floating-point instructions (instructions documented in CX-Programmer Operation Manual W446, section on arithmetic instructions).

ST code (CJ2M supports ST via task program type):

(* Rising edge of 1-s pulse *)
IF P_1s_Rising THEN
    (* Save oldest value before overwriting *)
    y_old := PressureBuf[RingPtr];
    (* Write new sample *)
    PressureBuf[RingPtr] := Pressure_Real;
    (* Advance ring pointer modulo N *)
    RingPtr := (RingPtr + 1) MOD N;
    (* Update running sums *)
    S_y  := S_y  + Pressure_Real - y_old;
    S_xy := S_xy + (RingPtr * T_s) * Pressure_Real - ((RingPtr - 1) * T_s) * y_old;
    (* Compute slope; constants S_x and S_xx are pre-stored in H-memory *)
    slope := (N * S_xy - S_x * S_y) / (N * S_xx - S_x * S_x);
    (* Convert to %/min *)
    RatePctMin := -slope * 100.0 / P_test * 60.0;
END_IF;

Optional refinement: compute the standard deviation of residuals sigma = sqrt(sum((y_i - m*x_i - b)^2) / (N-2)). If sigma exceeds a threshold (e.g. 1% of P_test), the data is too noisy for a reliable slope and the test should be flagged as indeterminate rather than pass/fail. This prevents false failures from electrical noise.

Method 3 - Simple Time-Windowed Pass/Fail

For a basic pass/no-pass quality test, no curve analysis is needed. The simplest correct implementation is:

  1. At the start of the test, latch P_start = current pressure.
  2. Start a timer of duration Y (in 0.1 s ticks: SV = Y x 600).
  3. On every scan, compute drop_pct = (P_start - P_current) x 100 / P_start.
  4. If drop_pct > X at any time, set the FAIL latch and stop the timer.
  5. If the timer completes without exceeding X, set the PASS latch.

CX-Programmer ladder for the test window:

| TestActive (W0.00)                 --|
|  TIM 0001 #6000                    --|  600.0 s = 10 min (0.1 s time base)
|                                    --|
|  --(TestActive AND P_Valid)        --|  Only check when actively testing
|  SUB P_start P_current D11020      --|  drop in bar
|  MUL D11020 #100 D11022            --|  * 100
|  DIV D11022 P_start_scaled D11024  --|  / P_test * 100
|  CMP D11024 H0                     --|  vs X (in H0)
|  >  --(KEEP W1.00)                 --|  Latch FAIL
|  <= --(KEEP W1.01 when TIM done)   --|  Latch PASS

Why this is often the right answer: the standard does not care about the rate of change during the window, only the cumulative drop at the end. A timer with continuous comparison is the most defensible from an audit perspective: the pass/fail decision is a single comparison at the end of a defined interval, the drop curve is fully reconstructible from the log, and the test logic is obvious to a third-party inspector. Methods 1 and 2 add value when you need early detection of a leak (e.g. to stop the test early and not waste time on a clearly failing part) or when noise makes the simple comparison unreliable.

Signal Filtering: EWMA and Median

For noisy installations, apply an Exponentially Weighted Moving Average (EWMA) filter to the raw pressure reading before any drop calculation:

Y_n = Y_{n-1} + (1/k) * (X_n - Y_{n-1})

This is a first-order IIR low-pass filter with:

  • Time constant tau = k x T_s (in seconds)
  • -3 dB cutoff f_c = 1 / (2*pi*tau)

For T_s = 1 s and a desired time constant of 5 s, use k = 5. For more aggressive filtering, k = 20 gives tau = 20 s. Note that excessive filtering will slow the response to real pressure changes, potentially delaying a fail decision. Tune empirically against a known leak source.

k tau (s) f_c (Hz) Use case
1 1 0.159 Light smoothing, fast response
5 5 0.032 Typical for 1% drop in 5 min
20 20 0.008 Heavy smoothing for very low-noise applications

Alternative: median-of-3 or median-of-5 filter. Rejects single-sample spikes with less lag than EWMA. On a CJ2M, sort 3 or 5 consecutive samples and pick the middle value. Cost: 5 compare-and-swap operations per sample, <10 us. Median-3 is a good companion to EWMA: median first to kill spikes, EWMA second to smooth broadband noise.

Analog I/O Configuration in CX-Programmer

  1. Open the I/O Table and add the CJ1W-AD081-V1 to the slot. The first input word of slot 0 is CIO 2000 (8 words for AD081).
  2. Double-click the module and set the input range per channel. For a 4-20 mA pressure transducer, select "4-20 mA" on the relevant channels.
  3. Set the averaging count to 64 or 128. The CJ1W-AD081-V1 Operation Manual lists the available averages.
  4. Scale the raw input to engineering units. For 1/8000 resolution with 4-20 mA selected, the raw value is 0 to 4000 for 0-100% of range. For a 0-600 bar transducer: P_bar = raw * 600 / 4000 = raw * 0.15. Use the SCL2 (scaling) or APR (arithmetic processing) instruction, documented in CX-Programmer manual W446.
  5. Store the scaled pressure in REAL (32-bit float) in D-memory, e.g. D2000-D2001 for the float representation of pressure in bar.

Data Logging to SD Card

Options for logging the drop curve:

  1. SD card on CJ2M-CPU3x: the built-in SD slot accepts standard SD/SDHC cards. Use the FWRIT instruction to write records to a CSV file. The CJ2M CPU Unit Operation Manual (W486) documents the SD card file handling instructions and their limit of 512 bytes per write, so a single CSV line must be formatted to fit.
  2. FTP via built-in Ethernet (CJ2M-CPU3x): write CSV to a remote FTP server using the FTP client instructions. Cleaner for networked production lines.
  3. HMI-side logging: NB7W and NS-series HMIs can log trend data and recipes to USB/SD natively, offloading the storage task from the PLC.
  4. External DAQ triggered by PLC: a dedicated DAQ system (e.g. National Instruments, Beckhoff) provides the highest sample rate and best post-processing tools. The PLC only sends a start/stop trigger.

Recommended CSV format:

TIMESTAMP,PRESSURE_BAR,STATE
2024-01-15T10:30:00,400.21,STABILIZE
2024-01-15T10:30:01,400.18,STABILIZE
2024-01-15T10:30:30,400.05,TEST_START
2024-01-15T10:30:31,400.04,TEST
2024-01-15T10:30:32,400.02,TEST
... (one row per second during test)
2024-01-15T10:35:30,398.50,TEST_PASS
or
2024-01-15T10:32:15,395.10,TEST_FAIL

The STATE column lets the certificate generator identify phases. For the test phase, log every 1 s. For the stabilise phase, every 5-10 s is sufficient. Total log size for a 5-min test at 1 Hz is ~25 KB; for an 8-hour shift of 96 tests, ~2.4 MB. A 4 GB SD card holds years of data.

Stabilization Phase Logic

A common failure mode is "test fails immediately at start" because the system has not yet stabilised. Add a separate pre-test phase:

  1. Pressurize to P_test.
  2. Wait for pressure to enter the band [P_test - 0.5%, P_test + 0.5%].
  3. Start a stabilisation dwell timer (e.g. 10 s).
  4. If the pressure leaves the band during the dwell, restart the dwell timer.
  5. When the dwell completes cleanly, latch P_start and start the test phase.

This logic is implemented in a few rungs of ladder using the TT (timer timing) and IN (timer running) flags, or in a single function block with a state machine. The dwell is essential for tests that fill through a manual valve or for objects that warm up under pressurisation (thermal expansion of gas over oil).

Scan Time and Cycle Budget

For a 1 s sample period the cycle budget is generous. Approximate timings on a CJ2M-CPU33 (typical instruction execution times, see CJ2M manual W486):

Task Instruction count Time
Analog read + scale ~20 <0.05 ms
EWMA filter ~10 <0.02 ms
Ring buffer update ~10 <0.02 ms
Running sum update ~15 <0.03 ms
Slope calculation ~20 <0.05 ms
Pass/fail decision ~10 <0.02 ms
CSV format + FWRIT ~50 ~0.5 ms (file I/O dominates)
Total per second ~135 <1 ms

There is no scan-time concern for this application. Even at 100 ms sample period, the logic is well within budget.

Verification and Commissioning

  1. Static accuracy: with the test object pressurised to 0, 25, 50, 75, and 100% of full scale, verify the scaled engineering value matches a calibrated reference gauge (0.05% FS or better) within +/-0.25% FS.
  2. Dynamic test: induce a controlled leak of 0.5% of test volume per 5 min via a needle valve, verify the system correctly flags FAIL within one sample period of the threshold being crossed.
  3. Noise test: install a known noise source (e.g. a small pump on a separate circuit) and verify the filter attenuates it to within the analog resolution.
  4. Edge case: at very low test pressures (e.g. 50 bar with a 1% criterion = 0.5 bar), the analog resolution and transducer accuracy become limiting. Either use a lower-range transducer or relax the criterion to 2%.
  5. Long-duration soak: a 30-min test on a known-good object should pass cleanly. If it intermittently fails, suspect thermal drift, transducer zero drift, or air dissolved in the hydraulic fluid.
  6. Power-loss recovery: kill power mid-test and restore. Verify the controller enters a safe state (test paused, valves vented) and requires operator acknowledgement to resume. The CJ2M manual W486 describes the IOM (I/O Memory) hold behaviour and how to configure it.

Troubleshooting Matrix

Symptom Likely cause Action
Test fails immediately at start Pressure not yet stabilised; transient drop exceeds X% Add pre-test stabilisation phase; only start timer when pressure is within band for N seconds
Test passes incorrectly Filter time constant too long Reduce k in EWMA or remove filter
Test fails intermittently with passing transducers Transducer noise exceeding 1% Apply EWMA filter; check cabling, shielding, and grounding per CJ1W-AD081-V1 manual
Slope calculation gives wildly different result than pass/fail Buffer pointer wraparound bug Verify IR0 wraps correctly modulo N; use the MOD instruction
PLC scan time too long for 100 ms sample period Block-move instruction in main loop Move shift register to scheduled task or interrupt task
CSV file truncated SD card full or power loss Implement ring buffer; reduce sample rate for long logs; use FWRIT flush after each line
Drop curve shows step changes Stuck transducer or wiring fault Add sanity check: reject sample if rate of change > 5*X% per sample
Slope test passes but timer test fails Slope averaged over a period that smooths out a sudden leak Use max single-sample drop check in addition to slope
Different result on CJ2M-CPU15 vs CPU33 Floating-point instruction set differences Verify FPU option board is present on CPU15; CPU33 has FPU built-in

Notes on Alternative Controllers

The same techniques apply to other Omron families with minor differences:

  • CP1H / CP1L: same instructions, but D-memory is smaller (D0-D9999 on CP1L, D0-D32767 on CP1H). CP1L does not have built-in Ethernet; add CP1W-CIF01/CIF11 for serial or CP1W-CIF41 for Ethernet.
  • NJ/NX: the NJ101, NJ301, and NX102 controllers use Sysmac Studio and ladder / ST programming on a Codesys-based runtime. Floating-point and ring buffers are first-class; the EWMA and LSF code translates directly to ST.
  • CS1 / CJ1 (legacy): same instruction set as CJ2M but slower floating-point. The CJ1W-AD081-V1 analog module is identical. Suitable for retrofit of older systems.

For non-Omron controllers (Allen-Bradley CompactLogix, Siemens S7-1200, etc.), the algorithmic content is identical; only the instruction names and memory area naming change.

FAQ

What is the minimum sample rate for a 1% drop in 5 min test?

For the shift-register first-vs-last method, sample at 1 s minimum (300-entry buffer for a 5-min window). For the least-squares slope method, 1 s also works; the 300-sample buffer provides enough statistical power to reject individual noisy samples. For the simple timer pass/fail method, sample at the controller scan rate (typically 1-10 ms) so the fail condition is detected within one scan of being crossed.

Can I use the built-in PID on the CJ2M for this?

No. PID is for closed-loop control driving an actuator to a setpoint. The pressure drop test is open-loop monitoring after a pressure setpoint has been reached and the fill valve is closed; PID is not the right tool. The CJ2M PID instructions (PID, PIDAT) are documented in CX-Programmer manual W446 but should not be used for this application.

Should I use floating-point or integer math?

Use REAL (IEEE 754 single-precision) for the slope calculation and EWMA filter, because the constants S_x and S_xx and intermediate products are large for a 300-sample window (S_x = 44850, S_xx = 4474550 for N=300, T_s=1). Integer math overflows at 16 bits. The CJ2M supports REAL natively; on the older CJ2M-CPU11/12/13/14/15, ensure the FPU option board (CP1W-FPU01) is installed, otherwise floating-point instructions take 100x longer via software emulation.

How do I handle multiple test standards with different X and Y values?

Store X and Y as operator-set values in H-memory or recipe D-memory, populated from the HMI. The same logic runs with different parameters loaded from a recipe selection on the HMI. Pre-compute the constants S_x and S_xx for the maximum Y value, and use a fixed N; for shorter Y, the slope test still works because the slope is independent of the window size used in its calculation.

Does CX-Programmer support circular buffers natively?

No explicit data structure. The combination of indirect addressing via IR0-IR15 and modulo arithmetic on the index register implements a circular buffer cleanly. The pattern is: increment IR0, compare to N, reset to 0 on overflow, then use IR0 as the offset for the buffer write. Watch the wraparound boundary carefully - a bug here will overwrite the wrong sample and corrupt the slope for the entire next window. Test the wraparound explicitly during commissioning by forcing IR0 to N-1 and observing the next-step behaviour.

How accurate is my pressure drop measurement really?

Three error sources stack: analog input resolution (1 LSB = 0.075 bar at 1/8000 with a 600 bar transducer), transducer accuracy (0.25% FS = 1.5 bar), and temperature drift (~0.02% FS / K = 0.12 bar per 10 K). Combined RSS uncertainty is ~1.5 bar. For a 1% drop criterion at 400 bar (4 bar), this is a 38% measurement uncertainty. If the standard requires this criterion, upgrade to a 0.1% FS transducer (uncertainty ~0.6 bar) and enable the 1024-sample average on the AD081 (reduces noise by ~30x). Otherwise, relax the criterion to 2%.

Can the same code run on a CJ1, CS1, or CP1 series?

Yes - the instruction set is largely compatible across CJ1/CS1/CJ2M/CP1 series. Memory area naming and a few instruction mnemonics differ slightly; see the migration notes in the CJ2M manual W486 for the full list. The CJ1W-AD081 analog module works in any of these racks. Floating-point performance is the main difference: a CJ1H-CPU67 with FPU is comparable to a CJ2M-CPU33, while a CJ1M-CPU12/13 needs the FPU option board for acceptable FP performance.

Back to blog