S7-1200 Peak Detection: Finding Max Values from Analog Sensors
Capturing the maximum value reached by an analog sensor on a SIMATIC S7-1200 PLC is a recurring requirement in machine building: an accelerometer measuring peak shock on a press, a load cell capturing spike forces on a stamping die, a pressure sensor recording water hammer, or a vibration sensor monitoring bearing health. This reference covers three engineering-grade approaches - native MAX instruction, the LGF SearchMinMax function block, and a slope-based transient peak detector FB - together with the analog scaling, filtering, and cycle-time decisions that determine whether the recorded peak is real or noise.
1. Overview
An S7-1200 CPU (firmware V4.2 or higher for full SCL feature set, V4.4+ recommended) running TIA Portal V17 or V18 exposes three building blocks for peak detection:
-
MAX / MIN instructions in the "Basic instructions > Comparator operations" folder - scalar comparators that return the larger of two
REALorINTvalues per scan. -
LGF_SearchMinMax from the official Siemens Library of General Functions (LGF) for S7-1200/S7-1500 - a parameterizable FB that scans an
ARRAY[*] OF REALand returns the minimum, maximum, and the array index where each occurred. - Custom FB using slope (first derivative) analysis - a three-sample window detects the apex of a transient that may last only a few milliseconds, which a single-scan MAX may miss entirely.
The choice between them is driven by the signal class: slowly varying process values (level, temperature, position) suit MAX; windowed/buffered measurement histories suit LGF_SearchMinMax; impulsive events (acceleration, pressure spikes, strain bursts) require a slope detector plus a fast cyclic interrupt OB.
2. Prerequisites
| Item | Specification | Notes |
|---|---|---|
| CPU | S7-1200, firmware V4.4 or higher | V4.4 adds enhanced trace and runtime diagnostics |
| Engineering software | TIA Portal V17 Update 4 or V18 Update 2 | Required for LGF V3.0.x compatibility |
| Analog input module | SM 1231 (6ES7231-4HF32-0XB0) or AI in signal board SB 1231 | 12-bit basic, 16-bit on HF/HS variants |
| Sensor | Accelerometer (IEPE/±10 V/4-20 mA), load cell, pressure, or any 0-10 V / ±10 V / 4-20 mA source | IEPE needs external conditioning (e.g., 6AT8002) |
| LGF library | Siemens LGF V3.0.0 or later (TIA V17/V18 build) | Distributed as .alp archive via Siemens Industry Online Support |
| Documentation | Siemens Industry Online Support | Search "LGF SearchMinMax" and "S7-1200 System Manual" |
3. Analog Input Signal Conditioning on the S7-1200
The SM 1231 module presents the raw input as an INT in the process image. The standard range is:
| Sensor signal | Raw INT range (S7-1200) | Resolution (16-bit HF) |
|---|---|---|
| Unipolar voltage 0-10 V | 0 to 27648 | ~153 µV / count |
| Bipolar voltage ±10 V | -27648 to +27648 | ~305 µV / count |
| Current 4-20 mA | 0 to 27648 | ~0.58 µA / count |
| Current 0-20 mA | 0 to 27648 | ~0.72 µA / count |
Convert raw to engineering units using the dedicated SCALE_X and NORM_X instructions in TIA Portal under Basic instructions > Converter operations:
// SCL - call SCALE_X in a function block
#EngineeringValue := SCALE_X(
MIN := 0, // Engineering low (e.g. 0.0 g)
MAX := 50.0, // Engineering high (e.g. 50.0 g)
VALUE := NORM_X(
MIN := 0, // Raw low = 0
MAX := 27648, // Raw high = 27648
VALUE := %IW64 // SM 1231 channel 0
)
);
MIN := -27648 and MAX := 27648 in NORM_X. Failing to do this produces a sign-locked output and a peak detector that reports only positive halves of the waveform.4. Approach 1 - Native MAX / MIN Instructions
The simplest peak latcher is a feedback loop: compare the current scaled value with a retained maximum and overwrite the retained value whenever the current value is higher. Because the retained value must survive across scan cycles, the logic must live in a function block (FB) with a static PeakValue variable - never in an FC.
FUNCTION_BLOCK "FB_PeakLatch_R"
{ S7_Optimized_Access := 'TRUE' }
VAR
PeakValue : REAL := 0.0; // Static, retained
SampleCnt : DINT; // Number of samples examined
END_VAR
VAR_INPUT
Reset : BOOL; // TRUE clears PeakValue
Enable : BOOL; // FALSE freezes the latch
Input : REAL; // Scaled engineering value
END_VAR
BEGIN
IF #Reset THEN
#PeakValue := 0.0;
#SampleCnt := 0;
ELSIF #Enable THEN
IF #Input > #PeakValue THEN
#PeakValue := #Input;
END_IF;
#SampleCnt := #SampleCnt + 1;
END_IF;
END_FUNCTION_BLOCK
Call the FB in OB1 (or in a cyclic interrupt OB - see Section 7):
// OB1 - cyclic call from main program
"FB_PeakLatch_R_DB"(
Reset := "HMI".ResetPeak OR "StartupFirstScan",
Enable := TRUE,
Input := "ScaleAccel".Output // scaled g value
);
"HMI".PeakValue := "FB_PeakLatch_R_DB".PeakValue;
Limitations of pure MAX latching:
- No time stamp of the peak - you know the value but not when it occurred.
- If the scan period is slower than the transient (e.g., 50 ms OB1 scanning a 5 ms pulse), the peak may be missed entirely between samples.
- No valley / minimum recording - extend the FB symmetrically if needed.
5. Approach 2 - LGF SearchMinMax Function Block
The Siemens LGF provides LGF_SearchMinMax (V3.0.0+), a parameterizable FB that scans an array of samples in one call and returns the minimum, maximum, and their indices. This is the correct choice when you want the peak over a defined measurement window (e.g., the last 1000 samples, or the samples taken between Start and Stop inputs).
Import the LGF into TIA Portal via Options > Global libraries > Open library, then drag the FB into your project. The interface of LGF_SearchMinMax is:
| Direction | Name | Type | Description |
|---|---|---|---|
| INPUT | execute | BOOL | Rising edge starts the scan |
| INPUT | arrayOfReal | ARRAY[*] OF REAL | Source buffer (slice or full array) |
| INPUT | mode | INT | 0=min, 1=max, 2=min&max |
| OUTPUT | minValue | REAL | Minimum value in array |
| OUTPUT | maxValue | REAL | Maximum value in array |
| OUTPUT | minIndex | DINT | Index where min occurred |
| OUTPUT | maxIndex | DINT | Index where max occurred |
| OUTPUT | error | BOOL | 1 = parameter error |
| OUTPUT | status | WORD | 0 = OK, non-zero = error code |
Typical use - capture the peak in a 1-second window at 100 Hz (100 samples):
// Cyclic OB30 every 10 ms, with 100-element ring buffer
"LGF_SearchMinMax_DB"(
execute := "Trigger".OneSecondTick, // 1 Hz pulse
arrayOfReal := "DataLog".Buffer, // 100 x REAL ring buffer
mode := 2, // 0=min, 1=max, 2=both
minValue => "HMI".WindowMin,
maxValue => "HMI".WindowMax,
minIndex => "HMI".WindowMinIdx,
maxIndex => "HMI".WindowMaxIdx,
error => "Diag".LgfErr,
status => "Diag".LgfStatus
);
Advantages over a single MAX instruction:
- Returns index, so a peak can be correlated with the time stamp stored in a parallel array.
- Detects both extremes from one scan, useful for closed-loop valves that need to know
maxandminover a stroke. - Battle-tested FB with documented status codes from the LGF manual.
6. Approach 3 - Slope-Based Transient Peak Detection
For impulsive events - the peak g of a stamping press, the water-hammer spike in a hydraulic line, the impact force of a tool engaging a workpiece - a single comparator misses the apex unless the scan period is shorter than the event itself. The robust solution is a three-sample slope detector that flags a peak when the signal was rising on the previous sample and falling on the current one.
FUNCTION_BLOCK "FB_PeakDetector_Transient"
{ S7_Optimized_Access := 'TRUE' }
VAR
x_n0 : REAL; // current sample
x_n1 : REAL; // previous sample
x_n2 : REAL; // pre-previous sample
ts : DINT; // peak time stamp (ms since PLC start)
END_VAR
VAR_INPUT
Input : REAL; // scaled engineering value
Threshold : REAL := 0.001; // min rise/fall slope
Enable : BOOL;
Reset : BOOL;
END_VAR
VAR_OUTPUT
PeakDetected : BOOL;
PeakValue : REAL;
PeakTime_ms : DINT;
END_VAR
VAR_TEMP
slopeUp : BOOL;
slopeDown : BOOL;
END_VAR
BEGIN
IF #Reset THEN
#PeakValue := 0.0;
#PeakDetected := FALSE;
#x_n0 := #Input;
#x_n1 := #Input;
#x_n2 := #Input;
RETURN;
END_IF;
IF NOT #Enable THEN RETURN; END_IF;
// Shift history
#x_n2 := #x_n1;
#x_n1 := #x_n0;
#x_n0 := #Input;
// Rising then falling = peak
#slopeUp := (#x_n0 - #x_n1) > #Threshold;
#slopeDown := (#x_n1 - #x_n2) > #Threshold;
IF #slopeUp AND #slopeDown THEN
#PeakValue := #x_n1; // apex is the middle sample
#PeakTime_ms := TIME_TCK(); // system tick in ms
#PeakDetected := TRUE; // sticky flag for HMI
END_IF;
END_FUNCTION_BLOCK
Why three samples? Two samples tell you the slope direction now; the third sample lets you know what the slope was previously. The combination up then down is a local maximum. Setting Threshold above the noise floor (use 3-5× the standard deviation of the resting signal) prevents the detector from firing on quantisation noise. TIME_TCK() returns a 100 ns tick; divide by 10,000 to convert to milliseconds.
7. Cycle Time and Sampling Considerations
The S7-1200 default scan in OB1 is 10-50 ms. A 5 ms accelerometer pulse will be aliased or missed. To sample fast, move the peak logic into a cyclic interrupt OB:
| OB | Name | Configurable interval | Typical use |
|---|---|---|---|
| OB1 | Main | Scan-driven (10-50 ms) | Slow process values |
| OB30 | Cyclic interrupt 0 | 1 ms to 60 s | Fast control loops, vibration, peak detect |
| OB31 | Cyclic interrupt 1 | 1 ms to 60 s | Independent loop |
| OB40 | Hardware interrupt | On threshold/limit | Edge-triggered capture |
For a 1 kHz vibration sample, set the OB30 time to 1 ms. The S7-1200 hardware filters the analog input to ~50 Hz on most SM 1231 channels, so a 1 kHz event is heavily attenuated - a true 1 kHz capture requires an external sample-and-hold or a third-party IEPE digitiser. For press-impact peaks of ~10-50 ms duration, a 1 ms OB30 is more than sufficient.
8. Filtering the Sensor Signal
Three filter strategies are commonly used before peak detection, each available as either a Siemens standard instruction or a hand-rolled SCL block:
8.1 Moving Average (N-tap FIR)
// 8-tap moving average ring buffer
IF #Index > 7 THEN #Index := 0; END_IF;
#Sum := #Sum - #Buf[#Index] + #Input;
#Buf[#Index] := #Input;
#Index := #Index + 1;
#Average := #Sum / 8.0;
An 8-tap moving average at 1 ms OB30 gives a flat passband to ~125 Hz with linear phase - ideal for a press-impact peak that lasts 10-50 ms.
8.2 PT1 First-Order Low-Pass
Siemens provides the standard CTRL_PT1 instruction, or use LGF_Filter_PT1 from the LGF library. Cutoff frequency fc is set by:
fc = 1 / (2π · Tconst)
For a 10 Hz cutoff: T_const = 0.0159 s.
8.3 Exponential Smoothing
#Filtered := #Alpha * #Input + (1.0 - #Alpha) * #Filtered;
With α = 0.1-0.3, exponential smoothing is computationally trivial and effective for slowly varying DC levels. It is not a true low-pass filter (no defined cutoff), but its single-coefficient footprint makes it the default on memory-constrained S7-1200 CPUs.
9. FB vs FC - Choosing the Right Block Type
A function (FC) is stateless; an function block (FB) carries a static data block (DB) that retains its values between calls. The peak-detection logic must remember the previous peak value, so it cannot live in an FC unless the previous value is passed in as an IN_OUT parameter from a global variable or another FB's static memory.
| Block | Retains data between calls | Recommended for peak detection |
|---|---|---|
| FC | No (stateless) | Only if previous peak is an IN_OUT from caller |
| FB | Yes (instance DB) | Default choice; clean encapsulation |
If you convert an FB to an FC because you only want a stateless function (e.g., to read the peak out of a buffer), declare the previous peak value as VAR_IN_OUT instead of VAR_OUTPUT. The compiler will not permit a VAR (static) inside an FC.
10. HMI Display and Data Logging
Typical WinCC / HMI tag mapping for a peak detection application:
| HMI tag | PLC address | Polling | Use |
|---|---|---|---|
| PeakValue | DB.PeakValue (REAL) | 1 s | Numeric display |
| PeakTime | DB.PeakTime_ms (DINT) | 1 s | Time stamp string |
| ResetPeak | DB.Reset (BOOL) | On demand | Button "Reset" |
| TrendValue | %IW64 (raw) or scaled REAL | 100 ms | Trend view for live waveform |
| SampleCount | DB.SampleCnt (DINT) | 1 s | Sanity check (must increase) |
For archiving, use the DataLog function on a S7-1200 with a 4 GB SD card (max 32 GB supported). Open a CSV log per shift, write the peak value, timestamp, and sample count on every OB30 tick. Retention: 2-3 months at 1 s logging is feasible on a 4 GB card.
11. Verification and Commissioning
- Force a known input. Apply a 5.000 V reference (or a calibrated 12.000 mA current source) to the SM 1231 input. Verify the scaled value matches the expected engineering unit to within 0.1 %.
-
Step test. Connect a function generator producing a 10 Hz, 4 Vpp square wave to the analog input. The expected peak is +2 V and -2 V (bipolar) or +2 V and 0 V (unipolar). Confirm the FB's
PeakValuestabilises within 2-3 samples of the true amplitude. -
Burst test. Drive a single impulse (e.g., tap the accelerometer with a calibration hammer) and verify that the slope detector's
PeakDetectedflag pulses for one OB30 cycle andPeakValuelatches at the expected g value within ±5 %. -
Reset verification. From the HMI, trigger Reset and confirm
PeakValuereturns to 0.0 (or to the configured idle value) within one OB1 cycle. - Long-duration test. Log the peak value for 24 h. Drift, saturation, and noise are easier to spot in a trend than a single number.
12. Troubleshooting Matrix
| Symptom | Likely cause | Diagnostic step | Fix |
|---|---|---|---|
| PeakValue stays at 0 | Sensor wired to wrong channel / polarity | Monitor %IW raw in watch table | Re-wire per SM 1231 pinout |
| PeakValue locks at 27648 | Over-range (sensor > 10 V or open current loop) | Check raw value vs. expected | Verify sensor output range; check 4-20 mA loop current |
| PeakValue tracks but is too low | PT1 low-pass attenuating transient | Compare with moving average | Replace PT1 with moving average for impacts |
| PeakDetected fires continuously | Threshold too low, noise triggering slope | View raw signal in trace | Raise Threshold to 3-5× noise std-dev |
| PeakValue never updates | FB called in wrong OB, or Enable stuck FALSE | Check OB30 active bit, watch Enable | Move call into OB30; verify Enable source |
| Bipolar sensor shows only positive peak | SCALE_X / NORM_X set to unipolar range | Inspect block parameters | Set NORM_X MIN := -27648, MAX := 27648 |
| LGF_SearchMinMax returns error | Mode out of range, or array passed by slice wrong | Inspect status word | Set mode to 0/1/2; pass array as ARRAY[*] OF REAL |
| Peak time stamp jumps backward | TIME_TCK() overflow or use of TIA system clock | Check CPU diagnostic buffer | Reset TIME_TCK reference, or use RD_SYS_T for absolute time |
13. Field-Proven Caveats
- Sample-and-hold mismatch. If your OB1 cycle is 30 ms but the analog event is 5 ms, the analog read may already be returning the tail of the pulse. Insert a hardware peak-detect op-amp (e.g., a diode + capacitor with FET reset) on the analog front-end, or move the entire capture into a 1 ms OB30.
- Retain behaviour. Mark the instance DB as Non-optimised with retain or Optimised with retain in TIA Portal if you need the peak value to survive a power cycle. Without retain, the peak resets to 0 on every restart.
-
First-scan reset. Tie the FB
Resetinput toFirstScan(system bit) so the latched peak does not contain a stale value from a previous run on the first cycle after PLC startup. -
Float math overhead.
REALdivision on the S7-1200 takes ~6 µs of CPU time at firmware V4.4. At OB30 1 ms, a 100-tap moving average with 100 divisions/sec is well within budget (~0.6 % of cycle), but on the smaller CPU 1212C at 1 ms OB30 it can starve communication. Use DINT fixed-point if cycle time is tight. - Ground loops on accelerometers. If the peak value drifts at mains frequency, the accelerometer shell is not grounded. Use a shielded cable with the shield bonded at the PLC end only and an isolated signal conditioner.
14. Choosing the Approach - Quick Selection
| Use case | Recommended method | Why |
|---|---|---|
| Slow process value, latch the highest reading | Native MAX FB | Trivial code, no buffer needed |
| Buffered measurement over a fixed window | LGF_SearchMinMax | Returns index, both extremes, validated code |
| Impulsive event (acceleration, water hammer, impact) | Slope FB in 1 ms OB30 + moving average | Catches the apex reliably with timestamp |
| Continuous trend, peak in last N seconds | LGF_SearchMinMax on ring buffer | Window-based, no missed scans |
| Vibration, FFT downstream | Raw buffer in OB30, no peak logic | FFT requires raw samples, not compressed peaks |
What cycle time is required to catch an accelerometer peak on the S7-1200?
For a 10-50 ms impact (typical press shock), a 1 ms OB30 cyclic interrupt is sufficient. For sub-millisecond transients, the SM 1231 bandwidth (~25 Hz filtered) and the S7-1200 analog scan rate become the bottleneck - in that case, an external peak-hold circuit or IEPE digitiser is required before the PLC.
How do I reset the latched peak value from the HMI?
Bind a WinCC button to a BOOL tag wired to the FB's Reset input. Pulse the BOOL for one OB1 cycle, then release. The FB sets PeakValue to 0.0 and clears PeakDetected. Make the instance DB retain if you want the value to survive a power cycle.
Can the S7-1200 detect multiple peaks per second?
Yes. Use a ring buffer in a 1 ms OB30 and run LGF_SearchMinMax with mode := 1 (max only) once per cycle, or once per 100 ms if you only need a coarse peak-per-window reading. For multiple discrete peaks per second, iterate the array and detect each local maximum with the slope detector rather than scanning once.
What is the difference between the MAX instruction and LGF_SearchMinMax?
The MAX instruction compares two scalar values per call and returns the larger. LGF_SearchMinMax scans an ARRAY[*] OF REAL and returns the minimum, maximum, and the array indices where each occurred. Use MAX for point-to-point comparison, LGF_SearchMinMax for windowed/buffered analysis.
How do I handle a bipolar analog signal such as ±10 V from an accelerometer?
Configure the SM 1231 channel for ±10 V mode in the device configuration, then in your SCL set NORM_X(MIN := -27648, MAX := 27648, ...) before calling SCALE_X. The peak FB must then accept negative peaks - either declare VAR PeakValue : REAL := 0.0 with a small dead-band, or initialise PeakValue to the most negative representable value so the first rising edge is captured.