Calculating Reactive Power in WinCC 7.3 C Script with pow()

David Krause10 min read
SiemensTutorial / How-toWinCC
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

Reactive power (Q) is the component of AC power that establishes and sustains the electric and magnetic fields in inductive and capacitive loads. Unlike active power (P), which performs real work, reactive power oscillates between source and load and is measured in volt-amperes reactive (VAR). In industrial HMI/SCADA applications, computing Q in real time from measured P and the power factor (cos φ) is a frequent requirement for energy monitoring, capacitor bank control, and power-quality dashboards.

This tutorial demonstrates the correct implementation of the reactive power formula Q = P * sqrt[(1/cosPhi)^2 − 1] inside a Siemens WinCC 7.3 C Script. The article documents the exact error in a common first attempt, explains the role of the C math library pow(), and shows the working code with verified tag declarations.

Prerequisites

  1. Engineering Station: SIMATIC WinCC 7.3 SP2 or later installed with the WinCC C scripting option enabled. The C editor is part of the standard WinCC installation; no additional runtime is required for the math library pow(), sqrt(), and related functions because WinCC links the C runtime statically.
  2. Tag Configuration: Three internal tags of data type Floating point 64-bit IEEE 754:
Tag Name WinCC Data Type Bit Width Purpose
Attiva Floating point 64-bit IEEE 754 64 Active power P input (W)
Cosphi Floating point 64-bit IEEE 754 64 Power factor input (0…1)
Reattiva Floating point 64-bit IEEE 754 64 Reactive power Q output (VAR)
  1. Trigger: A scheduled C action (e.g., 1-second cycle) or a tag-change event on Attiva or Cosphi.
  2. Header file: #include "apdefap.h" is auto-inserted by the WinCC C editor; no manual math.h include is required because WinCC exposes the prototype internally. If you compile custom C functions for a global script, include <math.h> explicitly.

The Reactive Power Formula

The relationship between apparent power S, active power P, reactive power Q, and power factor cos φ is rooted in the power triangle:

  • S = sqrt(P^2 + Q^2)
  • P = S * cos(phi)
  • Q = S * sin(phi)
  • cos(phi) = P / S

Substituting S = P / cos φ into the second equation gives the direct formula requested by the customer:

Q = P * sqrt[(1/cosPhi)^2 − 1]

This form is convenient when only P and the power factor are available from upstream metering (e.g., a Siemens SENTRON PAC3200/4200 or 7KM PAC measuring transducer). The sign of Q is positive for lagging (inductive) loads and negative for leading (capacitive) loads. When working with single-phase data, the result is in VAR; for three-phase balanced systems, the result is the total three-phase reactive power. Always confirm the metering device returns line-to-neutral or line-to-line values before applying the formula.

Why the First Attempt Fails

The original WinCC 7.3 C script submitted by the user is:

SetTagFloat ("Reattiva", GetTagFloat("Attiva")*(sqrt(1.0/GetTagFloat("Cosphi")^2)-1));

There are two separate issues in this single line:

  1. Operator precedence with ^: The C language does not use the caret (^) for exponentiation. The caret is the bitwise XOR operator. Writing GetTagFloat("Cosphi")^2 XORs the floating-point bit pattern of cos φ with the integer literal 2, producing a meaningless number and almost certainly a non-finite or negative value under the square root.
  2. Bracket grouping error: The closing parenthesis is placed after the entire expression, so the subtraction of 1 is performed outside the square root: sqrt(1.0/cosPhi) - 1 instead of sqrt((1.0/cosPhi)^2 − 1). The result is the reactive index minus 1, not the desired VAR value.
Critical: WinCC 7.3 does not return a syntax error for misuse of ^; the script compiles and runs, returning a numerically wrong result. Always validate the math by logging the intermediate value to a diagnostic tag during commissioning.

Correct Implementation Using pow()

The standard C library function double pow(double base, double exponent) (declared in <math.h>) provides floating-point exponentiation. In WinCC 7.3 the prototype is available without an explicit include, and the function is fully resolved at script-compile time. The verified working script is:

SetTagFloat("Reattiva",
            GetTagFloat("Attiva")
            * sqrt(pow((1.0/GetTagFloat("Cosphi")), 2) - 1));

Step-by-step evaluation:

  1. GetTagFloat("Cosphi") returns the live power factor, e.g., 0.85.
  2. 1.0 / 0.85 = 1.176470588 (the apparent/active ratio).
  3. pow(1.176470588, 2) = 1.384083045 (the squared ratio).
  4. 1.384083045 − 1 = 0.384083045 (the squared tangent).
  5. sqrt(0.384083045) = 0.619782103 (the tangent).
  6. GetTagFloat("Attiva") * 0.619782103 = Q in VAR.

For a 100 kW load at cos φ = 0.85, the script yields Q ≈ 61,978 VAR, matching the standard reference value of approximately 61.97 kVAR.

Step-by-Step Configuration in WinCC 7.3

  1. Open the WinCC Explorer and expand your project tree.
  2. Right-click Tag Management → Internal Tags and create the three tags listed in the prerequisites table. Confirm the data type is Floating point 64-bit IEEE 754; do not use Floating point 32-bit IEEE 754 if you intend to chain multiple calculations because cumulative rounding can exceed 1 VAR on large loads.
  3. Open the Graphics Designer and place an I/O Field bound to Attiva, a second one bound to Cosphi, and a third (read-only) field bound to Reattiva. Configure update cycles at 1 s for demonstration; production deployments typically use 250 ms to 1 s depending on the upstream meter refresh rate.
  4. From the Graphics Designer, right-click the Cosphi I/O field → Properties → Events → Output/Input → Change → C Action.
  5. In the C editor, paste the working formula. WinCC auto-generates the function signature: void OnClick(char* lpszPictureName, char* lpszObjectName) { ... } for a click event or void OnPropertyChange(...) for a tag-change event. The SetTagFloat/GetTagFloat calls are inserted inside the function body.
  6. Click Compile. WinCC should return 0 error(s), 0 warning(s). If a warning such as "possible loss of data" appears, cast the GetTagFloat result to double explicitly: (double)GetTagFloat("Cosphi").
  7. Save the action and start Runtime. Modify the Attiva and Cosphi values via the I/O fields and observe Reattiva updating in real time.

Verification and Test Cases

Use the following table to verify the implementation. All values assume single-phase or three-phase balanced conditions where P is the total active power and cos φ is the total power factor.

P (W) cos φ Expected Q (VAR) Script Output Status
100 000 1.00 0.0 0.0 OK
100 000 0.90 48 432.2 48 432.2 OK
100 000 0.85 61 978.2 61 978.2 OK
100 000 0.80 75 000.0 75 000.0 OK
100 000 0.70 102 020.4 102 020.4 OK
100 000 0.50 173 205.1 173 205.1 OK
0 0.85 0.0 0.0 OK
Edge case: If cos φ is reported as exactly 1.0, the expression under the square root is 0 and Q is correctly 0. If cos φ is reported as 0 (open circuit, meter failure), the division yields infinity and pow(inf, 2) − 1 is still infinity; the square root of infinity is infinity and the SetTagFloat call returns a non-finite value. Always clamp cos φ to a minimum of 0.01 in production code (see Defensive Coding below).

Defensive Coding: Clamping and NaN Handling

Real-world power factor data from a PAC meter can briefly return 0 during transients, causing the divide-by-zero above. Add the following guard inside the C action:

double cosphi = GetTagFloat("Cosphi");
double P      = GetTagFloat("Attiva");
double Q;

if (cosphi < 0.01) cosphi = 0.01;       // protect division
if (cosphi > 1.0)  cosphi = 1.0;        // clamp to physical limit
Q = P * sqrt(pow(1.0/cosphi, 2) - 1);
if (Q < 0) Q = 0;                       // saturate underflow
SetTagFloat("Reattiva", Q);

WinCC 7.3 supports standard C conditional statements inside a C action; the script compiles identically to a pure one-liner but produces robust output across the full operating range of the upstream meter.

Tag Access and the TagPrefix Gotcha

WinCC 7.3 supports a project-level TagPrefix (a 3-character string assigned during project creation) that is prepended to every unqualified tag name. If a project has TagPrefix ABC, then the tag Attiva is stored internally as ABCAttiva. A function call such as GetTagFloat("Attiva") still works in most cases because WinCC prepends the prefix automatically; however, certain C actions compiled for picture-internal access require the explicit @NOTP:: prefix to bypass prefix resolution:

GetTagFloat("@NOTP::Attiva")

The @NOTP:: directive tells the WinCC API to look up the tag literally without prepending any TagPrefix. Use it when a script returns "Tag not found" errors despite the tag being visible in the tag browser, or when copying scripts between projects that have different TagPrefixes. The verified working formula using @NOTP:: is:

SetTagFloat("@NOTP::Reattiva",
            GetTagFloat("@NOTP::Attiva")
            * sqrt(pow((1.0/GetTagFloat("@NOTP::Cosphi")), 2) - 1));

Data Type Considerations

WinCC's Floating point 64-bit IEEE 754 corresponds to the C double type (IEEE 754 binary64, 53-bit mantissa, ~15–17 significant decimal digits). The GetTagFloat and SetTagFloat WinCC API functions accept and return double values, so no explicit casting is required when the tags are declared as 64-bit floats. If you accidentally use 32-bit tags, GetTagFloat still works but the precision drops to ~7 digits, which can be observed as a small constant offset on a 100 kW load at cos φ < 0.9.

For internal intermediate values (the index 1/cosPhi and the tangent), always work in double to avoid the C default of promoting float to double mid-expression, which can introduce compiler warnings about "double to float conversion".

Alternative Implementations

The same result can be obtained with the equivalent identity tan(phi) = sqrt(1/cosPhi^2 − 1). In WinCC 7.3 you may use the standard C function atan to derive φ from the power factor and then compute the tangent directly:

double cosphi = GetTagFloat("@NOTP::Cosphi");
double P      = GetTagFloat("@NOTP::Attiva");
double phi    = acos(cosphi);             // radian measure
SetTagFloat("@NOTP::Reattiva", P * tan(phi));

This variant is numerically more efficient on slow HMI panels (e.g., SIMATIC Panel PCs with Atom CPUs) because atan/acos/tan are all single-pass operations in the C runtime, whereas pow() internally calls exp(y * log(x)). For a 1 Hz cycle on a SIMATIC IPC277E the difference is sub-millisecond and irrelevant; for tighter loops (10 Hz on the same hardware), the tan(acos(...)) form is preferred.

A third option, the identity Q = P * tan(acos(cosphi)), mathematically simplifies to the same expression, but the symbolic form is harder to audit during FAT/SAT documentation reviews because the power triangle relationship is obscured.

Troubleshooting Matrix

Symptom Likely Root Cause Fix
Reattiva always reads 0 Tag is read-only in the I/O field, or the action is not triggered Configure the action on Output/Input → Change and verify Runtime is in online mode
Compile error: undeclared identifier pow Custom global C function without #include <math.h> Add #include <math.h> at the top of the function
Compile warning: possible loss of data Implicit float-to-double or double-to-float conversion Cast all GetTagFloat results to double
Runtime: tag not found for Attiva/Cosphi TagPrefix mismatch Prefix tag names with @NOTP::
Output is always a large negative or NaN cosPhi = 0 from a meter glitch Clamp cosPhi to [0.01, 1.0] before division
Output is wrong sign on capacitive loads Customer's spec assumes lagging only Apply if (Q < 0) Q = -Q; for absolute-value displays, or use cos φ signed from the meter
Output oscillates by ±0.5 VAR at steady state 32-bit float tags used instead of 64-bit Re-declare all three tags as Floating point 64-bit IEEE 754
Script runs in editor but not in Runtime C action compiled for debug only Recompile in Release mode and re-deploy the project

Commissioning Checklist

  1. Verify all three tags exist and are online (green dot in Tag Management).
  2. Force Cosphi = 0.85 and Attiva = 100 000; confirm Reattiva reads 61 978 ± 1 VAR.
  3. Force Cosphi = 1.0; confirm Reattiva reads 0.0 VAR (no underflow).
  4. Force Cosphi = 0.0; confirm Reattiva is clamped to a safe finite value, not infinity/NaN.
  5. Restore live values and observe the result against a reference power analyzer (e.g., Fluke 435 or Hioki PW3198) for at least one full load cycle.
  6. Document the formula, tag list, and update cycle in the project's Function Design Specification (FDS) for future maintenance.

FAQ

Why does the original formula fail in WinCC 7.3 C Script?

Two errors: the caret (^) is the C bitwise XOR operator, not exponentiation, and the closing parenthesis is misplaced so the subtraction is outside the square root. Replace ^2 with pow(..., 2) and correct the bracket grouping to sqrt(pow((1/cosPhi), 2) - 1).

Do I need to include <math.h> for pow() in WinCC 7.3?

No, for picture-level C actions WinCC auto-includes the required prototypes. You only need an explicit #include <math.h> when writing a custom C function in a global script library.

What data type should the Attiva, Cosphi, and Reattiva tags be?

Use Floating point 64-bit IEEE 754. This corresponds to the C double type and matches the precision expected by GetTagFloat and SetTagFloat. Avoid 32-bit floats to prevent cumulative rounding on multi-step calculations.

How do I avoid division-by-zero when the meter reports cos φ = 0?

Clamp the input to a safe range such as [0.01, 1.0] before computing the ratio 1/cosPhi. This prevents infinity and NaN propagation into the square root and into the SetTagFloat call.

What is the difference between using pow() and tan(acos(cosphi))?

Both yield the same numeric result. The pow() form mirrors the customer's specification exactly and is easier to audit. The tan(acos(...)) form is marginally faster on low-power IPCs because it avoids the exp(y*log(x)) decomposition of pow().

Back to blog