Calculating relay operating times, according to IEC 60255
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
6
down vote
favorite
The script below is used to determine relay operating times, as defined in the standard IEC 60255. The equation and relevant information can be found here.
curve_equation
takes three input values, and outputs a list of values representing the trip times for currents in the fixed range np.logspace(np.log10(Is), 5, 1e2)
.
The part in the bottom plots the trip times for the different curves. The function curve_equation
will be used to much more than that, so I'm mostly interested in improvements to that one.
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 29 13:28:26 2018
@author: Stewie
"""
import numpy as np
import matplotlib.pyplot as plt
def curve_equation(curve_name, T, Is):
"""
This function calculates and returns the inverse curves for
the selected curve type.
Input:
curve_name: one of the strings: "SIT", "VIT", "LTI", "EIT", "UIT"
T: The time dial setting. Typically in the range 0.1 ... 1
Is: The current setting. Typically in the range 100-10000
The appropriate k, alpha and theta values are selected based on the
curve type.
"""
# Define constants to be used in the curve equation
k = (0.14, 13.5, 120, 80, 315.2)
alpha = (0.02, 1, 2, 2, 2.5)
beta = (2.97, 1.5, 13.33, 0.808, 1)
curve_types = ("SIT", "VIT", "LTI", "EIT", "UIT")
# idx is the index of the values we want
try:
idx = curve_types.index(curve_name)
except:
print("Non-existing curve-type")
return
I = np.logspace(np.log10(Is), 5, 1e2)
def td_equation():
td = k[idx]/((I/Is)**alpha[idx]-1) * (T / beta[idx])
return(td)
return(td_equation())
# For testing / plotting purposes:
curve_types = ("SIT", "VIT", "LTI", "EIT", "UIT")
I = np.logspace(1, 5, 1e2)
for curve_type in curve_types:
plt.loglog(I, curve_equation(curve_type, 1, 1e2), label=curve_type)
plt.xlabel("Current [A]")
plt.ylabel("Time [s]")
plt.title("IEC Time/current curves")
plt.grid()
plt.legend()
python python-3.x functional-programming matplotlib
add a comment |Â
up vote
6
down vote
favorite
The script below is used to determine relay operating times, as defined in the standard IEC 60255. The equation and relevant information can be found here.
curve_equation
takes three input values, and outputs a list of values representing the trip times for currents in the fixed range np.logspace(np.log10(Is), 5, 1e2)
.
The part in the bottom plots the trip times for the different curves. The function curve_equation
will be used to much more than that, so I'm mostly interested in improvements to that one.
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 29 13:28:26 2018
@author: Stewie
"""
import numpy as np
import matplotlib.pyplot as plt
def curve_equation(curve_name, T, Is):
"""
This function calculates and returns the inverse curves for
the selected curve type.
Input:
curve_name: one of the strings: "SIT", "VIT", "LTI", "EIT", "UIT"
T: The time dial setting. Typically in the range 0.1 ... 1
Is: The current setting. Typically in the range 100-10000
The appropriate k, alpha and theta values are selected based on the
curve type.
"""
# Define constants to be used in the curve equation
k = (0.14, 13.5, 120, 80, 315.2)
alpha = (0.02, 1, 2, 2, 2.5)
beta = (2.97, 1.5, 13.33, 0.808, 1)
curve_types = ("SIT", "VIT", "LTI", "EIT", "UIT")
# idx is the index of the values we want
try:
idx = curve_types.index(curve_name)
except:
print("Non-existing curve-type")
return
I = np.logspace(np.log10(Is), 5, 1e2)
def td_equation():
td = k[idx]/((I/Is)**alpha[idx]-1) * (T / beta[idx])
return(td)
return(td_equation())
# For testing / plotting purposes:
curve_types = ("SIT", "VIT", "LTI", "EIT", "UIT")
I = np.logspace(1, 5, 1e2)
for curve_type in curve_types:
plt.loglog(I, curve_equation(curve_type, 1, 1e2), label=curve_type)
plt.xlabel("Current [A]")
plt.ylabel("Time [s]")
plt.title("IEC Time/current curves")
plt.grid()
plt.legend()
python python-3.x functional-programming matplotlib
I get aNameError: name 'I' is not defined
error on theplt.loglog(I, â¦)
line.
â 200_success
Apr 29 at 19:19
@200_success thanks for noticing! It should work now. I made a mistake and removed that line.I
was already stored as a variable outside the function so I didn't get an error message when I removed it.
â Stewie Griffin
Apr 29 at 19:26
add a comment |Â
up vote
6
down vote
favorite
up vote
6
down vote
favorite
The script below is used to determine relay operating times, as defined in the standard IEC 60255. The equation and relevant information can be found here.
curve_equation
takes three input values, and outputs a list of values representing the trip times for currents in the fixed range np.logspace(np.log10(Is), 5, 1e2)
.
The part in the bottom plots the trip times for the different curves. The function curve_equation
will be used to much more than that, so I'm mostly interested in improvements to that one.
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 29 13:28:26 2018
@author: Stewie
"""
import numpy as np
import matplotlib.pyplot as plt
def curve_equation(curve_name, T, Is):
"""
This function calculates and returns the inverse curves for
the selected curve type.
Input:
curve_name: one of the strings: "SIT", "VIT", "LTI", "EIT", "UIT"
T: The time dial setting. Typically in the range 0.1 ... 1
Is: The current setting. Typically in the range 100-10000
The appropriate k, alpha and theta values are selected based on the
curve type.
"""
# Define constants to be used in the curve equation
k = (0.14, 13.5, 120, 80, 315.2)
alpha = (0.02, 1, 2, 2, 2.5)
beta = (2.97, 1.5, 13.33, 0.808, 1)
curve_types = ("SIT", "VIT", "LTI", "EIT", "UIT")
# idx is the index of the values we want
try:
idx = curve_types.index(curve_name)
except:
print("Non-existing curve-type")
return
I = np.logspace(np.log10(Is), 5, 1e2)
def td_equation():
td = k[idx]/((I/Is)**alpha[idx]-1) * (T / beta[idx])
return(td)
return(td_equation())
# For testing / plotting purposes:
curve_types = ("SIT", "VIT", "LTI", "EIT", "UIT")
I = np.logspace(1, 5, 1e2)
for curve_type in curve_types:
plt.loglog(I, curve_equation(curve_type, 1, 1e2), label=curve_type)
plt.xlabel("Current [A]")
plt.ylabel("Time [s]")
plt.title("IEC Time/current curves")
plt.grid()
plt.legend()
python python-3.x functional-programming matplotlib
The script below is used to determine relay operating times, as defined in the standard IEC 60255. The equation and relevant information can be found here.
curve_equation
takes three input values, and outputs a list of values representing the trip times for currents in the fixed range np.logspace(np.log10(Is), 5, 1e2)
.
The part in the bottom plots the trip times for the different curves. The function curve_equation
will be used to much more than that, so I'm mostly interested in improvements to that one.
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 29 13:28:26 2018
@author: Stewie
"""
import numpy as np
import matplotlib.pyplot as plt
def curve_equation(curve_name, T, Is):
"""
This function calculates and returns the inverse curves for
the selected curve type.
Input:
curve_name: one of the strings: "SIT", "VIT", "LTI", "EIT", "UIT"
T: The time dial setting. Typically in the range 0.1 ... 1
Is: The current setting. Typically in the range 100-10000
The appropriate k, alpha and theta values are selected based on the
curve type.
"""
# Define constants to be used in the curve equation
k = (0.14, 13.5, 120, 80, 315.2)
alpha = (0.02, 1, 2, 2, 2.5)
beta = (2.97, 1.5, 13.33, 0.808, 1)
curve_types = ("SIT", "VIT", "LTI", "EIT", "UIT")
# idx is the index of the values we want
try:
idx = curve_types.index(curve_name)
except:
print("Non-existing curve-type")
return
I = np.logspace(np.log10(Is), 5, 1e2)
def td_equation():
td = k[idx]/((I/Is)**alpha[idx]-1) * (T / beta[idx])
return(td)
return(td_equation())
# For testing / plotting purposes:
curve_types = ("SIT", "VIT", "LTI", "EIT", "UIT")
I = np.logspace(1, 5, 1e2)
for curve_type in curve_types:
plt.loglog(I, curve_equation(curve_type, 1, 1e2), label=curve_type)
plt.xlabel("Current [A]")
plt.ylabel("Time [s]")
plt.title("IEC Time/current curves")
plt.grid()
plt.legend()
python python-3.x functional-programming matplotlib
edited Apr 29 at 19:24
asked Apr 29 at 18:45
Stewie Griffin
1,717831
1,717831
I get aNameError: name 'I' is not defined
error on theplt.loglog(I, â¦)
line.
â 200_success
Apr 29 at 19:19
@200_success thanks for noticing! It should work now. I made a mistake and removed that line.I
was already stored as a variable outside the function so I didn't get an error message when I removed it.
â Stewie Griffin
Apr 29 at 19:26
add a comment |Â
I get aNameError: name 'I' is not defined
error on theplt.loglog(I, â¦)
line.
â 200_success
Apr 29 at 19:19
@200_success thanks for noticing! It should work now. I made a mistake and removed that line.I
was already stored as a variable outside the function so I didn't get an error message when I removed it.
â Stewie Griffin
Apr 29 at 19:26
I get a
NameError: name 'I' is not defined
error on the plt.loglog(I, â¦)
line.â 200_success
Apr 29 at 19:19
I get a
NameError: name 'I' is not defined
error on the plt.loglog(I, â¦)
line.â 200_success
Apr 29 at 19:19
@200_success thanks for noticing! It should work now. I made a mistake and removed that line.
I
was already stored as a variable outside the function so I didn't get an error message when I removed it.â Stewie Griffin
Apr 29 at 19:26
@200_success thanks for noticing! It should work now. I made a mistake and removed that line.
I
was already stored as a variable outside the function so I didn't get an error message when I removed it.â Stewie Griffin
Apr 29 at 19:26
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
6
down vote
accepted
You need not declare # -*- coding: utf-8 -*-
in Python 3: UTF-8 is the default.
Writing I = np.logspace(â¦)
inside your curve_equation
function is bad practice, because it hard-codes certain x-values for your plot. In fact, your plot is wrong, because the calculations are for $I_s$ values ranging from 102ÃÂ A to 105ÃÂ A (due to the inner I = np.logspace(np.log10(Is), 5, 1e2)
), but your plot's x axis is labelled as if the values ranged from 101ÃÂ A to 105ÃÂ A (due to the outer I = np.logspace(1, 5, 1e2)
). Specifically, four of the curves should intersect at 1ÃÂ kA, 10ÃÂ s.
I also find the way in which the curves are specified very cumbersome. You have five magic strings ("SIT", "VIT", etc.) which you search for in curve_types
. Then, you retrieve the k
, alpha
, and beta
parameters by using the corresponding index. Printing an error message and returning None
is an inappropriate error-handling mechanism; you should raise or propagate an exception for such a fatal error.
I'd rather specify the parameters the other way: each curve should be defined as a $(k, alpha, beta)$ tuple. To do that, I would use namedtuple
s. I'd go a bit further and make each namedtuple
smart enough to know what its own $td(I)$ function looks like, when $T$ and $I_s$ are specified.
from collections import namedtuple
import numpy as np
import matplotlib.pyplot as plt
class IEC_Curve(namedtuple('IEC_Curve', 'name k alpha beta')):
def td(self, T, Is):
"""
The td(I) function for a given IEC curve, time dial setting, and
current setting.
"""
return lambda I: self.k * T / self.beta / ((I / Is)**self.alpha - 1)
SIT = IEC_Curve('SIT', k=0.14, alpha=0.02, beta=2.97) # Standard inverse / A
VIT = IEC_Curve('VIT', k=13.5, alpha=1, beta=1.5) # Very inverse / B
LTI = IEC_Curve('LTI', k=120, alpha=2, beta=13.33) # Long time inverse / B
EIT = IEC_Curve('EIT', k=80, alpha=2, beta=0.808) # Extremely inverse / C
UIT = IEC_Curve('UIT', k=315.2, alpha=2.5, beta=1) # Ultra inverse
I = np.logspace(2, 5, 1e2)
for curve in (SIT, VIT, LTI, EIT, UIT):
plt.loglog(I, curve.td(T=1, Is=1e2)(I), label=curve.name)
plt.xlabel("Current [A]")
plt.ylabel("Time [s]")
plt.title("IEC Time/current curves")
plt.grid()
plt.legend()
plt.show()
Note that td
is a method that returns a function. To calculate values of $td$ with fixed $T$, fixed $I_s$, and swept $I$:
UIT.td(T=1, Is=1e2)(I=np.logspace(2, 5, 1e2))
To calculate a value of $td$ for a given $T$, $I_s$, and $I$:
UIT.td(T=1, Is=1e2)(I=1e2)
(This happens to cause a ZeroDivisionError
, which manifests itself as a RuntimeWarning: divide by zero encountered in divide
at the beginning of the sweep.)
In case you feel intimidated by my use of inheritance of namedtuple
, you could use a manually written constructor instead:
class IEC_Curve:
def __init__(self, name, k, alpha, beta):
self.name = name
self.k = k
self.alpha = alpha
self.beta = beta
def td(self, T, Is):
return lambda I: self.k * T / self.beta / ((I / Is)**self.alpha - 1)
One difference is that namedtuple
s are immutable, whereas the members here are mutable.
Thanks! I was originally planning on using thenamedtuple
approach, but didn't know how to do it, since I've never heard of it. I only knew aboutkey, value
pairs, and I needed more than one value per key.
â Stewie Griffin
Apr 29 at 20:24
Hardcoding theI
-values was actually intentional, since the range of the plot is usually fixed, and givingI
as input would indicate that it's a variable, when it actually isn't. It's always fromIs
(which is already an input), and up to10**5
. Passing bothIs
andI
is unnecessary sinceI
doesn't give any information. I agree with you though... This is better!
â Stewie Griffin
Apr 29 at 20:28
How do I get the operating times (the list of values) from the function, when I know the curve type? I seldom want all values (that's why I have it as an input).
â Stewie Griffin
Apr 29 at 20:36
@StewieGriffin Just make it a dictionary with the names as the keys and theIEC_Curve
s as values.
â Graipher
Apr 29 at 20:44
Thank you so much for explaining how I can use it! This is great!
â Stewie Griffin
Apr 30 at 6:52
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
6
down vote
accepted
You need not declare # -*- coding: utf-8 -*-
in Python 3: UTF-8 is the default.
Writing I = np.logspace(â¦)
inside your curve_equation
function is bad practice, because it hard-codes certain x-values for your plot. In fact, your plot is wrong, because the calculations are for $I_s$ values ranging from 102ÃÂ A to 105ÃÂ A (due to the inner I = np.logspace(np.log10(Is), 5, 1e2)
), but your plot's x axis is labelled as if the values ranged from 101ÃÂ A to 105ÃÂ A (due to the outer I = np.logspace(1, 5, 1e2)
). Specifically, four of the curves should intersect at 1ÃÂ kA, 10ÃÂ s.
I also find the way in which the curves are specified very cumbersome. You have five magic strings ("SIT", "VIT", etc.) which you search for in curve_types
. Then, you retrieve the k
, alpha
, and beta
parameters by using the corresponding index. Printing an error message and returning None
is an inappropriate error-handling mechanism; you should raise or propagate an exception for such a fatal error.
I'd rather specify the parameters the other way: each curve should be defined as a $(k, alpha, beta)$ tuple. To do that, I would use namedtuple
s. I'd go a bit further and make each namedtuple
smart enough to know what its own $td(I)$ function looks like, when $T$ and $I_s$ are specified.
from collections import namedtuple
import numpy as np
import matplotlib.pyplot as plt
class IEC_Curve(namedtuple('IEC_Curve', 'name k alpha beta')):
def td(self, T, Is):
"""
The td(I) function for a given IEC curve, time dial setting, and
current setting.
"""
return lambda I: self.k * T / self.beta / ((I / Is)**self.alpha - 1)
SIT = IEC_Curve('SIT', k=0.14, alpha=0.02, beta=2.97) # Standard inverse / A
VIT = IEC_Curve('VIT', k=13.5, alpha=1, beta=1.5) # Very inverse / B
LTI = IEC_Curve('LTI', k=120, alpha=2, beta=13.33) # Long time inverse / B
EIT = IEC_Curve('EIT', k=80, alpha=2, beta=0.808) # Extremely inverse / C
UIT = IEC_Curve('UIT', k=315.2, alpha=2.5, beta=1) # Ultra inverse
I = np.logspace(2, 5, 1e2)
for curve in (SIT, VIT, LTI, EIT, UIT):
plt.loglog(I, curve.td(T=1, Is=1e2)(I), label=curve.name)
plt.xlabel("Current [A]")
plt.ylabel("Time [s]")
plt.title("IEC Time/current curves")
plt.grid()
plt.legend()
plt.show()
Note that td
is a method that returns a function. To calculate values of $td$ with fixed $T$, fixed $I_s$, and swept $I$:
UIT.td(T=1, Is=1e2)(I=np.logspace(2, 5, 1e2))
To calculate a value of $td$ for a given $T$, $I_s$, and $I$:
UIT.td(T=1, Is=1e2)(I=1e2)
(This happens to cause a ZeroDivisionError
, which manifests itself as a RuntimeWarning: divide by zero encountered in divide
at the beginning of the sweep.)
In case you feel intimidated by my use of inheritance of namedtuple
, you could use a manually written constructor instead:
class IEC_Curve:
def __init__(self, name, k, alpha, beta):
self.name = name
self.k = k
self.alpha = alpha
self.beta = beta
def td(self, T, Is):
return lambda I: self.k * T / self.beta / ((I / Is)**self.alpha - 1)
One difference is that namedtuple
s are immutable, whereas the members here are mutable.
Thanks! I was originally planning on using thenamedtuple
approach, but didn't know how to do it, since I've never heard of it. I only knew aboutkey, value
pairs, and I needed more than one value per key.
â Stewie Griffin
Apr 29 at 20:24
Hardcoding theI
-values was actually intentional, since the range of the plot is usually fixed, and givingI
as input would indicate that it's a variable, when it actually isn't. It's always fromIs
(which is already an input), and up to10**5
. Passing bothIs
andI
is unnecessary sinceI
doesn't give any information. I agree with you though... This is better!
â Stewie Griffin
Apr 29 at 20:28
How do I get the operating times (the list of values) from the function, when I know the curve type? I seldom want all values (that's why I have it as an input).
â Stewie Griffin
Apr 29 at 20:36
@StewieGriffin Just make it a dictionary with the names as the keys and theIEC_Curve
s as values.
â Graipher
Apr 29 at 20:44
Thank you so much for explaining how I can use it! This is great!
â Stewie Griffin
Apr 30 at 6:52
add a comment |Â
up vote
6
down vote
accepted
You need not declare # -*- coding: utf-8 -*-
in Python 3: UTF-8 is the default.
Writing I = np.logspace(â¦)
inside your curve_equation
function is bad practice, because it hard-codes certain x-values for your plot. In fact, your plot is wrong, because the calculations are for $I_s$ values ranging from 102ÃÂ A to 105ÃÂ A (due to the inner I = np.logspace(np.log10(Is), 5, 1e2)
), but your plot's x axis is labelled as if the values ranged from 101ÃÂ A to 105ÃÂ A (due to the outer I = np.logspace(1, 5, 1e2)
). Specifically, four of the curves should intersect at 1ÃÂ kA, 10ÃÂ s.
I also find the way in which the curves are specified very cumbersome. You have five magic strings ("SIT", "VIT", etc.) which you search for in curve_types
. Then, you retrieve the k
, alpha
, and beta
parameters by using the corresponding index. Printing an error message and returning None
is an inappropriate error-handling mechanism; you should raise or propagate an exception for such a fatal error.
I'd rather specify the parameters the other way: each curve should be defined as a $(k, alpha, beta)$ tuple. To do that, I would use namedtuple
s. I'd go a bit further and make each namedtuple
smart enough to know what its own $td(I)$ function looks like, when $T$ and $I_s$ are specified.
from collections import namedtuple
import numpy as np
import matplotlib.pyplot as plt
class IEC_Curve(namedtuple('IEC_Curve', 'name k alpha beta')):
def td(self, T, Is):
"""
The td(I) function for a given IEC curve, time dial setting, and
current setting.
"""
return lambda I: self.k * T / self.beta / ((I / Is)**self.alpha - 1)
SIT = IEC_Curve('SIT', k=0.14, alpha=0.02, beta=2.97) # Standard inverse / A
VIT = IEC_Curve('VIT', k=13.5, alpha=1, beta=1.5) # Very inverse / B
LTI = IEC_Curve('LTI', k=120, alpha=2, beta=13.33) # Long time inverse / B
EIT = IEC_Curve('EIT', k=80, alpha=2, beta=0.808) # Extremely inverse / C
UIT = IEC_Curve('UIT', k=315.2, alpha=2.5, beta=1) # Ultra inverse
I = np.logspace(2, 5, 1e2)
for curve in (SIT, VIT, LTI, EIT, UIT):
plt.loglog(I, curve.td(T=1, Is=1e2)(I), label=curve.name)
plt.xlabel("Current [A]")
plt.ylabel("Time [s]")
plt.title("IEC Time/current curves")
plt.grid()
plt.legend()
plt.show()
Note that td
is a method that returns a function. To calculate values of $td$ with fixed $T$, fixed $I_s$, and swept $I$:
UIT.td(T=1, Is=1e2)(I=np.logspace(2, 5, 1e2))
To calculate a value of $td$ for a given $T$, $I_s$, and $I$:
UIT.td(T=1, Is=1e2)(I=1e2)
(This happens to cause a ZeroDivisionError
, which manifests itself as a RuntimeWarning: divide by zero encountered in divide
at the beginning of the sweep.)
In case you feel intimidated by my use of inheritance of namedtuple
, you could use a manually written constructor instead:
class IEC_Curve:
def __init__(self, name, k, alpha, beta):
self.name = name
self.k = k
self.alpha = alpha
self.beta = beta
def td(self, T, Is):
return lambda I: self.k * T / self.beta / ((I / Is)**self.alpha - 1)
One difference is that namedtuple
s are immutable, whereas the members here are mutable.
Thanks! I was originally planning on using thenamedtuple
approach, but didn't know how to do it, since I've never heard of it. I only knew aboutkey, value
pairs, and I needed more than one value per key.
â Stewie Griffin
Apr 29 at 20:24
Hardcoding theI
-values was actually intentional, since the range of the plot is usually fixed, and givingI
as input would indicate that it's a variable, when it actually isn't. It's always fromIs
(which is already an input), and up to10**5
. Passing bothIs
andI
is unnecessary sinceI
doesn't give any information. I agree with you though... This is better!
â Stewie Griffin
Apr 29 at 20:28
How do I get the operating times (the list of values) from the function, when I know the curve type? I seldom want all values (that's why I have it as an input).
â Stewie Griffin
Apr 29 at 20:36
@StewieGriffin Just make it a dictionary with the names as the keys and theIEC_Curve
s as values.
â Graipher
Apr 29 at 20:44
Thank you so much for explaining how I can use it! This is great!
â Stewie Griffin
Apr 30 at 6:52
add a comment |Â
up vote
6
down vote
accepted
up vote
6
down vote
accepted
You need not declare # -*- coding: utf-8 -*-
in Python 3: UTF-8 is the default.
Writing I = np.logspace(â¦)
inside your curve_equation
function is bad practice, because it hard-codes certain x-values for your plot. In fact, your plot is wrong, because the calculations are for $I_s$ values ranging from 102ÃÂ A to 105ÃÂ A (due to the inner I = np.logspace(np.log10(Is), 5, 1e2)
), but your plot's x axis is labelled as if the values ranged from 101ÃÂ A to 105ÃÂ A (due to the outer I = np.logspace(1, 5, 1e2)
). Specifically, four of the curves should intersect at 1ÃÂ kA, 10ÃÂ s.
I also find the way in which the curves are specified very cumbersome. You have five magic strings ("SIT", "VIT", etc.) which you search for in curve_types
. Then, you retrieve the k
, alpha
, and beta
parameters by using the corresponding index. Printing an error message and returning None
is an inappropriate error-handling mechanism; you should raise or propagate an exception for such a fatal error.
I'd rather specify the parameters the other way: each curve should be defined as a $(k, alpha, beta)$ tuple. To do that, I would use namedtuple
s. I'd go a bit further and make each namedtuple
smart enough to know what its own $td(I)$ function looks like, when $T$ and $I_s$ are specified.
from collections import namedtuple
import numpy as np
import matplotlib.pyplot as plt
class IEC_Curve(namedtuple('IEC_Curve', 'name k alpha beta')):
def td(self, T, Is):
"""
The td(I) function for a given IEC curve, time dial setting, and
current setting.
"""
return lambda I: self.k * T / self.beta / ((I / Is)**self.alpha - 1)
SIT = IEC_Curve('SIT', k=0.14, alpha=0.02, beta=2.97) # Standard inverse / A
VIT = IEC_Curve('VIT', k=13.5, alpha=1, beta=1.5) # Very inverse / B
LTI = IEC_Curve('LTI', k=120, alpha=2, beta=13.33) # Long time inverse / B
EIT = IEC_Curve('EIT', k=80, alpha=2, beta=0.808) # Extremely inverse / C
UIT = IEC_Curve('UIT', k=315.2, alpha=2.5, beta=1) # Ultra inverse
I = np.logspace(2, 5, 1e2)
for curve in (SIT, VIT, LTI, EIT, UIT):
plt.loglog(I, curve.td(T=1, Is=1e2)(I), label=curve.name)
plt.xlabel("Current [A]")
plt.ylabel("Time [s]")
plt.title("IEC Time/current curves")
plt.grid()
plt.legend()
plt.show()
Note that td
is a method that returns a function. To calculate values of $td$ with fixed $T$, fixed $I_s$, and swept $I$:
UIT.td(T=1, Is=1e2)(I=np.logspace(2, 5, 1e2))
To calculate a value of $td$ for a given $T$, $I_s$, and $I$:
UIT.td(T=1, Is=1e2)(I=1e2)
(This happens to cause a ZeroDivisionError
, which manifests itself as a RuntimeWarning: divide by zero encountered in divide
at the beginning of the sweep.)
In case you feel intimidated by my use of inheritance of namedtuple
, you could use a manually written constructor instead:
class IEC_Curve:
def __init__(self, name, k, alpha, beta):
self.name = name
self.k = k
self.alpha = alpha
self.beta = beta
def td(self, T, Is):
return lambda I: self.k * T / self.beta / ((I / Is)**self.alpha - 1)
One difference is that namedtuple
s are immutable, whereas the members here are mutable.
You need not declare # -*- coding: utf-8 -*-
in Python 3: UTF-8 is the default.
Writing I = np.logspace(â¦)
inside your curve_equation
function is bad practice, because it hard-codes certain x-values for your plot. In fact, your plot is wrong, because the calculations are for $I_s$ values ranging from 102ÃÂ A to 105ÃÂ A (due to the inner I = np.logspace(np.log10(Is), 5, 1e2)
), but your plot's x axis is labelled as if the values ranged from 101ÃÂ A to 105ÃÂ A (due to the outer I = np.logspace(1, 5, 1e2)
). Specifically, four of the curves should intersect at 1ÃÂ kA, 10ÃÂ s.
I also find the way in which the curves are specified very cumbersome. You have five magic strings ("SIT", "VIT", etc.) which you search for in curve_types
. Then, you retrieve the k
, alpha
, and beta
parameters by using the corresponding index. Printing an error message and returning None
is an inappropriate error-handling mechanism; you should raise or propagate an exception for such a fatal error.
I'd rather specify the parameters the other way: each curve should be defined as a $(k, alpha, beta)$ tuple. To do that, I would use namedtuple
s. I'd go a bit further and make each namedtuple
smart enough to know what its own $td(I)$ function looks like, when $T$ and $I_s$ are specified.
from collections import namedtuple
import numpy as np
import matplotlib.pyplot as plt
class IEC_Curve(namedtuple('IEC_Curve', 'name k alpha beta')):
def td(self, T, Is):
"""
The td(I) function for a given IEC curve, time dial setting, and
current setting.
"""
return lambda I: self.k * T / self.beta / ((I / Is)**self.alpha - 1)
SIT = IEC_Curve('SIT', k=0.14, alpha=0.02, beta=2.97) # Standard inverse / A
VIT = IEC_Curve('VIT', k=13.5, alpha=1, beta=1.5) # Very inverse / B
LTI = IEC_Curve('LTI', k=120, alpha=2, beta=13.33) # Long time inverse / B
EIT = IEC_Curve('EIT', k=80, alpha=2, beta=0.808) # Extremely inverse / C
UIT = IEC_Curve('UIT', k=315.2, alpha=2.5, beta=1) # Ultra inverse
I = np.logspace(2, 5, 1e2)
for curve in (SIT, VIT, LTI, EIT, UIT):
plt.loglog(I, curve.td(T=1, Is=1e2)(I), label=curve.name)
plt.xlabel("Current [A]")
plt.ylabel("Time [s]")
plt.title("IEC Time/current curves")
plt.grid()
plt.legend()
plt.show()
Note that td
is a method that returns a function. To calculate values of $td$ with fixed $T$, fixed $I_s$, and swept $I$:
UIT.td(T=1, Is=1e2)(I=np.logspace(2, 5, 1e2))
To calculate a value of $td$ for a given $T$, $I_s$, and $I$:
UIT.td(T=1, Is=1e2)(I=1e2)
(This happens to cause a ZeroDivisionError
, which manifests itself as a RuntimeWarning: divide by zero encountered in divide
at the beginning of the sweep.)
In case you feel intimidated by my use of inheritance of namedtuple
, you could use a manually written constructor instead:
class IEC_Curve:
def __init__(self, name, k, alpha, beta):
self.name = name
self.k = k
self.alpha = alpha
self.beta = beta
def td(self, T, Is):
return lambda I: self.k * T / self.beta / ((I / Is)**self.alpha - 1)
One difference is that namedtuple
s are immutable, whereas the members here are mutable.
edited Apr 30 at 0:12
answered Apr 29 at 20:16
200_success
123k14142399
123k14142399
Thanks! I was originally planning on using thenamedtuple
approach, but didn't know how to do it, since I've never heard of it. I only knew aboutkey, value
pairs, and I needed more than one value per key.
â Stewie Griffin
Apr 29 at 20:24
Hardcoding theI
-values was actually intentional, since the range of the plot is usually fixed, and givingI
as input would indicate that it's a variable, when it actually isn't. It's always fromIs
(which is already an input), and up to10**5
. Passing bothIs
andI
is unnecessary sinceI
doesn't give any information. I agree with you though... This is better!
â Stewie Griffin
Apr 29 at 20:28
How do I get the operating times (the list of values) from the function, when I know the curve type? I seldom want all values (that's why I have it as an input).
â Stewie Griffin
Apr 29 at 20:36
@StewieGriffin Just make it a dictionary with the names as the keys and theIEC_Curve
s as values.
â Graipher
Apr 29 at 20:44
Thank you so much for explaining how I can use it! This is great!
â Stewie Griffin
Apr 30 at 6:52
add a comment |Â
Thanks! I was originally planning on using thenamedtuple
approach, but didn't know how to do it, since I've never heard of it. I only knew aboutkey, value
pairs, and I needed more than one value per key.
â Stewie Griffin
Apr 29 at 20:24
Hardcoding theI
-values was actually intentional, since the range of the plot is usually fixed, and givingI
as input would indicate that it's a variable, when it actually isn't. It's always fromIs
(which is already an input), and up to10**5
. Passing bothIs
andI
is unnecessary sinceI
doesn't give any information. I agree with you though... This is better!
â Stewie Griffin
Apr 29 at 20:28
How do I get the operating times (the list of values) from the function, when I know the curve type? I seldom want all values (that's why I have it as an input).
â Stewie Griffin
Apr 29 at 20:36
@StewieGriffin Just make it a dictionary with the names as the keys and theIEC_Curve
s as values.
â Graipher
Apr 29 at 20:44
Thank you so much for explaining how I can use it! This is great!
â Stewie Griffin
Apr 30 at 6:52
Thanks! I was originally planning on using the
namedtuple
approach, but didn't know how to do it, since I've never heard of it. I only knew about key, value
pairs, and I needed more than one value per key.â Stewie Griffin
Apr 29 at 20:24
Thanks! I was originally planning on using the
namedtuple
approach, but didn't know how to do it, since I've never heard of it. I only knew about key, value
pairs, and I needed more than one value per key.â Stewie Griffin
Apr 29 at 20:24
Hardcoding the
I
-values was actually intentional, since the range of the plot is usually fixed, and giving I
as input would indicate that it's a variable, when it actually isn't. It's always from Is
(which is already an input), and up to 10**5
. Passing both Is
and I
is unnecessary since I
doesn't give any information. I agree with you though... This is better!â Stewie Griffin
Apr 29 at 20:28
Hardcoding the
I
-values was actually intentional, since the range of the plot is usually fixed, and giving I
as input would indicate that it's a variable, when it actually isn't. It's always from Is
(which is already an input), and up to 10**5
. Passing both Is
and I
is unnecessary since I
doesn't give any information. I agree with you though... This is better!â Stewie Griffin
Apr 29 at 20:28
How do I get the operating times (the list of values) from the function, when I know the curve type? I seldom want all values (that's why I have it as an input).
â Stewie Griffin
Apr 29 at 20:36
How do I get the operating times (the list of values) from the function, when I know the curve type? I seldom want all values (that's why I have it as an input).
â Stewie Griffin
Apr 29 at 20:36
@StewieGriffin Just make it a dictionary with the names as the keys and the
IEC_Curve
s as values.â Graipher
Apr 29 at 20:44
@StewieGriffin Just make it a dictionary with the names as the keys and the
IEC_Curve
s as values.â Graipher
Apr 29 at 20:44
Thank you so much for explaining how I can use it! This is great!
â Stewie Griffin
Apr 30 at 6:52
Thank you so much for explaining how I can use it! This is great!
â Stewie Griffin
Apr 30 at 6:52
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f193223%2fcalculating-relay-operating-times-according-to-iec-60255%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
I get a
NameError: name 'I' is not defined
error on theplt.loglog(I, â¦)
line.â 200_success
Apr 29 at 19:19
@200_success thanks for noticing! It should work now. I made a mistake and removed that line.
I
was already stored as a variable outside the function so I didn't get an error message when I removed it.â Stewie Griffin
Apr 29 at 19:26