1. Problem Overview: Real-Time Timer Execution in S7-PLCSIM
S7-PLCSIM (V15.1 through V19 SP1) executes standard IEC timers (TP, TON, TOF, TONR, RT, CT, SFB3/4/5, IEC_TP/TON/TOF) using the internal PLC clock of the simulated CPU. The simulation runs against the host machine's wall clock; there is no user-accessible command to multiply, divide, or compress this clock for IEC timers. The official S7-PLCSIM online help explicitly states that the simulated time base mirrors the host system time. For a 1,000 ms TON that triggers a sequencing output, the simulated CPU waits 1,000 ms regardless of how fast the rest of the logic runs.
When an engineer writes a hardware-agnostic test harness in TIA Portal (V16 +) that exercises 10,000+ scenarios containing 200+ safety timers, the cumulative wait time becomes:
T_total = N_tests x Sum(Timer_i) = 10,000 x sum of all active timer presets
For a typical 5 s average per case, that is 13.9 hours of waiting. Modifying every timer preset in the safety program after each code change is rejected by Functional Safety (SIL 2/3) change-control processes because the safety program must remain the release candidate, not a test-only variant.
2. Why PLCSIM Timers Run at Host Clock Speed
The S7-1500/1200 CPU firmware stores the system clock in the data block area and updates it once per OB1 cycle. The IEC timer instructions read the system clock and the start-time tag to compute elapsed time. PLCSIM emulates the CPU's OB1 dispatcher, which means the dispatcher must run fast enough to give the timers deterministic 1 ms resolution (or 10 ms for older CPU sets). PLCSIM therefore aligns its tick to the host QPC / GetTickCount64 source.
The PLCSIM simulation engine has no exposed parameter to scale the clock. Internal commands exist (Siemens internal) for re-playing trace buffers, but they are not part of the public API. The instruction set installed in your project determines the surface area available for acceleration:
| Timer instruction | Block family | Source of elapsed time | Acceleration path |
|---|---|---|---|
| IEC_TP / IEC_TON / IEC_TOF (SFB3/4/5) | S7-300/400 system | System clock 1 s | None in PLCSIM; replace with Timer_P |
| TP / TON / TOF / TONR (LAD/FBD multi-instance) | S7-1200/1500 system | System clock 1 ms / 10 ms | None in PLCSIM; use cyclic interrupt |
| Timer_P (CFC) | CFC library | Configurable via Sample_T input | Direct scaling |
| Runtime clock via PLCSIM Advanced ODK | PLCSIM Advanced V2.0+ | Virtual time maintained in ODK API | VirtualTimeControl |
3. Method 1: CFC Timer_P with Cyclic Interrupt OB
The most surgical fix is to use the CFC library block Timer_P (F-libraries / CFC) instead of the system IEC timers. Timer_P takes a Sample_T input that tells the function block what time base to assume. If you call the block from a cyclic interrupt OB (OB30 through OB38), the actual elapsed time between calls is the OB period. When the OB period is much smaller than the desired timer value, the multiplier becomes:
Effective_time = OB_period_ms / Sample_T_ms x Preset
Implementation steps (CFC in TIA Portal):
- Open the project in TIA Portal V16+ with the CFC optional package installed.
- Insert a cyclic interrupt OB, e.g.
OB30 "Cyclic_10x"with a 1 ms phase offset and a period of 1 ms. - Place
Timer_Pon the CFC chart and wire theSample_Tinput to a constant1000ms (interpreted as 1 second of simulation time per real-time call). Note: this is an interpretation parameter, not a clock source. - Set the timer preset PT to the same engineering value (in seconds) you would use in production.
- Run the chart in OB30. The timer will expire after
OB_period x Preset / Sample_Treal-time milliseconds. With OB30 = 1 ms and Sample_T = 1000 ms, a 5 s PT expires after 5 ms of real time. - Repeat for all 200+ timers. Because the safety program logic is unchanged, only the timer invocation is moved into the CFC scheduler, the safety baseline is preserved.
Sample_T and the OB period diverge from the production call rate, the timer will be faster or slower than the engineering value, both on activation and deactivation. Always measure with an oscilloscope trace or PLCSIM trace buffer to confirm scaling.
4. Method 2: PLCSIM Advanced Virtual Time Control (ODK API)
For S7-1500 projects where you cannot refactor to CFC, S7-PLCSIM Advanced V2.0+ exposes the ODK (Open Development Kit) automation interface. The API allows a test harness (C#, Python via pythonnet, or any COM/.NET client) to manipulate the simulated CPU's notion of time directly.
The ODK object model exposes:
-
PlcsimAdvInstance– the active simulated CPU -
VirtualTimeMode– enum:RealTime,Accelerated,Stepping -
SetVirtualTimeScale(double scale)– multiply the simulation clock by a factor (1.0 = real time, 100.0 = 100x faster) -
StepVirtualTime(int ms)– advance the simulation by a deterministic number of milliseconds and pause
Example C# harness against PLCSIM Advanced:
// Reference: Siemens.Simatic.S7PLCSIM.Advanced.dll (V2.0+)
using Siemens.Simatic.S7PlcsimAdvanced;
var instance = new PlcsimAdvInstance();
instance.Connect("192.168.0.1", 0); // TCP loopback to local PLCSIM
// 1000x speedup for IEC timer testing
instance.VirtualTimeMode = VirtualTimeMode.Accelerated;
instance.SetVirtualTimeScale(1000.0);
foreach (var testCase in testSuite)
{
instance.PowerOn();
instance.Run();
SetInputs(testCase.Inputs);
instance.StepVirtualTime(testCase.MaxRuntimeMs);
var actual = ReadOutputs();
Assert.AreEqual(testCase.Expected, actual);
instance.Stop();
}
instance.Disconnect();
This is the official Siemens-supported path for headless CI/CD test automation. It does not require modifying the safety program and is the recommended method for >10k test cases.
5. Method 3: Cyclic Interrupt OB Without CFC
If you cannot install the CFC optional package but you can edit the project structure, you can use a cyclic interrupt OB (OB30) to read system time at a custom rate and compute timer expiration in the application code. This requires that the safety program calls a single point of entry inside the cyclic OB, then uses an in-house "Timer_P-like" FB whose SampleTime input is wired to the OB period.
- Create
OB30 "FAST_TEST_TICK"with 1 ms period. - Inside OB30, call a wrapper FB
FB_TestTimerwith inputSampleTimeMs := 1andPresetSec := 5. - Inside the FB, accumulate
SampleTimeMsper call and compare againstPresetSec * 1000to set the Q output. - Replace every system TON/TP with this FB at the I/O boundary; the safety logic body remains untouched.
This is functionally identical to the CFC approach but is achievable with stock TIA Portal without optional packages. It is the most common pattern in factories that standardize on SCL-only programming.
6. Method 4: Manual Time Stepping with PLCSIM Trace and Pause
PLCSIM (V16+) supports single-step OB execution when the CPU is in STOP with breakpoint, and trace recording in RUN. Combining trace + manual step:
- Set the CPU to
RUN, capture a trace, set a breakpoint at the first instruction after the timer coil. - When the breakpoint hits, manually issue a single OB1 cycle (
Step Nextin the TIA Portal online menu) and let the timer expire in the next cycle if the elapsed time is sufficient. - This is not a 10,000-case solution; it is a debug aid. Documented in the TIA Portal automation framework guide at TIA Portal DocV001, Section 16.3.
7. Method 5: Test Harness Outside the Safety Domain
The pragmatic enterprise solution isolates the safety code into a library and exposes a test override interface on the F-runtime boundary. The non-safety (standard) program reads the F-shared DB and forces timer state via a test-only FB. This is permitted by IEC 61508-3 Clause 7.4.6 only when:
- The test override FB is removed from the build via a compile-time switch (
{IF SIL_TEST}...{END_IF}) in the F-runtime boundary. - The release build is byte-identical to the validated F-program; the test-only block lives in the standard runtime and is excluded by the F-signature check.
- The compiler directive is read from a project property, not from a runtime variable, so it cannot be toggled in production.
This pattern is officially referenced in Siemens application example "SIMATIC F-Program test with SIMIT" (entry ID 109770144) and is the path used in the automotive discrete manufacturing sector for SIL 2 cells.
8. Comparison Matrix of Acceleration Methods
| Method | Speedup factor | Code change required | Safety program impact | License requirement | CI/CD friendly |
|---|---|---|---|---|---|
| CFC Timer_P + OB30 | 100-1000x | Yes (wrap in CFC) | None | CFC optional package | Yes |
| PLCSIM Advanced ODK VirtualTimeScale | 1-1000x configurable | None | None | PLCSIM Advanced V2.0+ | Yes (best) |
| Custom OB30 in-house FB | 100-1000x | Yes (add wrapper FB) | None | TIA Portal base | Yes |
| Manual stepping + breakpoints | None | None | None | TIA Portal base | No |
| F-override at standard boundary | 100x | Yes (compile-time only) | None in release | F-system optional package | Yes |
| Modify all 200 timers (NOT recommended) | 100x | Yes (200 changes) | HIGH - violates baseline | None | Yes |
9. Implementation Example: 10,000-Case Headless Test Suite
The following architecture supports a 10,000-case test suite over an Ethernet-attached PLCSIM Advanced instance. The harness runs in a CI container (GitLab CI or Azure DevOps), communicates with PLCSIM Advanced over the ODK TCP interface, and accelerates the simulated clock by 1000x for 5 s timers, reducing the total test time from 13.9 hours to 50 seconds of simulation time.
- Spin up the S7-PLCSIM Advanced instance via the CLI:
PlcSimAdv.exe -instance "/PLC1:192.168.0.1" -start - Compile the safety program in TIA Portal and download to the simulated instance:
tia-cli /project compile --target /PLC1 - Connect the ODK client and set
VirtualTimeScale(1000.0). - For each test case:
StepVirtualTime(MaxRuntimeMs)until the F-runtime reportsStateReadyor timeout. - Compare the captured outputs to the goldens; archive the trace buffer for any failure.
- Power-off the instance and dispose the ODK handle.
Verification check (Step 6): Run a single known-good test case with VirtualTimeScale(1.0) first to confirm the program logic, then re-run with VirtualTimeScale(1000.0) and confirm the output trace is identical to the second-scale resolution. Any drift indicates the safety program has a path dependent on absolute wall-clock time and must be re-engineered.
10. Limitations and Edge Cases
- High-speed counter modules (TM Count, TM PosInput): The S7-PLCSIM help PDF explicitly states PLCSIM does not simulate module behavior; the counter returns the initial value. Do not run timer-related counter tests in PLCSIM; use the S7-PLCSIM Advanced + SIMIT hardware-in-the-loop coupling instead.
- PROFINET IRT: PLCSIM does not simulate PROFINET IRT cycle times; the simulated CPU free-runs the OB1 cycle at the host's tick. Timer-based PROFINET diagnostics will not behave like real hardware.
- Web server and OPC UA server diagnostics: The OPC UA time stamps are read from the host OS, not the simulated clock. If you accelerate the clock, OPC UA time stamps will jump backwards. Use the ODK API to query the OpcUaServerAbsoluteTime tag for consistency.
- Force table: The PLCSIM force table (M, I, Q) operates on the simulated process image, not the simulated time. Forced inputs do not bypass timer expiration; they bypass the input wiring only.
- S7-1500 system time tag "LOCTIME": This tag is updated by the host wall clock and will not match the accelerated simulation. Avoid using it as a timer base inside the test harness.
11. Troubleshooting Matrix
| Symptom | Likely cause | Resolution |
|---|---|---|
| Timer expires in real time, not simulation time | PLCSIM (not Advanced) used; no ODK license | Upgrade to S7-PLCSIM Advanced V2.0+ or use Method 1/3 |
| Timer expires too early with CFC Timer_P | OB period shorter than Sample_T expectation | Set OB period = Sample_T / 1000 for direct scaling |
| Trace buffer shows 5 s but CPU still in RUN | OB1 cycle too slow to honor the timer | Increase OB1 priority or reduce monitored blocks |
| Safety program fails signature check after refactor | F-runtime detected change in safety blocks | Move acceleration to standard program; preserve F-signature |
| OPK StepVirtualTime blocks indefinitely | Cyclic OB priority higher than test harness interrupt | Lower OB30 priority or set StepVirtualTime(maxMs) with timeout |
| Test runs 10x slower after acceleration | OPDK mode set to RealTime by accident | Verify VirtualTimeMode = Accelerated before each test |
12. FAQ
Does S7-PLCSIM expose a clock-speed multiplier for IEC timers?
No. Standard S7-PLCSIM (V15-V19) executes timers against the host wall clock with no scaling parameter. Only S7-PLCSIM Advanced V2.0+ exposes VirtualTimeScale via the ODK API.
Can I refactor 200+ safety timers to CFC Timer_P without changing the safety baseline?
Yes, when the F-runtime boundary reads the CFC outputs through a standard F-shared DB. The CFC chart lives in the standard program, so the F-signature remains unchanged. Document the change in the F-change log per IEC 61508-3.
What is the maximum VirtualTimeScale factor in PLCSIM Advanced?
Empirically up to 10,000x for short timers (≤100 ms preset); above 1,000x the OB1 dispatcher may saturate and timers drift. Always validate with a single-case trace before scaling the full suite.
Will the OPC UA server time stamp follow the accelerated clock?
No. OPC UA server time stamps come from the host OS. Use the PLC tag "OpcUaServerAbsoluteTime" or a custom tag populated inside the accelerated simulation to keep test logs consistent.
Is the S7-PLCSIM Advanced ODK API stable across firmware versions?
The ODK interface is part of PLCSIM Advanced V2.0+ and is contract-stable for V2.x. Always reference Siemens.Simatic.S7PLCSIM.Advanced.dll with the version matching the installed PLCSIM Advanced (V2.0 → 2.0.x.y).