transformer-thermal-model
is a library for modelling the transformer top-oil and
hot-spot temperature based on the transformer specifications, a load profile and an ambient temperature profile.
The model is an implementation according to the standard IEC 60076-7, also known as de Loading Guide.
Check out our documentation page, the technical documentation, the quick start or one of the many other examples!
You can directly install the package from PyPI.
pip install transformer-thermal-model
This package contains the following modules to work with:
transformer_thermal_model.model
: the core of the package to calculate a temperature profile of a transformer using the thermal model;transformer_thermal_model.transformer
: a module containing multiple transformer classes to be used to define a transformer;transformer_thermal_model.cooler
: a module containing the enumerators to define the cooler type of the transformer;transformer_thermal_model.schemas
: in schemas one can find a.o. the definition of the model interfaces and how the transformer specificitations should be specified;transformer_thermal_model.hot_spot_calibration
: a module that is used to determine the transformer hot-spot factor to be used in the thermal model.
The following modules contain elements that are not required for thermal modelling but are used to get more insight in aging and load capacity:
transformer_thermal_model.aging
: a module to calculate the aging of a transformer according to IEC 60076-7 paragraph 6.3;transformer_thermal_model.components
: a module containing enumerators to define components of a power transformer if one wants to calculate the relative load capacity of each component in the transformer.
Before performing a calculation, a transformer object must be created with all necessary details about the transformer. Default values will be used for any attribute not specified by the user.
transformer_thermal_model.transformer
: This module has multiple Transformer
children, which will be elements used for the temperature calculation inside Model
.
PowerTransformer
: A power transformer class, child of theTransformer
class.DistributionTransformer
: A distribution transformer class, also child of theTransformer
class.ThreeWindingTransformer
: A three winding transformer, also child of theTransformer
class.TransformerType
(Enum
): For easily checking all available types. Does not have any use in our code, but might be useful for your use-case.
A Transformer
needs a couple of specifications (user_specs
) and a
cooling type (in cooling_type
). The specifications are defined in
transformer_thermal_model.schemas.UserTransformerSpecifications
, and are
a composition of some mandatory specifications and some optionals. When the
optionals are left unchanged, the default values per class will be used.
These can be found by defaults
, e.g. PowerTransformer.defaults
will show
you the default specifications.
An example on how to initialise a PowerTransformer
:
from transformer_thermal_model.cooler import CoolerType
from transformer_thermal_model.transformer import PowerTransformer
from transformer_thermal_model.schemas import UserTransformerSpecifications
tr_specs = UserTransformerSpecifications(
load_loss=1000, # Transformer load loss [W]
nom_load_sec_side=1500, # Transformer nominal current secondary side [A]
no_load_loss=200, # Transformer no-load loss [W]
amb_temp_surcharge=20, # Ambient temperature surcharge [K]
)
transformer = PowerTransformer(user_specs=tr_specs, cooling_type=CoolerType.ONAF)
It is recommended to adjust the following parameters when modelling a specific transformer as these influence the thermal modelling and are transformer-specifically defined (the ones with a '*' are mandatory):
load_loss
*: load loss of the transformer.no_load_loss
*: no load loss of the transformer.nom_load_sec_side
*: nominal current of the secondary side of the transformer.amb_temp_surcharge
*:PowerTransformer
: temperature surcharge on ambient temperature due to installation conditions.DistributionTransformer
: Building or placement thermal classification.
top_oil_temp_rise
: top-oil temperature increase under nominal conditions.winding_oil_gradient
: temperature difference between the average winding and average oil temperature under nominal conditionshot_spot_fac
: factor determining the temperature difference between top-oil and hot-spot. Only specify when known, otherwise see hot-spot factor calibration.
transformer_thermal_model.cooler
: Similarly, you must provide the type of
cooling of your transformer. This is only for a PowerTransformer
, since a
DistributionTransformer
is always ONAN.
To adjust the cooler type for a PowerTransformer
, you can do the following:
from transformer_thermal_model.transformer import PowerTransformer
from transformer_thermal_model.cooler import CoolerType
from transformer_thermal_model.schemas import UserTransformerSpecifications
tr_specs = UserTransformerSpecifications(
load_loss=10000,
nom_load_sec_side=1000,
no_load_loss=1000,
amb_temp_surcharge=0,
)
# You can create a power transformer with ONAF cooling.
onaf_trafo = PowerTransformer(user_specs = tr_specs, cooling_type = CoolerType.ONAF)
# Or you can create a power transformer with ONAN cooling
onan_trafo = PowerTransformer(user_specs = tr_specs, cooling_type = CoolerType.ONAN)
When the hot-spot factor of a transformer is known, it can be given as a
specification as hot_spot_fact
in a UserTransformerSpecifications
object.
It often occurs, however, that a transformer hot-spot factor is not
known. If this is the case, a hot-spot factor calibration can be performed to determine
the hot-spot factor of a given PowerTransformer
object. Note that for
DistributionTransformer
objects, hot-spot calibrations should not be performed and the
default value can be used. For both the PowerTransformer
and the DistributionTransformer
the hot_spot_fac
in the specification is set to the default value of no hot-spot factor is provided via the UserTransformerSpecifications
.
The following example shows how to calibrate a PowerTransformer
object.
from transformer_thermal_model.cooler import CoolerType
from transformer_thermal_model.schemas import UserTransformerSpecifications
from transformer_thermal_model.transformer import PowerTransformer
from transformer_thermal_model.hot_spot_calibration import calibrate_hotspot_factor
tr_specs = UserTransformerSpecifications(
load_loss=1000, # Transformer load loss [W]
nom_load_sec_side=1500, # Transformer nominal current secondary side [A]
no_load_loss=200, # Transformer no-load loss [W]
amb_temp_surcharge=20, # Ambient temperature surcharge [K]
)
uncalibrated_transformer = PowerTransformer(user_specs=tr_specs, cooling_type=CoolerType.ONAF)
calibrated_trafo = calibrate_hotspot_factor(
uncalibrated_transformer=uncalibrated_transformer,
ambient_temp=20.0,
hot_spot_limit=98, # in most cases a hot-spot temperature limit of 98 can be used
hot_spot_factor_min=1.1,
hot_spot_factor_max=1.3,
)
The new hot-spot factor is available via calibrated_trafo.specs.hot_spot_fac
, and from now on used in the thermal model.
>>> print(calibrated_trafo.specs.hot_spot_fac)
1.1
For load capacity calculations it can be required to take into account the capacity of the different components of a power transformers. Therefore a functionality is available to calculate the relative capacity of the tap changers, the bushings (primary and secondary) and the internal current transformer. The capacity is defined as the ratio of the component capacity and the nominal load of the transformer.
The capacities are properties of the PowerTransformer
and require the TransformerComponentSpecifications
to be given
during initiating a PowerTransformer object.
In the following example for all components the required information is provided.
from transformer_thermal_model.components import BushingConfig, TransformerSide, VectorConfig
from transformer_thermal_model.cooler import CoolerType
from transformer_thermal_model.schemas import (
TransformerComponentSpecifications,
UserTransformerSpecifications,
)
from transformer_thermal_model.transformer import PowerTransformer
comp_specs = TransformerComponentSpecifications(
tap_chang_capacity=600, # Tap changer nominal current [A]
nom_load_prim_side=550, # Transformer nominal current primary side [A]
tap_chang_conf=VectorConfig.TRIANGLE_OUTSIDE, # Tap Changer configuration
tap_chang_side=TransformerSide.SECONDARY, # Tap changer side
prim_bush_capacity=600, # Primary bushing nominal current [A]
prim_bush_conf=BushingConfig.SINGLE_BUSHING, # Primary bushing configuration
sec_bush_capacity=1800, # Secondary bushing nominal current [A]
sec_bush_conf=BushingConfig.SINGLE_BUSHING, # Secondary bushing configuration
cur_trans_capacity=1300, # Current transformer nominal current [A]
cur_trans_conf=VectorConfig.STAR, # Current transformer configuration
cur_trans_side=TransformerSide.PRIMARY, # Current transformer side
)
user_specs = UserTransformerSpecifications(
load_loss=1000, # Transformer load loss [W]
nom_load_sec_side=1500, # Transformer nominal current secondary side [A]
no_load_loss=200, # Transformer no-load loss [W]
amb_temp_surcharge=20,
)
power_transformer = PowerTransformer(
user_specs=user_specs, cooling_type=CoolerType.ONAF, internal_component_specs=comp_specs
)
The resulting component capacities are available in power_transformer.component_capacities
:
>>> print(power_transformer.component_capacities)
{'tap_changer': 0.4, 'primary_bushings': 1.0909090909090908, 'secondary_bushings': 1.2, 'current_transformer': 2.3636363636363638}
Note that it is also possible to only define a subset of the components if not all components are present. Then only the component capacities of the provided components are available:
comp_specs = TransformerComponentSpecifications(
tap_chang_capacity=600, # Tap changer nominal current [A]
nom_load_prim_side=550, # Transformer nominal current primary side [A]
tap_chang_conf=VectorConfig.TRIANGLE_OUTSIDE, # Tap Changer configuration
tap_chang_side=TransformerSide.SECONDARY, # Tap changer side
)
power_transformer = PowerTransformer(
user_specs=user_specs, cooling_type=CoolerType.ONAF, internal_component_specs=comp_specs
)
This will generate the following result:
>>> print(power_transformer.component_capacities)
{'tap_changer': 0.4, 'primary_bushings': None, 'secondary_bushings': None, 'current_transformer': None}
When a Transformer
object is completely defined, the temperatures can be calculated using
transformer_thermal_model.model
: the core of the package. The Model
is
built as follows:
import pandas as pd
from transformer_thermal_model.model import Model
from transformer_thermal_model.cooler import CoolerType
from transformer_thermal_model.schemas import UserTransformerSpecifications, InputProfile
from transformer_thermal_model.transformer import PowerTransformer
# In this example the model is used to calculate the transformer temperature based on a load and ambient
# profile with a period of one week. Any duration can be chosen preferably with timestamps with an interval of
# 15 minute or lower. Larger timesteps will result in incorrect results but it *is* possible to calculate with them.
one_week = 4*24*7
datetime_index = pd.date_range("2020-01-01", periods=one_week, freq="15min")
# For the load (in A) and ambient temperature (in C) arbitrary constants profiles are chosen.
# It is also possible to use a realistic profile.
nominal_load = 100
load_points = pd.Series([nominal_load] * one_week, index=datetime_index)
ambient_temp = 21
temperature_points = pd.Series([ambient_temp] * one_week, index=datetime_index)
# Create an input object with the profiles
profile_input = InputProfile.create(
datetime_index = datetime_index,
load_profile = load_points,
ambient_temperature_profile = temperature_points
)
# Initialise a power transformer with cooling type ONAF and, besides the mandatory user specifications, default values.
tr_specs = UserTransformerSpecifications(
load_loss=1000, # Transformer load loss [W]
nom_load_sec_side=1500, # Transformer nominal current secondary side [A]
no_load_loss=200, # Transformer no-load loss [W]
amb_temp_surcharge=20, # Ambient temperature surcharge [K]
)
transformer = PowerTransformer(user_specs=tr_specs, cooling_type=CoolerType.ONAF)
model = Model(
temperature_profile = profile_input,
transformer = transformer
)
results = model.run()
# Get the results as pd.Series, with the same datetime_index as your input.
top_oil_temp_profile = results.top_oil_temp_profile
hot_spot_temp_profile = results.hot_spot_temp_profile
>>> top_oil_temp_profile.head(3)
2020-01-01 00:00:00 41.000000
2020-01-01 00:15:00 43.639919
2020-01-01 00:30:00 45.801302
>>> hot_spot_temp_profile.head(3)
2020-01-01 00:00:00 41.000000
2020-01-01 00:15:00 44.381177
2020-01-01 00:30:00 46.443459
You can use the Model
to run a calculation with either a PowerTransformer
or
a DistributionTransformer
. The model will return results
with the
top_oil_temperature
and hot_spot_temperature
as pd.Series
. More
specifically, the output will be in the form of OutputProfile
, as
defined in transformer_thermal_model.schemas
. The reason for using pd.Series
as output, is that the model uses the index
of the series that you have provided to run the
calculation, which also creates the benefit for you that you can
relate the result to your provided input for eventual
cross-validation or analysis.
The model also supports thermal modeling of three-winding transformers. To use this feature, provide both a
ThreeWindingTransformer
and a ThreeWindingInputProfile
as input to the Model
. The
ThreeWindingInputProfile
requires a separate load profile for each winding (high, medium, and low voltage sides),
all sharing the same length and datetime index.
With UserThreeWindingTransformerSpecifications
, you can specify the nominal load and winding oil gradient for each
winding, as well as the load losses between windings. The resulting hot-spot temperature profile is returned as a
DataFrame with columns for each winding, making it easy to analyze the results for each part of the transformer.
import pandas as pd
from transformer_thermal_model.cooler import CoolerType
from transformer_thermal_model.model import Model
from transformer_thermal_model.schemas import (
ThreeWindingInputProfile,
UserThreeWindingTransformerSpecifications,
WindingSpecifications,
)
from transformer_thermal_model.transformer import ThreeWindingTransformer
# Define the time range for your simulation
one_week = 4 * 24 * 7
datetime_index = pd.date_range("2020-01-01", periods=one_week, freq="15min")
# Create ambient temperature profile (can be a constant or a realistic profile)
ambient_temp = 21
temperature_points = pd.Series([ambient_temp] * one_week, index=datetime_index)
# Create load profiles for each winding (high, medium, low voltage sides)
load_profile_high_voltage_side = pd.Series([2000] * one_week, index=datetime_index)
load_profile_middle_voltage_side = pd.Series([1500] * one_week, index=datetime_index)
load_profile_low_voltage_side = pd.Series([1000] * one_week, index=datetime_index)
# Create the input profile for the three-winding transformer
profile_input = ThreeWindingInputProfile.create(
datetime_index=datetime_index,
ambient_temperature_profile=temperature_points,
load_profile_high_voltage_side=load_profile_high_voltage_side,
load_profile_middle_voltage_side=load_profile_middle_voltage_side,
load_profile_low_voltage_side=load_profile_low_voltage_side,
)
# Define the transformer specifications for each winding
user_specs = UserThreeWindingTransformerSpecifications(
no_load_loss=20,
amb_temp_surcharge=10,
lv_winding=WindingSpecifications(
nom_load=1000, winding_oil_gradient=20, hot_spot_fac=1.2, time_const_winding=1, nom_power=1000
),
mv_winding=WindingSpecifications(
nom_load=1000, winding_oil_gradient=20, hot_spot_fac=1.2, time_const_winding=1, nom_power=1000
),
hv_winding=WindingSpecifications(
nom_load=2000, winding_oil_gradient=20, hot_spot_fac=1.2, time_const_winding=1, nom_power=2000
),
load_loss_hv_lv=100,
load_loss_hv_mv=100,
load_loss_mv_lv=100,
)
# Create the transformer object
transformer = ThreeWindingTransformer(user_specs=user_specs, cooling_type=CoolerType.ONAN)
# Run the thermal model
model = Model(
temperature_profile=profile_input,
transformer=transformer
)
results = model.run()
# The results are returned as pandas Series/DataFrame, indexed by your datetime_index
top_oil_temp_profile = results.top_oil_temp_profile
hot_spot_temp_profile = results.hot_spot_temp_profile
top_oil_temp_profile = results.top_oil_temp_profile
hot_spot_temp_profile = results.hot_spot_temp_profile
>>> top_oil_temp_profile.head()
2020-01-01 00:00:00 31.000000
2020-01-01 00:15:00 40.212693
2020-01-01 00:30:00 48.198972
2020-01-01 00:45:00 55.122101
2020-01-01 01:00:00 61.123609
```text
>>> hot_spot_temp_profile.head()
low_voltage_side middle_voltage_side high_voltage_side
2020-01-01 00:00:00 31.000000 31.000000 31.000000
2020-01-01 00:15:00 84.991214 116.068422 84.991214
2020-01-01 00:30:00 90.234413 119.407866 90.234413
2020-01-01 00:45:00 94.756639 122.263816 94.756639
2020-01-01 01:00:00 98.676844 124.739555 98.676844
Optionally, you can provide the top oil temperature as an input parameter to the InputProfile
to use it in place of the ambient temperature as an input to the model:
import pandas as pd
from transformer_thermal_model.model import Model
from transformer_thermal_model.cooler import CoolerType
from transformer_thermal_model.schemas import UserTransformerSpecifications, InputProfile
from transformer_thermal_model.transformer import PowerTransformer
one_week = 4*24*7
datetime_index = pd.date_range("2020-01-01", periods=one_week, freq="15min")
nominal_load = 100
load_points = pd.Series([nominal_load] * one_week, index=datetime_index)
ambient_temp = 21
temperature_points = pd.Series([ambient_temp] * one_week, index=datetime_index)
top_oil_temp = 42
top_oil_points = pd.Series([top_oil_temp] * one_week, index=datetime_index)
profile_input = InputProfile.create(
datetime_index = datetime_index,
load_profile = load_points,
ambient_temperature_profile = temperature_points,
# Here is where we add the top oil temperature as an input. It has the same shape as the ambient temperature.
top_oil_temperature_profile = top_oil_points
)
tr_specs = UserTransformerSpecifications(
load_loss=1000, # Transformer load loss [W]
nom_load_sec_side=1500, # Transformer nominal current secondary side [A]
no_load_loss=200, # Transformer no-load loss [W]
amb_temp_surcharge=20, # Ambient temperature surcharge [K]
)
transformer = PowerTransformer(user_specs=tr_specs, cooling_type=CoolerType.ONAF)
model = Model(
temperature_profile = profile_input,
transformer = transformer
)
# As we have provided the top oil temperature as an input, this is now being used in place of the ambient temperature.
# If you still want to use the top oil temperature you can do so using model.run(force_use_ambient_temperature=True)
results = model.run()
top_oil_temp_profile = results.top_oil_temp_profile
hot_spot_temp_profile = results.hot_spot_temp_profile
>>> top_oil_temp_profile.head(3)
2020-01-01 00:00:00 42.0
2020-01-01 00:15:00 42.0
2020-01-01 00:30:00 42.0
>>> hot_spot_temp_profile.head(3)
2020-01-01 00:00:00 42.000000
2020-01-01 00:15:00 42.741258
2020-01-01 00:30:00 42.938711
Note, how the top oil temperature we receive as the output results.top_oil_temp_profile
exactly matches
the top oil temperature we provided as the input.
This project is licensed under the Mozilla Public License, version 2.0 - see LICENSE for details.
This project includes third-party libraries, which are licensed under their own respective Open-Source licenses. SPDX-License-Identifier headers are used to show which license is applicable.
The concerning license files can be found in the LICENSES directory.
Please read CODE_OF_CONDUCT, CONTRIBUTING and PROJECT GOVERNANCE for details on the process for submitting pull requests to us.
Please read SUPPORT for how to get in touch with the Transformer Thermal Model project.