-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support concentric neutral cables #16
Merged
Merged
Changes from 5 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
5187fa1
use delta for more concise formulation
AnjoMan 8845a58
Add test case based on Kersting
AnjoMan 949a7fd
Implement Carson's Equations for concentric neutral cables
veronicaguo 18fe874
Simplify equations before computing to avoid undefined terms
veronicaguo 8351582
Fix lint error
veronicaguo 9c9c85f
Refactor
veronicaguo 7ffb2b0
Get neutral wire positions from corresponding phase conductors
veronicaguo c6a6ed6
Put concentric model in init.py
veronicaguo 9d7e4ed
Test with IEEE37 underground cable config
veronicaguo 04b4c1a
Refactor tests
veronicaguo d2193b1
Fix flake8
veronicaguo 11c786a
Use separate helper for concentric model
veronicaguo 18a8d84
Flake8
veronicaguo c1c5a13
Assign set evaluations to variables
veronicaguo 53fa95f
Drop duplicating compute_P()
veronicaguo 7cdfd20
Add tests for single/two phase cables
veronicaguo 723ff87
Expose `impedance` as a stand-alone function
veronicaguo c578e9a
Update readme
veronicaguo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import pint | ||
from numpy import array | ||
from numpy.testing import assert_array_almost_equal | ||
|
||
from carsons.carsons import ConcentricNeutralCarsonsEquations | ||
from tests.test_carsons import OHM_PER_MILE_TO_OHM_PER_METER | ||
|
||
ureg = pint.UnitRegistry() | ||
|
||
feet = ureg.feet | ||
inches = ureg.inches | ||
miles = ureg.miles | ||
ohms = ureg.ohms | ||
|
||
|
||
def GMR_cn(GMR_s, k, R): | ||
veronicaguo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return (GMR_s * k * R**(k-1))**(1/k) | ||
|
||
|
||
class ABCCable: | ||
""" Modelled after Kerstings 'Distribution System Modeling and Analysis' | ||
pg. 102 example """ | ||
|
||
@property | ||
def neutral_strand_geometric_mean_radius(self): | ||
return { | ||
'NA': (0.00208*feet).to('meters').magnitude, | ||
'NB': (0.00208*feet).to('meters').magnitude, | ||
'NC': (0.00208*feet).to('meters').magnitude, | ||
} | ||
|
||
@property | ||
def neutral_strand_resistance(self): | ||
return { | ||
'NA': (14.87*ohms / miles).to('ohm / meters').magnitude, | ||
'NB': (14.87*ohms / miles).to('ohm / meters').magnitude, | ||
'NC': (14.87*ohms / miles).to('ohm / meters').magnitude, | ||
} | ||
|
||
@property | ||
def neutral_strand_diameter(self): | ||
return { | ||
'NA': (0.0641*inches).to('meters').magnitude, | ||
'NB': (0.0641*inches).to('meters').magnitude, | ||
'NC': (0.0641*inches).to('meters').magnitude, | ||
} | ||
|
||
@property | ||
def diameter_over_neutral(self): | ||
return { | ||
'NA': (1.29*inches).to('meters').magnitude, | ||
'NB': (1.29*inches).to('meters').magnitude, | ||
'NC': (1.29*inches).to('meters').magnitude, | ||
} | ||
|
||
@property | ||
def resistance(self): | ||
return { | ||
'A': (0.4100*(ohms / miles)).to('ohm / meters').magnitude, | ||
'B': (0.4100*(ohms / miles)).to('ohm / meters').magnitude, | ||
'C': (0.4100*(ohms / miles)).to('ohm / meters').magnitude, | ||
} | ||
|
||
@property | ||
def geometric_mean_radius(self): | ||
return { | ||
'A': (0.0171*feet).to('meters').magnitude, | ||
'B': (0.0171*feet).to('meters').magnitude, | ||
'C': (0.0171*feet).to('meters').magnitude, | ||
} | ||
|
||
@property | ||
def wire_positions(self): | ||
return { | ||
'A': (0, 0), | ||
'B': ((6*inches).to('meters').magnitude, 0), | ||
'C': ((12*inches).to('meters').magnitude, 0), | ||
'NA': (0, 0), | ||
'NB': ((6*inches).to('meters').magnitude, 0), | ||
'NC': ((12*inches).to('meters').magnitude, 0), | ||
} | ||
|
||
@property | ||
def neutral_strand_count(self): | ||
return { | ||
'NA': 13, | ||
'NB': 13, | ||
'NC': 13, | ||
} | ||
|
||
@property | ||
def phases(self): | ||
return ['A', 'B', 'C', 'NA', 'NB', 'NC'] | ||
|
||
|
||
def test_concentric_neutral_cable(): | ||
model = ConcentricNeutralCarsonsEquations(ABCCable()) | ||
|
||
assert_array_almost_equal( | ||
model.impedance, | ||
array([ | ||
[0.7981 + 1j*0.4467, 0.3188 + 1j*0.0334, 0.2848 + 1j*0.0138], | ||
[0.3188 + 1j*0.0334, 0.7890 + 1j*0.4048, 0.3188 + 1j*0.0334], | ||
[0.2848 + 1j*0.0138, 0.3188 + 1j*0.0334, 0.7981 + 1j*0.4467], | ||
|
||
veronicaguo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
]) * OHM_PER_MILE_TO_OHM_PER_METER, | ||
decimal=4 | ||
) | ||
EmilyYLMa marked this conversation as resolved.
Show resolved
Hide resolved
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comparison to Gridlab-d
To try and find the issues with the impedance calculations, I audited the gridlab-d source. I think this method differs from the Gridlab-d distance calculations in the following cases.
Background
Gridlab-d appears to use the following indexes for different phases. The snippets below use these phase indexes
Conductor to Neutral Cable
Python Implementation
In this case, the inputs are
I = {'A'}, J = {'N'}
This leads to the following:
Thus the code passed the check on line 233 and returns
(distance_ij**2 + r**2) ** 0.5
.Gridlab-D Implementation
However, gridlab-d does the following in the case of A -> N:
Solution
I think the correct solution in this case is to return
distance_ij
Conductor to Own Concentric Neutral
Python Implementation
In this case, the inputs are
I = {'A'}, J = {'A', 'N'}
This leads to the following:
Thus the check on line 227 is true, and so
r
is returned. This value was calculated earlier on lines 200 and 201 asGridlab-d Distance
Gridlab-d does the following:
Solution
Divide by 24 on line 201 instead of 2. Additionally, check that the gridlab-d outer diameter is the diameter over the neutral.
Conductor to Different Phase Concentric Neutral
Python Implementation
In this case, the inputs are
I = {'A'}, J = {'B', 'N'}
This leads to the following:
Thus the check on line 233 is True, and so the python code returns
(distance_ij**2 + r**2) ** 0.5
Gridlab-d Implementation
In otherwords, the distance from A -> BN is the same as the distance from A -> B.
Concentric Neutral to Another Concentric Neutral
Python Implementation
In this case, the inputs are
I = {'A', 'N'}, J = {'B', 'N'}
This leads to the following:
Thus the check on line 227 and the check on line 233 are False and so
distance_ij
is returnedGridlab-d Implementation
In other words, the distance from AN -> BN is the same as the distance from A -> B. The code appears to be correct here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the thorough audit @etimberg ! A couple points here:
For case
Conductor to Own Concentric Neutral
, I think gridlab-d divides by24
to include unit conversion frominch
toft
. We handle everything using metric units, so dividing by2
to get radius from diameter.For case
Conductor to Different Phase Concentric Neutral
, our implementation follows the assumption and example given in the Kersting's book, approximating the concentric neutrals as one single wire directly above their respective phase conductors. So there comes the Pythagorean theorem.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense @veronicaguo re 2 instead of 24. For the
Conductor to Different Phase Concentric Neutral
case, I'm not sure that the distance calculation is correct. It assumes all the cables are in one horizontal plane because that's the only way the triangle becomes right angle. If the cables were arranged in a geometry similar to this image, the distance from the top conductor to one of the bottom concentric neutrals is formed by a non right triangle and so the extra term from the cosine law would need to be added.Maybe a way to simplify the code here is to calculate the position (x,y) of the concentric neutral in a prior step. Then, all you'd do here is lookup
distance_ij
. It might be worthwhile testing this function independently too for the following cases: