Skip to content

Commit 0968941

Browse files
authored
Merge pull request #37 from opusonesolutions/tape-shield-cable
Support Tape-shielded cables
2 parents b1d6254 + bb03e51 commit 0968941

File tree

4 files changed

+215
-2
lines changed

4 files changed

+215
-2
lines changed

README.md

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,51 @@ class Cable:
212212
For examples of how to use the model, see the [multi-conductor cable
213213
tests](https://github.com/opusonesolutions/carsons/blob/master/tests/test_multi_conductor.py).
214214

215-
Problem Description
215+
216+
### Tape Shield Cable
217+
218+
`carsons` also supports modelling of tape shield cables of any
219+
phasings. Its usage is very similar to the example above, only requiring
220+
a few more parameters about the tape shield conductors in the line model
221+
object.
222+
223+
```python
224+
from carsons import (TapeShieldedCableCarsonsEquations,
225+
calculate_impedance)
226+
227+
class Cable:
228+
resistance: {
229+
'A': per-length resistance of conductor A in ohm/meters
230+
...
231+
}
232+
geometric_mean_radius: {
233+
'A': geometric mean radius of conductor A in meters
234+
...
235+
}
236+
wire_positions: {
237+
'A': (x, y) cross-sectional position of conductor A in meters
238+
...
239+
}
240+
phases: {'A', ... }
241+
tape_shield_thickness: {
242+
'A': thickness of tape shield conductor on phase A cable in meters
243+
...
244+
}
245+
tape_shield_outer_diameter: {
246+
'A': outer diameter of tape shield conductor on phase A cable in meters
247+
...
248+
}
249+
250+
251+
cable_impedance = calculate_impedance(TapeShieldedCableCarsonsEquations(Cable()))
252+
```
253+
254+
For examples of how to use the model, see the [tape shielded cable
255+
tests](https://github.com/opusonesolutions/carsons/blob/master/tests/test_tape_shielded_cables.py).
256+
257+
258+
259+
## Problem Description
216260
-------------------
217261

218262
Carsons equations model an AC transmission or distribution line into an

carsons/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
calculate_sequence_impedances,
55
CarsonsEquations,
66
ConcentricNeutralCarsonsEquations, # noqa 401
7-
MultiConductorCarsonsEquations) # noqa 401
7+
MultiConductorCarsonsEquations, # noqa 401
8+
TapeShieldedCableCarsonsEquations) # noqa 401
89

910
name = "carsons"

carsons/carsons.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,67 @@ def GMR_cn(self, phase) -> float:
311311
return (GMR_s * k * R**(k-1))**(1/k)
312312

313313

314+
class TapeShieldedCableCarsonsEquations(ModifiedCarsonsEquations):
315+
316+
ρ_tape_shield = 1.7721e-8 # copper resistivity at 20 degrees, ohm-meter
317+
318+
def __init__(self, model, *args, **kwargs):
319+
super().__init__(model)
320+
self.ds = model.tape_shield_outer_diameter
321+
self.thickness = model.tape_shield_thickness
322+
323+
self.phases.extend(
324+
f'{ph}t' for ph in model.tape_shield_outer_diameter.keys()
325+
)
326+
327+
self.r.update({
328+
f'{ph}t': self.compute_shield_r(self.ds[ph], self.thickness[ph])
329+
for ph in model.tape_shield_outer_diameter.keys()
330+
})
331+
332+
self.gmr.update({
333+
f'{ph}t': self.compute_shield_gmr(self.ds[ph], self.thickness[ph])
334+
for ph in model.tape_shield_outer_diameter.keys()
335+
})
336+
337+
# set shield position to be the same as its phase conductor position
338+
tape_shield_positions = {
339+
f'{ph}t': self.phase_positions[ph]
340+
for ph in model.tape_shield_outer_diameter.keys()
341+
}
342+
self.phase_positions.update(tape_shield_positions)
343+
344+
@staticmethod
345+
def compute_shield_gmr(ds, thickness) -> float:
346+
return (ds - thickness) / 2
347+
348+
@classmethod
349+
def compute_shield_r(cls, ds, thickness) -> float:
350+
area = (π*(ds/2)**2) - (π*(ds/2 - thickness)**2)
351+
return cls.ρ_tape_shield/area
352+
353+
def compute_d(self, i, j) -> float:
354+
I, J = set(i), set(j)
355+
356+
one_tape_shield_same_phase = I ^ J == set('t')
357+
358+
if one_tape_shield_same_phase:
359+
return self.gmr[i] if 't' in i else self.gmr[j]
360+
else:
361+
return super().compute_d(i, j)
362+
363+
@property
364+
def conductors(self):
365+
neutral_conductors = sorted([
366+
ph for ph in self.phases if ph.startswith("N")
367+
])
368+
shield_conductors = sorted([
369+
ph for ph in self.phases if ph.endswith("t")
370+
])
371+
372+
return ['A', 'B', 'C'] + shield_conductors + neutral_conductors
373+
374+
314375
class MultiConductorCarsonsEquations(ModifiedCarsonsEquations):
315376
def __init__(self, model):
316377
super().__init__(model)

tests/test_tape_shielded_cables.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
from numpy import array
2+
from numpy.testing import assert_array_almost_equal
3+
4+
from carsons.carsons import (
5+
TapeShieldedCableCarsonsEquations,
6+
calculate_impedance,
7+
)
8+
from tests.test_overhead_line import OHM_PER_MILE_TO_OHM_PER_METER
9+
from tests.test_concentric_neutral_cable import ureg, feet, inches, miles, ohms
10+
11+
mils = ureg.mil_length
12+
13+
14+
class AN_Tape_Shielded_Cable:
15+
def __init__(self, n_pos):
16+
# parametrize with position of n-phase conductor
17+
if n_pos:
18+
self.n_pos = n_pos
19+
20+
@property
21+
def resistance(self):
22+
return {
23+
"A": (0.97 * (ohms / miles)).to("ohm / meters").magnitude,
24+
"N": (0.607 * (ohms / miles)).to("ohm / meters").magnitude,
25+
}
26+
27+
@property
28+
def geometric_mean_radius(self):
29+
return {
30+
"A": (0.0111 * feet).to("meters").magnitude,
31+
"N": (0.01113 * feet).to("meters").magnitude,
32+
}
33+
34+
@property
35+
def wire_positions(self):
36+
return {
37+
"A": (0, 0),
38+
"N": ((self.n_pos * inches).to("meters").magnitude, 0),
39+
}
40+
41+
@property
42+
def tape_shield_outer_diameter(self):
43+
return {
44+
"A": (0.88 * inches).to("meters").magnitude,
45+
}
46+
47+
@property
48+
def tape_shield_thickness(self):
49+
return {
50+
"A": (5 * mils).to("meters").magnitude,
51+
}
52+
53+
@property
54+
def phases(self):
55+
return [
56+
"A",
57+
"N",
58+
]
59+
60+
61+
def test_single_phase_tape_shield_with_neutral_Keirsting():
62+
# Example 4.4, Kiersting, Distribution System Modelling and Analysis
63+
# 4th Ed, Taylor&Francis, 2018
64+
65+
n_pos = 3 # n phase conductor placed 3 inches away from phase cond
66+
67+
tape_shielded_cable = TapeShieldedCableCarsonsEquations(
68+
AN_Tape_Shielded_Cable(n_pos)
69+
)
70+
assert_array_almost_equal(
71+
calculate_impedance(tape_shielded_cable),
72+
array(
73+
[
74+
# Kersting example has:
75+
# [1.3218 + 1j * 0.6744, ...]
76+
# but we think this is due to a numerical error in
77+
# the calculation of the tape shield resistivity
78+
[1.3325 + 1j * 0.6458, 0.0 + 1j * 0.0, 0 + 1j * 0],
79+
[0 + 1j * 0, 0 + 1j * 0, 0 + 1j * 0],
80+
[0 + 1j * 0, 0 + 1j * 0, 0 + 1j * 0],
81+
]
82+
)
83+
* OHM_PER_MILE_TO_OHM_PER_METER,
84+
decimal=5,
85+
)
86+
87+
88+
def test_single_phase_tape_shield_with_neutral_IEEE13():
89+
# Cable config #607, defined in IEEE13 test feeder
90+
# https://cmte.ieee.org/pes-testfeeders/resources/
91+
n_pos = 1 # n phase conductor placed 3 inches away from phase cond
92+
93+
tape_shielded_cable = TapeShieldedCableCarsonsEquations(
94+
AN_Tape_Shielded_Cable(n_pos)
95+
)
96+
assert_array_almost_equal(
97+
calculate_impedance(tape_shielded_cable),
98+
array(
99+
[
100+
[1.3425 + 1j * 0.5124, 0.0 + 1j * 0.0, 0 + 1j * 0],
101+
[0 + 1j * 0, 0 + 1j * 0, 0 + 1j * 0],
102+
[0 + 1j * 0, 0 + 1j * 0, 0 + 1j * 0],
103+
]
104+
)
105+
* OHM_PER_MILE_TO_OHM_PER_METER,
106+
decimal=5,
107+
)

0 commit comments

Comments
 (0)