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
-
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. - 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) |
-
Trigger: A scheduled C action (e.g., 1-second cycle) or a tag-change event on
AttivaorCosphi. -
Header file:
#include "apdefap.h"is auto-inserted by the WinCC C editor; no manualmath.hinclude 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:
-
Operator precedence with
^: The C language does not use the caret (^) for exponentiation. The caret is the bitwise XOR operator. WritingGetTagFloat("Cosphi")^2XORs the floating-point bit pattern of cos φ with the integer literal2, producing a meaningless number and almost certainly a non-finite or negative value under the square root. -
Bracket grouping error: The closing parenthesis is placed after the entire expression, so the subtraction of
1is performed outside the square root:sqrt(1.0/cosPhi) - 1instead ofsqrt((1.0/cosPhi)^2 − 1). The result is the reactive index minus 1, not the desired VAR value.
^; 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:
-
GetTagFloat("Cosphi")returns the live power factor, e.g., 0.85. -
1.0 / 0.85 = 1.176470588(the apparent/active ratio). -
pow(1.176470588, 2) = 1.384083045(the squared ratio). -
1.384083045 − 1 = 0.384083045(the squared tangent). -
sqrt(0.384083045) = 0.619782103(the tangent). -
GetTagFloat("Attiva") * 0.619782103 = Qin 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
- Open the WinCC Explorer and expand your project tree.
- 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.
- Open the Graphics Designer and place an I/O Field bound to
Attiva, a second one bound toCosphi, and a third (read-only) field bound toReattiva. Configure update cycles at 1 s for demonstration; production deployments typically use 250 ms to 1 s depending on the upstream meter refresh rate. - From the Graphics Designer, right-click the
CosphiI/O field → Properties → Events → Output/Input → Change → C Action. - In the C editor, paste the working formula. WinCC auto-generates the function signature:
void OnClick(char* lpszPictureName, char* lpszObjectName) { ... }for a click event orvoid OnPropertyChange(...)for a tag-change event. The SetTagFloat/GetTagFloat calls are inserted inside the function body. - 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
doubleexplicitly:(double)GetTagFloat("Cosphi"). - Save the action and start Runtime. Modify the
AttivaandCosphivalues via the I/O fields and observeReattivaupdating 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 |
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
- Verify all three tags exist and are online (green dot in Tag Management).
- Force
Cosphi = 0.85andAttiva = 100 000; confirmReattivareads 61 978 ± 1 VAR. - Force
Cosphi = 1.0; confirmReattivareads 0.0 VAR (no underflow). - Force
Cosphi = 0.0; confirmReattivais clamped to a safe finite value, not infinity/NaN. - 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.
- 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().