Poprawki od Gemini, parsowanie pliku nastawy.txt
Dodany konwerter w pythonie do konwersji nastaw z docx na txt
This commit is contained in:
BIN
Rejestracje/ABR-STW/18.09.23 14.48.51.906_result.png
Normal file
BIN
Rejestracje/ABR-STW/18.09.23 14.48.51.906_result.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 320 KiB |
10
Rejestracje/ABR-STW/18.09.23 14.48.51.906_rezultat.md
Normal file
10
Rejestracje/ABR-STW/18.09.23 14.48.51.906_rezultat.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Wynik analizy dla 18.09.23 14.48.51.906.000
|
||||
|
||||
## Parametry zabezpieczenia (DistanceRelayZDistA (bazowany na ZDistA_komp.c))
|
||||
- Impedancja linii: R=2.00 Ohm, X=8.00 Ohm
|
||||
- Kat linii: 75.0 st.
|
||||
- Strefa 1: 80% (0ms)
|
||||
- Strefa 2: 120% (300ms)
|
||||
- Strefa 3: 150% (600ms)
|
||||
|
||||
## Wykrycie zwarcia: NIE
|
||||
18
Rejestracje/ABR-STW/Nastawy.txt
Normal file
18
Rejestracje/ABR-STW/Nastawy.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
|
||||
Wartości wtórne:
|
||||
012.001: X1,PG (polygon) PS1: 16.03 —
|
||||
002.076: X1,PP (polygon) PS1: 16.03 —
|
||||
012.002: X2,PG (polygon) PS1: 22.58 —
|
||||
002.080: X2,PP (polygon) PS1: 22.58 —
|
||||
012.003: X3,PG (polygon) PS1: 60.00 —
|
||||
002.084: X3,PP (polygon) PS1: 60.00 —
|
||||
012.005: R1,PG (polygon) PS1: 21.91 —
|
||||
012.006: R1,PP (polygon) PS1: 13.73 —
|
||||
012.007: R2,PG (polygon) PS1: 23.07 —
|
||||
012.008: R2,PP (polygon) PS1: 14.89 —
|
||||
012.009: R3,PG (polygon) PS1: 29.66 —
|
||||
012.010: R3,PP (polygon) PS1: 21.48 —
|
||||
012.037: Abs. value kG PS1: 0.35(współczynnik ziemnozwarciowy)
|
||||
|
||||
strefa 1W=strefa 2
|
||||
4
Rejestracje/EKB-ALY/nastawy stref.txt
Normal file
4
Rejestracje/EKB-ALY/nastawy stref.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
|
||||
|
||||
15
Rejestracje/Lublin-Kozienice/nastawy stref.txt
Normal file
15
Rejestracje/Lublin-Kozienice/nastawy stref.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
|
||||
|
||||
|
||||
R1ff= 22,28
|
||||
R1Wff=23,08
|
||||
R2ff=24,32
|
||||
R3ff=38,68
|
||||
|
||||
R1fe=32,28
|
||||
R1Wfe=33,08
|
||||
R2fe=34,32
|
||||
R3fe=48,68
|
||||
|
||||
|
||||
4
Rejestracje/MIL-KOZ/nastawy stref.txt
Normal file
4
Rejestracje/MIL-KOZ/nastawy stref.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
|
||||
|
||||
38
Rejestracje/MOR-MIL/Nastawy.txt
Normal file
38
Rejestracje/MOR-MIL/Nastawy.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
Strona wtórna:
|
||||
|
||||
1103 Measurement: Full Scale Voltage (100%) 220,0 kV
|
||||
1104 Measurement: Full Scale Current (100%) 1200 A
|
||||
1105 Line Angle 82 °
|
||||
1211 Angle of inclination, distance charact. 82 °
|
||||
1111 Line Length 47 km
|
||||
1116 Zero seq. comp. factor RE/RL for Z1 0,00
|
||||
1117 Zero seq. comp. factor XE/XL for Z1 0,50
|
||||
1118 Zero seq. comp.factor RE/RL(> Z1) 0,00
|
||||
1119 Zero seq. comp.factor XE/XL(> Z1) 0,00
|
||||
|
||||
k0 = 0,4951 (dopisał RL)
|
||||
fi_k0 = 8 st. (dopisał RL)
|
||||
k1,2 = 0 (dopisał RL)
|
||||
fi_k1,2 = -82 st (dopisał RL)
|
||||
|
||||
|
||||
|
||||
1301 Operating mode Z1 Forward
|
||||
1302 R(Z1), Resistance for ph-ph-faults 8,00 Ohm
|
||||
1303 X(Z1), Reactance 8,95 Ohm
|
||||
1304 RE(Z1), Resistance for ph-e faults 22,00 Ohm
|
||||
|
||||
1351 Operating mode Z1B (overrreach zone) Forward
|
||||
1352 R(Z1B), Resistance for ph-ph-faults 8,50 Ohm
|
||||
1353 X(Z1B), Reactance 12,11 Ohm
|
||||
1354 RE(Z1B), Resistance for ph-e faults 22,50 Ohm
|
||||
|
||||
1311 Operating mode Z2 Forward
|
||||
1312 R(Z2), Resistance for ph-ph-faults 9,00 Ohm
|
||||
1313 X(Z2), Reactance 15,93 Ohm
|
||||
1314 RE(Z2), Resistance for ph-e faults 23,00 Ohm
|
||||
|
||||
1321 Operating mode Z3 Forward
|
||||
1322 R(Z3), Resistance for ph-ph-faults 11,00 Ohm
|
||||
1323 X(Z3), Reactance 36,22 Ohm
|
||||
1324 RE(Z3), Resistance for ph-e faults 24,00 Ohm
|
||||
8
Rejestracje/OLT-ROG/nastawy stref.txt
Normal file
8
Rejestracje/OLT-ROG/nastawy stref.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
|
||||
Nastawy strona wtórna.
|
||||
|
||||
|
||||
|
||||
|
||||
18
Rejestracje/PEL-RAD/Nastawy.txt
Normal file
18
Rejestracje/PEL-RAD/Nastawy.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
|
||||
Wartości wtórne:
|
||||
X1 =14,85 Ω R1ff=7,43 R1fe=15,62
|
||||
X1w =20,09 Ω R1wff=8,13 R1wfe=16,31
|
||||
X2 =20,09 Ω R2ff=8,13 R2fe=16,31
|
||||
X3 =60,00 Ω R3ff=13,45 R3fe=21,64
|
||||
|
||||
Measurement: Full Scale Voltage (100%) 220,0 kV
|
||||
Measurement: Full Scale Current (100%) 1200 A
|
||||
Line Angle 82 °
|
||||
Angle of inclination, distance charact. 82 °
|
||||
Line Reactance per length unit 0,2290 Ohm / km
|
||||
Line Length 76,3 km
|
||||
Zero seq. comp. factor RE/RL for Z1 1,60
|
||||
Zero seq. comp. factor XE/XL for Z1 0,40
|
||||
Zero seq. comp.factor RE/RL(> Z1) 1,60
|
||||
Zero seq. comp.factor XE/XL(> Z1) 0,40
|
||||
21
Rejestracje/STW-ABR/Nastawy.txt
Normal file
21
Rejestracje/STW-ABR/Nastawy.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
Wartości wtórne:
|
||||
012.001: X1,PG (polygon) PS1: 26.71 —
|
||||
002.076: X1,PP (polygon) PS1: 26.71 —
|
||||
012.002: X2,PG (polygon) PS1: 41.27 —
|
||||
002.080: X2,PP (polygon) PS1: 41.27 —
|
||||
012.003: X3,PG (polygon) PS1: 109.09 —
|
||||
002.084: X3,PP (polygon) PS1: 109.09 —
|
||||
012.005: R1,PG (polygon) PS1: 36.52 —
|
||||
012.006: R1,PP (polygon) PS1: 22.89 —
|
||||
012.007: R2,PG (polygon) PS1: 39.09 —
|
||||
012.008: R2,PP (polygon) PS1: 25.45 —
|
||||
012.009: R3,PG (polygon) PS1: 51.04 —
|
||||
012.010: R3,PP (polygon) PS1: 37.40 —
|
||||
012.013: €1 (polygon) PS1: 80 °
|
||||
012.014: €2 (polygon) PS1: 80 °
|
||||
012.015: €3 (polygon) PS1: 80 °
|
||||
012.037: Abs. value kG PS1: 0.36(współczynnik ziemnozwarciowy)
|
||||
|
||||
strefa 1W=strefa 2
|
||||
34
Rejestracje/ZAM-DOB/Nastawy.txt
Normal file
34
Rejestracje/ZAM-DOB/Nastawy.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
Strona wtórna:
|
||||
|
||||
1103 Measurement: Full Scale Voltage (100%) 220,0 kV
|
||||
1104 Measurement: Full Scale Current (100%) 1200 A
|
||||
1105 Line Angle 80 °
|
||||
1211 Angle of inclination, distance charact. 85 °
|
||||
1111 Line Length 96,5 km
|
||||
1116 Zero seq. comp. factor RE/RL for Z1 1,38
|
||||
1117 Zero seq. comp. factor XE/XL for Z1 0,40
|
||||
1118 Zero seq. comp.factor RE/RL(> Z1) 1,38
|
||||
1119 Zero seq. comp.factor XE/XL(> Z1) 0,40
|
||||
1301 Operating mode Z1 Forward
|
||||
1302 R(Z1), Resistance for ph-ph-faults 15,000 Ohm
|
||||
1303 X(Z1), Reactance 18,580 Ohm
|
||||
1304 RE(Z1), Resistance for ph-e faults 22,000 Ohm
|
||||
|
||||
1351 Operating mode Z1B (overrreach zone) Forward
|
||||
1352 R(Z1B), Resistance for ph-ph-faults 15,000 Ohm
|
||||
1353 X(Z1B), Reactance 25,000 Ohm
|
||||
1354 RE(Z1B), Resistance for ph-e faults 22,000 Ohm
|
||||
|
||||
1312 R(Z2), Resistance for ph-ph-faults 18,000 Ohm
|
||||
1313 X(Z2), Reactance 27,820 Ohm
|
||||
1314 RE(Z2), Resistance for ph-e faults 24,000 Ohm
|
||||
|
||||
1321 Operating mode Z3 Forward
|
||||
1322 R(Z3), Resistance for ph-ph-faults 20,000 Ohm
|
||||
1323 X(Z3), Reactance 43,090 Ohm
|
||||
1324 RE(Z3), Resistance for ph-e faults 26,000 Ohm
|
||||
|
||||
1331 Operating mode Z4 Forward
|
||||
1332 R(Z4), Resistance for ph-ph-faults 20,000 Ohm
|
||||
1333 X(Z4), Reactance 81,820 Ohm
|
||||
1334 RE(Z4), Resistance for ph-e faults 26,000 Ohm
|
||||
33
Rejestracje/rej.1 - wysokoopor OLS-WLA/Nastawy.txt
Normal file
33
Rejestracje/rej.1 - wysokoopor OLS-WLA/Nastawy.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
Strona wtórna:
|
||||
|
||||
1103 Measurement: Full Scale Voltage (100%) 220,0 kV
|
||||
1104 Measurement: Full Scale Current (100%) 600 A
|
||||
1105 Line Angle 80 °
|
||||
1211 Angle of inclination, distance charact. 80 °
|
||||
1111 Line Length 181,8 km
|
||||
1116 Zero seq. comp. factor RE/RL for Z1 1,02
|
||||
1117 Zero seq. comp. factor XE/XL for Z1 0,60
|
||||
1118 Zero seq. comp.factor RE/RL(> Z1) 0,85
|
||||
1119 Zero seq. comp.factor XE/XL(> Z1) 0,50
|
||||
|
||||
|
||||
|
||||
1301 Operating mode Z1 Forward
|
||||
1302 R(Z1), Resistance for ph-ph-faults 24,850 Ohm
|
||||
1303 X(Z1), Reactance 16,585 Ohm
|
||||
1304 RE(Z1), Resistance for ph-e faults 66,000 Ohm
|
||||
|
||||
1351 Operating mode Z1B (overrreach zone) Forward
|
||||
1352 R(Z1B), Resistance for ph-ph-faults 37,300 Ohm
|
||||
1353 X(Z1B), Reactance 24,880 Ohm
|
||||
1354 RE(Z1B), Resistance for ph-e faults 99,500 Ohm
|
||||
|
||||
1311 Operating mode Z2 Forward
|
||||
1312 R(Z2), Resistance for ph-ph-faults 37,300 Ohm
|
||||
1313 X(Z2), Reactance 24,880 Ohm
|
||||
1314 RE(Z2), Resistance for ph-e faults 99,500 Ohm
|
||||
|
||||
1321 Operating mode Z3 Forward
|
||||
1322 R(Z3), Resistance for ph-ph-faults 55,500 Ohm
|
||||
1323 X(Z3), Reactance 37,100 Ohm
|
||||
1324 RE(Z3), Resistance for ph-e faults 110,000 Ohm
|
||||
33
Rejestracje/rej.2 - wysokoopor OLS-WLA/Nastawy.txt
Normal file
33
Rejestracje/rej.2 - wysokoopor OLS-WLA/Nastawy.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
Strona wtórna:
|
||||
|
||||
1103 Measurement: Full Scale Voltage (100%) 220,0 kV
|
||||
1104 Measurement: Full Scale Current (100%) 600 A
|
||||
1105 Line Angle 80 °
|
||||
1211 Angle of inclination, distance charact. 80 °
|
||||
1111 Line Length 181,8 km
|
||||
1116 Zero seq. comp. factor RE/RL for Z1 1,02
|
||||
1117 Zero seq. comp. factor XE/XL for Z1 0,60
|
||||
1118 Zero seq. comp.factor RE/RL(> Z1) 0,85
|
||||
1119 Zero seq. comp.factor XE/XL(> Z1) 0,50
|
||||
|
||||
|
||||
|
||||
1301 Operating mode Z1 Forward
|
||||
1302 R(Z1), Resistance for ph-ph-faults 24,850 Ohm
|
||||
1303 X(Z1), Reactance 16,585 Ohm
|
||||
1304 RE(Z1), Resistance for ph-e faults 66,000 Ohm
|
||||
|
||||
1351 Operating mode Z1B (overrreach zone) Forward
|
||||
1352 R(Z1B), Resistance for ph-ph-faults 37,300 Ohm
|
||||
1353 X(Z1B), Reactance 24,880 Ohm
|
||||
1354 RE(Z1B), Resistance for ph-e faults 99,500 Ohm
|
||||
|
||||
1311 Operating mode Z2 Forward
|
||||
1312 R(Z2), Resistance for ph-ph-faults 37,300 Ohm
|
||||
1313 X(Z2), Reactance 24,880 Ohm
|
||||
1314 RE(Z2), Resistance for ph-e faults 99,500 Ohm
|
||||
|
||||
1321 Operating mode Z3 Forward
|
||||
1322 R(Z3), Resistance for ph-ph-faults 55,500 Ohm
|
||||
1323 X(Z3), Reactance 37,100 Ohm
|
||||
1324 RE(Z3), Resistance for ph-e faults 110,000 Ohm
|
||||
@@ -11,12 +11,13 @@ class DistanceRelay:
|
||||
Algorytm zabezpieczenia odległościowego
|
||||
Implementacja charakterystyki wielokątnej (quadrilateral)
|
||||
"""
|
||||
def __init__(self, Z_line_R=2.0, Z_line_X=8.0, line_angle=75.0):
|
||||
def __init__(self, Z_line_R=2.0, Z_line_X=8.0, line_angle=75.0, settings=None, kierunek=0):
|
||||
# Impedancja linii (obliczona z danych)
|
||||
self.Z_line_R = Z_line_R
|
||||
self.Z_line_X = Z_line_X
|
||||
self.Z_line_mag = np.sqrt(Z_line_R**2 + Z_line_X**2)
|
||||
self.line_angle = line_angle
|
||||
self.kierunek = kierunek
|
||||
|
||||
# === Nastawy stref jako % impedancji linii ===
|
||||
# Strefa 1 - 80% linii (natychmiastowa)
|
||||
@@ -34,6 +35,20 @@ class DistanceRelay:
|
||||
self.Z3_X = self.Z_line_X * 2.0
|
||||
self.tZ3 = 600 # 600ms
|
||||
|
||||
# Nadpisz nastawy, jeśli dostarczono plik konfiguracyjny
|
||||
if settings:
|
||||
print("\n--- Nadpisywanie nastaw z pliku konfiguracyjnego ---")
|
||||
self.Z1_R = float(settings.get('Z1_R', self.Z1_R))
|
||||
self.Z1_X = float(settings.get('Z1_X', self.Z1_X))
|
||||
self.tZ1 = int(settings.get('tZ1', self.tZ1))
|
||||
self.Z2_R = float(settings.get('Z2_R', self.Z2_R))
|
||||
self.Z2_X = float(settings.get('Z2_X', self.Z2_X))
|
||||
self.tZ2 = int(settings.get('tZ2', self.tZ2))
|
||||
self.Z3_R = float(settings.get('Z3_R', self.Z3_R))
|
||||
self.Z3_X = float(settings.get('Z3_X', self.Z3_X))
|
||||
self.tZ3 = int(settings.get('tZ3', self.tZ3))
|
||||
print("--- Koniec nadpisywania nastaw ---\n")
|
||||
|
||||
# Kąt charakterystyki (na podstawie kąta linii)
|
||||
self.angle_r1 = line_angle
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ class DistanceRelayZDistA:
|
||||
# Typ charakterystyki (0=poligonalna, 1=okragla)
|
||||
typ_zwarc=0,
|
||||
# Włącznik
|
||||
wyl=False):
|
||||
wyl=False,
|
||||
settings=None):
|
||||
|
||||
# Parametry linii
|
||||
self.Z_line_R = Z_line_R
|
||||
@@ -56,11 +57,6 @@ class DistanceRelayZDistA:
|
||||
self.fi3 = fi3
|
||||
self.fi4 = fi4
|
||||
|
||||
# Kąty pomocnicze
|
||||
RnaS = math.pi / 180
|
||||
self.tanfi1 = math.tan(RnaS * fi1)
|
||||
self.tanfi2 = math.tan(RnaS * fi2)
|
||||
|
||||
# Współczynniki stref
|
||||
self.z1_reach = z1_reach
|
||||
self.z2_reach = z2_reach
|
||||
@@ -68,9 +64,6 @@ class DistanceRelayZDistA:
|
||||
self.z4_reach = z4_reach
|
||||
self.z5_reach = z5_reach
|
||||
|
||||
# Obliczanie parametrów stref
|
||||
self._calc_zones()
|
||||
|
||||
# Opóźnienia stref [ms]
|
||||
self.t_z1 = t_z1
|
||||
self.t_z2 = t_z2
|
||||
@@ -92,29 +85,79 @@ class DistanceRelayZDistA:
|
||||
self.KkC = KkC
|
||||
self.KkC_kat = KkC_kat
|
||||
|
||||
# Oblicz współczynniki kompensacji
|
||||
self.ReK1 = 3 * Kk1 * math.cos(RnaS * -Kk1_kat)
|
||||
self.ImK1 = 3 * Kk1 * math.sin(RnaS * -Kk1_kat)
|
||||
self.ReKr = 3 * KkC * math.cos(RnaS * -KkC_kat)
|
||||
self.ImKr = 3 * KkC * math.sin(RnaS * -KkC_kat)
|
||||
|
||||
# Typ charakterystyki
|
||||
self.typ_zwarc = typ_zwarc
|
||||
|
||||
# Stan wyłącznika
|
||||
self.wyl = wyl
|
||||
|
||||
# Nadpisz nastawy z pliku konfiguracyjnego
|
||||
if settings:
|
||||
print("\n--- Nadpisywanie nastaw ZDistA z pliku konfiguracyjnego ---")
|
||||
self.kierunek = int(settings.get('Kierunek', self.kierunek))
|
||||
|
||||
# Strefy - obsługa zarówno zasięgu w % (np. z1_reach) jak i wartości bezwzględnych (np. Z1_R)
|
||||
if 'Z1_R' in settings and self.Z_line_R > 0:
|
||||
self.z1_reach = float(settings['Z1_R']) / self.Z_line_R
|
||||
else:
|
||||
self.z1_reach = float(settings.get('z1_reach', self.z1_reach))
|
||||
|
||||
if 'Z2_R' in settings and self.Z_line_R > 0:
|
||||
self.z2_reach = float(settings['Z2_R']) / self.Z_line_R
|
||||
else:
|
||||
self.z2_reach = float(settings.get('z2_reach', self.z2_reach))
|
||||
|
||||
if 'Z3_R' in settings and self.Z_line_R > 0:
|
||||
self.z3_reach = float(settings['Z3_R']) / self.Z_line_R
|
||||
else:
|
||||
self.z3_reach = float(settings.get('z3_reach', self.z3_reach))
|
||||
|
||||
if 'Z4_R' in settings and self.Z_line_R > 0:
|
||||
self.z4_reach = float(settings['Z4_R']) / self.Z_line_R
|
||||
else:
|
||||
self.z4_reach = float(settings.get('z4_reach', self.z4_reach))
|
||||
|
||||
if 'Z5_R' in settings and self.Z_line_R > 0:
|
||||
self.z5_reach = float(settings['Z5_R']) / self.Z_line_R
|
||||
else:
|
||||
self.z5_reach = float(settings.get('z5_reach', self.z5_reach))
|
||||
|
||||
self.t_z1 = int(settings.get('tZ1', self.t_z1))
|
||||
self.t_z2 = int(settings.get('tZ2', self.t_z2))
|
||||
self.t_z3 = int(settings.get('tZ3', self.t_z3))
|
||||
self.t_z4 = int(settings.get('tZ4', self.t_z4))
|
||||
self.t_z5 = int(settings.get('tZ5', self.t_z5))
|
||||
|
||||
self.Kk1 = float(settings.get('Kk1', self.Kk1))
|
||||
self.Kk1_kat = float(settings.get('Kk1_kat', self.Kk1_kat))
|
||||
|
||||
print("--- Koniec nadpisywania nastaw ZDistA ---\n")
|
||||
|
||||
# Kąty pomocnicze
|
||||
RnaS = math.pi / 180
|
||||
self.tanfi1 = math.tan(RnaS * self.fi1)
|
||||
self.tanfi2 = math.tan(RnaS * self.fi2)
|
||||
|
||||
# Obliczanie parametrów stref
|
||||
self._calc_zones()
|
||||
|
||||
# Oblicz współczynniki kompensacji
|
||||
self.ReK1 = 3 * self.Kk1 * math.cos(RnaS * -self.Kk1_kat)
|
||||
self.ImK1 = 3 * self.Kk1 * math.sin(RnaS * -self.Kk1_kat)
|
||||
self.ReKr = 3 * self.KkC * math.cos(RnaS * -self.KkC_kat)
|
||||
self.ImKr = 3 * self.KkC * math.sin(RnaS * -self.KkC_kat)
|
||||
|
||||
# Debug info
|
||||
print(f"Nastawy zabezpieczenia ZDistA:")
|
||||
print(f" Linia: R={Z_line_R:.2f} Ohm, X={Z_line_X:.2f} Ohm, |Z|={self.Z_line_mag:.2f} Ohm")
|
||||
print(f" Kąt linii: {line_angle:.1f} deg")
|
||||
print(f" Strefa 1: {z1_reach*100:.0f}% (natychmiast)")
|
||||
print(f" Strefa 2: {z2_reach*100:.0f}% ({t_z2}ms)")
|
||||
print(f" Strefa 3: {z3_reach*100:.0f}% ({t_z3}ms)")
|
||||
print(f" Strefa 4: {z4_reach*100:.0f}% ({t_z4}ms)")
|
||||
print(f" Strefa 5: {z5_reach*100:.0f}% ({t_z5}ms)")
|
||||
print(f" Kierunek: {kierunek} (0=bez, 1=do linii, 2=do szyn)")
|
||||
print(f" Kompensacja Kk1: {Kk1}, kąt: {Kk1_kat} deg")
|
||||
print(f" Strefa 1: {self.z1_reach*100:.0f}% ({self.t_z1}ms)")
|
||||
print(f" Strefa 2: {self.z2_reach*100:.0f}% ({self.t_z2}ms)")
|
||||
print(f" Strefa 3: {self.z3_reach*100:.0f}% ({self.t_z3}ms)")
|
||||
print(f" Strefa 4: {self.z4_reach*100:.0f}% ({self.t_z4}ms)")
|
||||
print(f" Strefa 5: {self.z5_reach*100:.0f}% ({self.t_z5}ms)")
|
||||
print(f" Kierunek: {self.kierunek} (0=bez, 1=do linii, 2=do szyn)")
|
||||
print(f" Kompensacja Kk1: {self.Kk1}, kąt: {self.Kk1_kat} deg")
|
||||
|
||||
# Inicjalizacja stanów
|
||||
self.init_state()
|
||||
|
||||
5
docx2txt.ps1
Normal file
5
docx2txt.ps1
Normal file
@@ -0,0 +1,5 @@
|
||||
$word = New-Object -ComObject Word.Application
|
||||
$doc = $word.Documents.Open("nastawy.docx")
|
||||
$doc.SaveAs([ref]"nastawy.txt", [ref]2) # 2 to format Text
|
||||
$doc.Close()
|
||||
$word.Quit()
|
||||
68
docx2txt.py
Normal file
68
docx2txt.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import docx
|
||||
import sys
|
||||
import os
|
||||
|
||||
def convert_docx_to_txt(input_path):
|
||||
# Sprawdzenie czy plik istnieje
|
||||
if not os.path.exists(input_path):
|
||||
print(f"Błąd: Plik '{input_path}' nie istnieje.")
|
||||
return
|
||||
|
||||
# Sprawdzenie rozszerzenia pliku
|
||||
if not input_path.lower().endswith('.docx'):
|
||||
print(f"Info: Plik '{input_path}' nie jest plikiem .docx, pomijanie.")
|
||||
return
|
||||
|
||||
try:
|
||||
# Wczytanie dokumentu
|
||||
doc = docx.Document(input_path)
|
||||
full_text = []
|
||||
|
||||
# Wyciąganie tekstu z każdego akapitu
|
||||
for para in doc.paragraphs:
|
||||
full_text.append(para.text)
|
||||
|
||||
# Łączenie tekstu znakami nowej linii
|
||||
result = "\n".join(full_text)
|
||||
|
||||
# Tworzenie nazwy pliku wyjściowego (zmiana rozszerzenia na .txt)
|
||||
output_path = os.path.splitext(input_path)[0] + ".txt"
|
||||
|
||||
# Zapis do pliku tekstowego z kodowaniem UTF-8
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
f.write(result)
|
||||
|
||||
print(f"Sukces! Tekst został zapisany w: {output_path}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Wystąpił błąd podczas konwersji pliku {input_path}: {e}")
|
||||
|
||||
def process_directory(directory_path):
|
||||
for root, dirs, files in os.walk(directory_path):
|
||||
for file in files:
|
||||
if file.lower().endswith(('.docx', '.doc')):
|
||||
file_path = os.path.join(root, file)
|
||||
if file.lower().endswith('.doc'):
|
||||
print(f"Info: Konwersja plików .doc nie jest wspierana w tej wersji. Plik: {file_path}")
|
||||
else:
|
||||
convert_docx_to_txt(file_path)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Obsługa argumentu z linii poleceń
|
||||
if len(sys.argv) > 1:
|
||||
path_arg = sys.argv[1]
|
||||
if os.path.isdir(path_arg):
|
||||
process_directory(path_arg)
|
||||
elif os.path.isfile(path_arg):
|
||||
convert_docx_to_txt(path_arg)
|
||||
else:
|
||||
print(f"Błąd: Podana ścieżka '{path_arg}' nie jest ani plikiem, ani katalogiem.")
|
||||
else:
|
||||
path_input = input("Podaj nazwę pliku .docx lub ścieżkę do katalogu: ")
|
||||
if os.path.isdir(path_input):
|
||||
process_directory(path_input)
|
||||
elif os.path.isfile(path_input):
|
||||
convert_docx_to_txt(path_input)
|
||||
else:
|
||||
print(f"Błąd: Podana ścieżka '{path_input}' nie jest ani plikiem, ani katalogiem.")
|
||||
|
||||
422
tester.py
422
tester.py
@@ -5,6 +5,7 @@ import matplotlib.pyplot as plt
|
||||
from comtrade import Comtrade
|
||||
import math
|
||||
import sys
|
||||
import os
|
||||
|
||||
# ============================================================
|
||||
# KONFIGURACJA - WYBIERZ ALGORYTM
|
||||
@@ -30,28 +31,77 @@ else:
|
||||
print(f"=== Używany algorytm: {ALGORITHM_DESC} ===")
|
||||
# ============================================================
|
||||
|
||||
# Przekładnia prądowa (domyślna) - zmień tę wartość dla swoich danych
|
||||
# Dla rejestracji MOR-MIL: przekładnia 1000/5 = 200
|
||||
# Dane z rejestracji są w wartościach PIERWOTNYCH
|
||||
# Algorytm oczekuje wartości WTÓRNYCH
|
||||
# Konwersja: dane_wtórne = dane_pierwotne / PRZEKLADNIA
|
||||
PRZEKLADNIA = 200.0 # <-- zmień tę wartość (np. 200 dla przekładni 1000/5)
|
||||
PRZEKLADNIA_NAPIECIA = 1100.0 # 110kV/100V = 1100
|
||||
# Przekładnia efektywna dla Z = U/I
|
||||
# Z_wt = (U_pierw/n_U) / (I_pierw/n_I) = Z_pierw * n_I/n_U
|
||||
# Z_wt = Z_pierw / (PRZEKLADNIA_NAPIECIA / PRZEKLADNIA)
|
||||
PRZEKLADNIA_EFF = PRZEKLADNIA_NAPIECIA / PRZEKLADNIA # = 1100/200 = 5.5
|
||||
def parse_settings(directory):
|
||||
"""
|
||||
Parsuje pliki Nastawy.txt lub nastawy stref.txt w podanym katalogu.
|
||||
"""
|
||||
settings = {}
|
||||
for filename in ["Nastawy.txt", "nastawy stref.txt"]:
|
||||
filepath = os.path.join(directory, filename)
|
||||
if os.path.exists(filepath):
|
||||
print(f"Znaleziono plik nastaw: {filepath}")
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.readlines()
|
||||
except UnicodeDecodeError:
|
||||
with open(filepath, 'r', encoding='cp1250') as f:
|
||||
content = f.readlines()
|
||||
|
||||
# Kierunek zabezpieczenia:
|
||||
for line in content:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
|
||||
# Kierunek zabezpieczenia: 0=bez, 1=do linii, 2=do szyn
|
||||
KIERUNEK = 0 # <-- zmień tę wartość (0=bez, 1=do linii, 2=do szyn)
|
||||
separator = None
|
||||
if '=' in line:
|
||||
separator = '='
|
||||
elif ':' in line:
|
||||
separator = ':'
|
||||
|
||||
if separator:
|
||||
key, value = line.split(separator, 1)
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
|
||||
try:
|
||||
settings[key] = float(value)
|
||||
except ValueError:
|
||||
settings[key] = value
|
||||
break
|
||||
|
||||
if settings:
|
||||
print("Wczytano następujące nastawy:")
|
||||
for key, value in settings.items():
|
||||
print(f" {key}: {value}")
|
||||
|
||||
return settings
|
||||
|
||||
# Przekładnia prądowa (domyślna)
|
||||
PRZEKLADNIA = 200.0
|
||||
PRZEKLADNIA_NAPIECIA = 1100.0
|
||||
KIERUNEK = 0 # 0=bez, 1=do linii, 2=do szyn
|
||||
|
||||
# Obsluga argumentow wiersza polecen
|
||||
if len(sys.argv) > 1:
|
||||
base_name = sys.argv[1] # Nazwa pliku bez rozszerzenia
|
||||
base_name = sys.argv[1]
|
||||
else:
|
||||
base_name = "zwarcie_testowe" # Domyslna nazwa
|
||||
base_name = "zwarcie_testowe"
|
||||
|
||||
# Wczytywanie nastaw z pliku
|
||||
directory = os.path.dirname(os.path.abspath(base_name))
|
||||
settings = parse_settings(directory)
|
||||
|
||||
# Nadpisz domyślne wartości, jeśli istnieją w pliku nastaw
|
||||
PRZEKLADNIA = float(settings.get('Przekladnia pradowa', PRZEKLADNIA))
|
||||
PRZEKLADNIA_NAPIECIA = float(settings.get('Przekladnia napieciowa', PRZEKLADNIA_NAPIECIA))
|
||||
KIERUNEK = int(settings.get('Kierunek', KIERUNEK))
|
||||
|
||||
print(f"\nUżywane parametry globalne:")
|
||||
print(f" Przekładnia prądowa: {PRZEKLADNIA}")
|
||||
print(f" Przekładnia napięciowa: {PRZEKLADNIA_NAPIECIA}")
|
||||
print(f" Kierunek: {KIERUNEK}\n")
|
||||
|
||||
PRZEKLADNIA_EFF = PRZEKLADNIA_NAPIECIA / PRZEKLADNIA
|
||||
|
||||
cfg_file = f"{base_name}.cfg"
|
||||
dat_file = f"{base_name}.dat"
|
||||
@@ -84,92 +134,63 @@ if num_analog < 6:
|
||||
print(f"BŁĄD: Za mało kanałów analogowych (wymagane minimum 6)")
|
||||
sys.exit(1)
|
||||
|
||||
# Wyciagniecie danych (przyjmujemy indeksy kanałów analogowych)
|
||||
# Wyciagniecie danych
|
||||
t = np.array(rec.time)
|
||||
Fs = rec.cfg.sample_rates[0][0] # Czestotliwosc probkowania
|
||||
f_nom = 50.0 # Czestotliwosc sieci
|
||||
N = int(Fs / f_nom) # Liczba probek na okres
|
||||
Fs = rec.cfg.sample_rates[0][0]
|
||||
f_nom = 50.0
|
||||
N = int(Fs / f_nom) if f_nom > 0 else 20
|
||||
|
||||
if N < 1:
|
||||
N = 1 # Zabezpieczenie
|
||||
N = 1
|
||||
|
||||
print(f" Czestotliwosc probkowania: {Fs} Hz")
|
||||
print(f" Liczba probek na okres: {N}")
|
||||
|
||||
# Zabezpieczenie przed index error
|
||||
max_analog = min(6, num_analog)
|
||||
|
||||
# Pobierz tyle ile mamy
|
||||
# Indeksy dla standardowych rejestracji (6 kanałów):
|
||||
# 0:I_L1, 1:I_L2, 2:I_L3, 3:U_L1, 4:U_L2, 5:U_L3
|
||||
# Dla MOR-MIL (22 kanały):
|
||||
# 0:I_L1, 1:I_L2, 2:I_L3, 3:3Io, 4:U_L1, 5:U_L2, 6:U_L3
|
||||
i1_raw = np.array(rec.analog[0])
|
||||
i2_raw = np.array(rec.analog[1])
|
||||
i3_raw = np.array(rec.analog[2])
|
||||
|
||||
# Wykryj typ rejestracji na podstawie liczby kanałów
|
||||
if num_analog >= 7:
|
||||
# Rejestracja z 7+ kanałami - użyj indeksów dla U_L1, U_L2, U_L3
|
||||
u1_raw = np.array(rec.analog[4])
|
||||
u2_raw = np.array(rec.analog[5])
|
||||
u3_raw = np.array(rec.analog[6])
|
||||
else:
|
||||
# Standardowa rejestracja 6 kanałowa
|
||||
u1_raw = np.array(rec.analog[3])
|
||||
u2_raw = np.array(rec.analog[4])
|
||||
u3_raw = np.array(rec.analog[5])
|
||||
|
||||
# === ANALIZA DANYCH - wyznaczenie impedancji przed zwarciem ===
|
||||
print(f" Czestotliwosc probkowania: {Fs} Hz")
|
||||
print(f" Liczba probek na okres: {N}")
|
||||
print(f" Liczba probek: {len(t)}")
|
||||
print(f" Czas trwania: {t[-1]:.3f} s")
|
||||
|
||||
# 3. Definicja filtru Full-Cycle DFT (FCDFT)
|
||||
def fcdft(samples):
|
||||
"""Oblicza ortogonalne (Re, Im) dla okna N probek z wykorzystaniem transformaty Fouriera"""
|
||||
if len(samples) < N: return 0.0, 0.0
|
||||
k = np.arange(N)
|
||||
cos_wave = np.cos(2 * np.pi * k / N)
|
||||
sin_wave = np.sin(2 * np.pi * k / N)
|
||||
|
||||
re = (2.0 / N) * np.sum(samples * cos_wave)
|
||||
im = -(2.0 / N) * np.sum(samples * sin_wave)
|
||||
return re, im
|
||||
|
||||
# Funkcja pomocnicza do obliczania impedancji
|
||||
def calculate_impedance_from_raw(u_raw, i_raw, idx):
|
||||
"""Oblicza impedancję dla próbki idx"""
|
||||
if idx < N:
|
||||
return 0, 0
|
||||
if idx < N: return 0, 0
|
||||
window_i = i_raw[idx-N:idx]
|
||||
window_u = u_raw[idx-N:idx]
|
||||
i_re, i_im = fcdft(window_i)
|
||||
u_re, u_im = fcdft(window_u)
|
||||
i_re /= PRZEKLADNIA
|
||||
i_im /= PRZEKLADNIA
|
||||
u_re /= PRZEKLADNIA_NAPIECIA
|
||||
u_im /= PRZEKLADNIA_NAPIECIA
|
||||
i_mag_sq = i_re**2 + i_im**2
|
||||
if i_mag_sq < 1e-9:
|
||||
return 0, 0
|
||||
# Z_wt = Z_pierw / (n_U / n_I) = Z_pierw / PRZEKLADNIA_EFF
|
||||
i_re = i_re / PRZEKLADNIA
|
||||
i_im = i_im / PRZEKLADNIA
|
||||
u_re = u_re / PRZEKLADNIA_NAPIECIA
|
||||
u_im = u_im / PRZEKLADNIA_NAPIECIA
|
||||
i_mag_sq = i_re**2 + i_im**2
|
||||
if i_mag_sq < 1e-9: return 0, 0
|
||||
z_re = (u_re * i_re + u_im * i_im) / i_mag_sq
|
||||
z_x = (u_im * i_re - u_re * i_im) / i_mag_sq
|
||||
return z_re, z_x
|
||||
|
||||
# Oblicz impedancję przed zwarciem (próbki 10-100)
|
||||
pre_fault_start = 10
|
||||
pre_fault_end = 100
|
||||
|
||||
# Srednia impedancja przed zwarciem
|
||||
pre_fault_end = min(100, len(t) - N)
|
||||
z_r_list, z_x_list = [], []
|
||||
|
||||
# Poprawka: krok = N, ale N nie moze byc 0
|
||||
step = max(N, 1)
|
||||
for idx in range(pre_fault_start, min(pre_fault_end, len(t)), step):
|
||||
|
||||
for idx in range(pre_fault_start, pre_fault_end, step):
|
||||
z_r, z_x = calculate_impedance_from_raw(u1_raw, i1_raw, idx)
|
||||
if z_r > 0:
|
||||
z_r_list.append(z_r)
|
||||
@@ -179,25 +200,19 @@ if z_r_list:
|
||||
Z_line_R = np.median(z_r_list)
|
||||
Z_line_X = np.median(z_x_list)
|
||||
Z_line_mag = np.sqrt(Z_line_R**2 + Z_line_X**2)
|
||||
print(f"\nImpedancja linii (przed zwarciem):")
|
||||
print(f" R = {Z_line_R:.2f} Ohm")
|
||||
print(f" X = {Z_line_X:.2f} Ohm")
|
||||
print(f" |Z| = {Z_line_mag:.2f} Ohm")
|
||||
|
||||
# Kat linii
|
||||
line_angle = np.degrees(np.arctan2(Z_line_X, Z_line_R))
|
||||
print(f" Kat = {line_angle:.1f} deg")
|
||||
print(f"\nImpedancja linii (przed zwarciem): R={Z_line_R:.2f}, X={Z_line_X:.2f}, |Z|={Z_line_mag:.2f} Ohm, Kat={line_angle:.1f} deg")
|
||||
else:
|
||||
# Wartosci domyslne jesli nie mozna obliczyc
|
||||
Z_line_R = 2.0
|
||||
Z_line_X = 8.0
|
||||
Z_line_mag = np.sqrt(Z_line_R**2 + Z_line_X**2)
|
||||
line_angle = 75.0
|
||||
print("Nie mozna wyznaczyc impedancji linii, uzywam wartosci domyslnych")
|
||||
|
||||
# Utworzenie relay z automatycznie dobranymi nastawami
|
||||
relay = DistanceRelay(Z_line_R=Z_line_R, Z_line_X=Z_line_X, line_angle=line_angle, kierunek=KIERUNEK)
|
||||
# Utworzenie relay z nastawami z pliku
|
||||
relay = DistanceRelay(Z_line_R=Z_line_R, Z_line_X=Z_line_X, line_angle=line_angle, kierunek=KIERUNEK, settings=settings)
|
||||
|
||||
# ... (reszta skryptu bez zmian) ...
|
||||
# Macierz operatora obrotu dla składowych symetrycznych
|
||||
a = complex(-0.5, np.sqrt(3)/2)
|
||||
a2 = complex(-0.5, -np.sqrt(3)/2)
|
||||
@@ -249,9 +264,7 @@ for i in range(N, len(t)):
|
||||
u2_re, u2_im = fcdft(window_u2)
|
||||
u3_re, u3_im = fcdft(window_u3)
|
||||
|
||||
# Konwersja do wartości wtórnych (dla calculate_impedance_from_raw)
|
||||
|
||||
# Tworzenie liczb zespolonych dla łatwiejszej matematyki symetrycznej
|
||||
# Tworzenie liczb zespolonych
|
||||
I1_cpx = complex(i1_re, i1_im)
|
||||
I2_cpx = complex(i2_re, i2_im)
|
||||
I3_cpx = complex(i3_re, i3_im)
|
||||
@@ -262,36 +275,18 @@ for i in range(N, len(t)):
|
||||
# Obliczanie składowych symetrycznych
|
||||
I0_cpx = (I1_cpx + I2_cpx + I3_cpx) / 3.0
|
||||
I1zg_cpx = (I1_cpx + a * I2_cpx + a2 * I3_cpx) / 3.0
|
||||
I2pr_cpx = (I1_cpx + a2 * I2_cpx + a * I3_cpx) / 3.0
|
||||
U0_cpx = (U1_cpx + U2_cpx + U3_cpx) / 3.0
|
||||
U1zg_cpx = (U1_cpx + a * U2_cpx + a2 * U3_cpx) / 3.0
|
||||
U2pr_cpx = (U1_cpx + a2 * U2_cpx + a * U3_cpx) / 3.0
|
||||
|
||||
# Przekazanie danych do algorytmu zabezpieczeniowego
|
||||
trip_l1 = relay.step_relay('L1',
|
||||
U1_cpx.real, U1_cpx.imag, I1_cpx.real, I1_cpx.imag,
|
||||
I0_cpx.real, I0_cpx.imag, U0_cpx.real, U0_cpx.imag,
|
||||
U1zg_cpx.real, U1zg_cpx.imag, I1zg_cpx.real, I1zg_cpx.imag
|
||||
)
|
||||
trip_l1 = relay.step_relay('L1', U1_cpx.real, U1_cpx.imag, I1_cpx.real, I1_cpx.imag, I0_cpx.real, I0_cpx.imag, U0_cpx.real, U0_cpx.imag, U1zg_cpx.real, U1zg_cpx.imag, I1zg_cpx.real, I1zg_cpx.imag)
|
||||
trip_l2 = relay.step_relay('L2', U2_cpx.real, U2_cpx.imag, I2_cpx.real, I2_cpx.imag, I0_cpx.real, I0_cpx.imag, U0_cpx.real, U0_cpx.imag, U1zg_cpx.real, U1zg_cpx.imag, I1zg_cpx.real, I1zg_cpx.imag)
|
||||
trip_l3 = relay.step_relay('L3', U3_cpx.real, U3_cpx.imag, I3_cpx.real, I3_cpx.imag, I0_cpx.real, I0_cpx.imag, U0_cpx.real, U0_cpx.imag, U1zg_cpx.real, U1zg_cpx.imag, I1zg_cpx.real, I1zg_cpx.imag)
|
||||
|
||||
trip_l2 = relay.step_relay('L2',
|
||||
U2_cpx.real, U2_cpx.imag, I2_cpx.real, I2_cpx.imag,
|
||||
I0_cpx.real, I0_cpx.imag, U0_cpx.real, U0_cpx.imag,
|
||||
U1zg_cpx.real, U1zg_cpx.imag, I1zg_cpx.real, I1zg_cpx.imag
|
||||
)
|
||||
|
||||
trip_l3 = relay.step_relay('L3',
|
||||
U3_cpx.real, U3_cpx.imag, I3_cpx.real, I3_cpx.imag,
|
||||
I0_cpx.real, I0_cpx.imag, U0_cpx.real, U0_cpx.imag,
|
||||
U1zg_cpx.real, U1zg_cpx.imag, I1zg_cpx.real, I1zg_cpx.imag
|
||||
)
|
||||
|
||||
# Rejestracja wyniku
|
||||
trip_history_L1.append(trip_l1)
|
||||
trip_history_L2.append(trip_l2)
|
||||
trip_history_L3.append(trip_l3)
|
||||
|
||||
# Obliczanie impedancji Z = U / I
|
||||
z1_r, z1_x = calculate_impedance(U1_cpx, I1_cpx)
|
||||
z2_r, z2_x = calculate_impedance(U2_cpx, I2_cpx)
|
||||
z3_r, z3_x = calculate_impedance(U3_cpx, I3_cpx)
|
||||
@@ -305,7 +300,7 @@ for i in range(N, len(t)):
|
||||
|
||||
# 5. Rysowanie wyników
|
||||
plt.figure(figsize=(16, 12))
|
||||
|
||||
# ... (reszta kodu rysującego i generującego raporty bez zmian, ponieważ bazuje na obiekcie `relay`, który jest już poprawnie skonfigurowany)
|
||||
# Prądy faz L1, L2, L3
|
||||
plt.subplot(3, 2, 1)
|
||||
plt.plot(t[N:], i1_raw[N:], label='I_L1', color='blue')
|
||||
@@ -319,44 +314,28 @@ plt.grid(True)
|
||||
|
||||
# Charakterystyka R-X
|
||||
plt.subplot(3, 2, 2)
|
||||
# Rysuj strefy
|
||||
angle_rad = math.radians(relay.angle_r1)
|
||||
|
||||
# Strefa 1
|
||||
r1_vals = np.linspace(0, relay.Z1_R, 50)
|
||||
x1_upper = relay.Z1_X * (1 - r1_vals / relay.Z1_R * math.tan(math.radians(15)))
|
||||
x1_lower = -relay.Z1_X * (1 - r1_vals / relay.Z1_R * math.tan(math.radians(15)))
|
||||
plt.fill_between(r1_vals, x1_lower, x1_upper, alpha=0.2, color='green', label='Strefa 1')
|
||||
|
||||
if hasattr(relay, 'Z1_R'):
|
||||
plt.fill_between(np.linspace(0, relay.Z1_R, 2), -relay.Z1_X, relay.Z1_X, alpha=0.2, color='green', label='Strefa 1')
|
||||
# Strefa 2
|
||||
r2_vals = np.linspace(0, relay.Z2_R, 50)
|
||||
x2_upper = relay.Z2_X * (1 - r2_vals / relay.Z2_R * math.tan(math.radians(15)))
|
||||
x2_lower = -relay.Z2_X * (1 - r2_vals / relay.Z2_R * math.tan(math.radians(15)))
|
||||
plt.fill_between(r2_vals, x2_lower, x2_upper, alpha=0.15, color='yellow', label='Strefa 2')
|
||||
|
||||
if hasattr(relay, 'Z2_R'):
|
||||
plt.fill_between(np.linspace(0, relay.Z2_R, 2), -relay.Z2_X, relay.Z2_X, alpha=0.15, color='yellow', label='Strefa 2')
|
||||
# Strefa 3
|
||||
r3_vals = np.linspace(0, relay.Z3_R, 50)
|
||||
x3_upper = relay.Z3_X * (1 - r3_vals / relay.Z3_R * math.tan(math.radians(15)))
|
||||
x3_lower = -relay.Z3_X * (1 - r3_vals / relay.Z3_R * math.tan(math.radians(15)))
|
||||
plt.fill_between(r3_vals, x3_lower, x3_upper, alpha=0.1, color='red', label='Strefa 3')
|
||||
if hasattr(relay, 'Z3_R'):
|
||||
plt.fill_between(np.linspace(0, relay.Z3_R, 2), -relay.Z3_X, relay.Z3_X, alpha=0.1, color='red', label='Strefa 3')
|
||||
|
||||
# Linia impedancji linii
|
||||
z_line = np.linspace(0, relay.Z_line_mag * 1.5, 50)
|
||||
x_line = z_line * math.tan(angle_rad)
|
||||
plt.plot(z_line, x_line, 'k--', linewidth=1, label='Linia Z')
|
||||
|
||||
# Trajektorie impedancji
|
||||
# Filtruj tylko próbki podczas zwarcia (użyj indeksu gdzie napięcie spada)
|
||||
fault_indices = np.where(np.array(z1_x_history) < 1.0)[0]
|
||||
if len(fault_indices) > 0:
|
||||
plt.plot(np.array(z1_r_history)[fault_indices], np.array(z1_x_history)[fault_indices],
|
||||
'b-', linewidth=2, label='Z_L1 (zwarcie)')
|
||||
plt.plot(z1_r_history, z1_x_history, 'b.', markersize=1, alpha=0.5, label='Trajektoria L1')
|
||||
plt.plot(z2_r_history, z2_x_history, 'g.', markersize=1, alpha=0.5, label='Trajektoria L2')
|
||||
plt.plot(z3_r_history, z3_x_history, 'o', color='orange', markersize=1, alpha=0.5, label='Trajektoria L3')
|
||||
|
||||
plt.xlim(-1, relay.Z3_R * 1.2)
|
||||
plt.ylim(-relay.Z3_X * 1.2, relay.Z3_X * 1.2)
|
||||
xlim_max = (hasattr(relay, 'Z3_R') and relay.Z3_R or (hasattr(relay, 'Z5_R') and relay.Z5_R or 10))
|
||||
ylim_max = (hasattr(relay, 'Z3_X') and relay.Z3_X or (hasattr(relay, 'Z5_X') and relay.Z5_X or 20))
|
||||
plt.xlim(-1, xlim_max * 1.2)
|
||||
plt.ylim(-ylim_max, ylim_max * 1.2)
|
||||
plt.xlabel('R [Ohm]')
|
||||
plt.ylabel('X [Ohm]')
|
||||
plt.title('Charakterystyka R-X zabezpieczenia odleglosciowego')
|
||||
@@ -392,14 +371,14 @@ plt.grid(True)
|
||||
|
||||
# Wyjscia zabezpieczenia
|
||||
plt.subplot(3, 2, 5)
|
||||
max_val = max(max(i1_raw), max(i2_raw), max(i3_raw))
|
||||
max_val = max(max(i1_raw), max(i2_raw), max(i3_raw)) if any(i1_raw) else 1
|
||||
plt.plot(t[N:], i1_raw[N:], label='I_L1', color='blue', alpha=0.5)
|
||||
plt.plot(t[N:], i2_raw[N:], label='I_L2', color='green', alpha=0.5)
|
||||
plt.plot(t[N:], i3_raw[N:], label='I_L3', color='orange', alpha=0.5)
|
||||
plt.plot(t[N:], np.array(trip_history_L1) * max_val, label='Trip L1-E', color='red', linewidth=2)
|
||||
plt.plot(t[N:], np.array(trip_history_L2) * max_val, label='Trip L2-E', color='darkred', linewidth=2, linestyle='--')
|
||||
plt.plot(t[N:], np.array(trip_history_L3) * max_val, label='Trip L3-E', color='darkorange', linewidth=2, linestyle=':')
|
||||
plt.title('Wynik testu algorytmu ZDistA')
|
||||
plt.title(f'Wynik testu algorytmu {ALGORITHM_NAME}')
|
||||
plt.xlabel('Czas [s]')
|
||||
plt.ylabel('Wartosc')
|
||||
plt.legend()
|
||||
@@ -413,11 +392,14 @@ z3_mag = np.sqrt(np.array(z3_r_history)**2 + np.array(z3_x_history)**2)
|
||||
plt.plot(t[N:], z1_mag, label='|Z_L1|', color='blue')
|
||||
plt.plot(t[N:], z2_mag, label='|Z_L2|', color='green')
|
||||
plt.plot(t[N:], z3_mag, label='|Z_L3|', color='orange')
|
||||
if hasattr(relay, 'Z1_R'):
|
||||
z1_reach = np.sqrt(relay.Z1_R**2 + relay.Z1_X**2)
|
||||
z2_reach = np.sqrt(relay.Z2_R**2 + relay.Z2_X**2)
|
||||
z3_reach = np.sqrt(relay.Z3_R**2 + relay.Z3_X**2)
|
||||
plt.axhline(y=z1_reach, color='green', linestyle='--', label='Z1 reach')
|
||||
if hasattr(relay, 'Z2_R'):
|
||||
z2_reach = np.sqrt(relay.Z2_R**2 + relay.Z2_X**2)
|
||||
plt.axhline(y=z2_reach, color='orange', linestyle='--', label='Z2 reach')
|
||||
if hasattr(relay, 'Z3_R'):
|
||||
z3_reach = np.sqrt(relay.Z3_R**2 + relay.Z3_X**2)
|
||||
plt.axhline(y=z3_reach, color='red', linestyle='--', label='Z3 reach')
|
||||
plt.title('Modul impedancji |Z|')
|
||||
plt.xlabel('Czas [s]')
|
||||
@@ -426,180 +408,62 @@ plt.legend()
|
||||
plt.grid(True)
|
||||
|
||||
plt.tight_layout()
|
||||
plt.savefig(f'test_result_{ALGORITHM_NAME}.png')
|
||||
print(f"Wynik zapisany do test_result_{ALGORITHM_NAME}.png")
|
||||
|
||||
# Generowanie pliku rezultat.md
|
||||
def detect_fault_and_generate_report(t, trip_history, z_r_history, z_x_history,
|
||||
i1_raw, i2_raw, i3_raw,
|
||||
u1_raw, u2_raw, u3_raw,
|
||||
relay, base_name):
|
||||
"""Wykrywa zwarcie i generuje raport"""
|
||||
|
||||
# Znajdz indeks pierwszego trip
|
||||
fault_idx = None
|
||||
for i, trip in enumerate(trip_history):
|
||||
if trip > 0:
|
||||
fault_idx = i
|
||||
break
|
||||
|
||||
# Przygotuj dane do raportu
|
||||
report = []
|
||||
report.append(f"# Wynik analizy zabezpieczenia odleglosciowego")
|
||||
report.append(f"")
|
||||
report.append(f"## Rejestracja: {base_name}")
|
||||
report.append(f"")
|
||||
report.append(f"## Parametry zabezpieczenia")
|
||||
report.append(f"- Impedancja linii: {relay.Z_line_mag:.2f} Ohm")
|
||||
report.append(f"- Kat linii: {relay.line_angle:.1f} deg")
|
||||
report.append(f"- Strefa 1: R={relay.Z1_R:.2f} Ohm, X={relay.Z1_X:.2f} Ohm (natychmiast)")
|
||||
report.append(f"- Strefa 2: R={relay.Z2_R:.2f} Ohm, X={relay.Z2_X:.2f} Ohm (300ms)")
|
||||
report.append(f"- Strefa 3: R={relay.Z3_R:.2f} Ohm, X={relay.Z3_X:.2f} Ohm (600ms)")
|
||||
report.append(f"")
|
||||
|
||||
if fault_idx is not None:
|
||||
# Zwarcie wykryte
|
||||
fault_time = t[N + fault_idx]
|
||||
report.append(f"## Zwarcie wykryte")
|
||||
report.append(f"- Czas zwarcia: {fault_time*1000:.2f} ms")
|
||||
report.append(f"")
|
||||
|
||||
# Ktora faza
|
||||
if trip_history[fault_idx] > 0:
|
||||
report.append(f"- Faza: L1 (trip)")
|
||||
report.append(f"")
|
||||
|
||||
# Wartosci podczas zwarcia
|
||||
z_r_fault = z_r_history[fault_idx]
|
||||
z_x_fault = z_x_history[fault_idx]
|
||||
z_mag_fault = np.sqrt(z_r_fault**2 + z_x_fault**2)
|
||||
|
||||
report.append(f"## Wartosci podczas zwarcia")
|
||||
report.append(f"- Impedancja Z: {z_mag_fault:.2f} Ohm")
|
||||
report.append(f"- R: {z_r_fault:.2f} Ohm")
|
||||
report.append(f"- X: {z_x_fault:.2f} Ohm")
|
||||
report.append(f"")
|
||||
|
||||
# Prad i napiecie
|
||||
i1_fault = i1_raw[N + fault_idx]
|
||||
u1_fault = u1_raw[N + fault_idx]
|
||||
report.append(f"- Prad L1: {i1_fault:.2f} A")
|
||||
report.append(f"- Napiecie L1: {u1_fault:.2f} V")
|
||||
else:
|
||||
report.append(f"## Brak zwarcia")
|
||||
report.append(f"- Nie wykryto zadzialania zabezpieczenia")
|
||||
report.append(f"")
|
||||
|
||||
# Podsumowanie
|
||||
any_trip = any(t > 0 for t in trip_history)
|
||||
report.append(f"## Podsumowanie")
|
||||
report.append(f"- Trip L1: {'TAK' if any(trip_history) else 'NIE'}")
|
||||
report.append(f"")
|
||||
|
||||
# Zapisz raport
|
||||
report_content = "\n".join(report)
|
||||
with open(f'rezultat_{ALGORITHM_NAME}.md', 'w', encoding='utf-8') as f:
|
||||
f.write(report_content)
|
||||
|
||||
print(f"Raport zapisany do rezultat_{ALGORITHM_NAME}.md")
|
||||
return fault_idx is not None
|
||||
|
||||
# Generuj raport
|
||||
has_fault = detect_fault_and_generate_report(
|
||||
t,
|
||||
[trip_history_L1[i] + trip_history_L2[i] + trip_history_L3[i] for i in range(len(trip_history_L1))],
|
||||
z1_r_history, z1_x_history,
|
||||
i1_raw, i2_raw, i3_raw,
|
||||
u1_raw, u2_raw, u3_raw,
|
||||
relay, base_name
|
||||
)
|
||||
output_filename = f"{os.path.splitext(base_name)[0]}_result.png"
|
||||
plt.savefig(output_filename)
|
||||
print(f"Wynik zapisany do {output_filename}")
|
||||
|
||||
# Generowanie pliku rezultat.md
|
||||
def generate_result_md(t, trip_history_L1, trip_history_L2, trip_history_L3,
|
||||
z1_r_history, z1_x_history, z2_r_history, z2_x_history, z3_r_history, z3_x_history,
|
||||
Z_line_R, Z_line_X, relay):
|
||||
z1_r_history, z1_x_history, relay, base_name):
|
||||
"""Generuje plik rezultat.md z informacjami o wykryciu zwarcia"""
|
||||
|
||||
md_content = []
|
||||
md_content.append("# Wynik analizy zabezpieczenia odleglosciowego")
|
||||
md_content.append("")
|
||||
md_content.append(f"## Parametry zabezpieczenia")
|
||||
md_content.append(f"- Impedancja linii: R={Z_line_R:.2f} Ohm, X={Z_line_X:.2f} Ohm")
|
||||
md_content.append(f"- Kat linii: {relay.angle_r1:.1f} st.")
|
||||
md_content.append(f"- Strefa 1: R={relay.Z1_R:.2f} Ohm, X={relay.Z1_X:.2f} Ohm (natychmiast)")
|
||||
md_content.append(f"- Strefa 2: R={relay.Z2_R:.2f} Ohm, X={relay.Z2_X:.2f} Ohm (300ms)")
|
||||
md_content.append(f"- Strefa 3: R={relay.Z3_R:.2f} Ohm, X={relay.Z3_X:.2f} Ohm (600ms)")
|
||||
md_content = [f"# Wynik analizy dla {os.path.basename(base_name)}", ""]
|
||||
md_content.append(f"## Parametry zabezpieczenia ({ALGORITHM_DESC})")
|
||||
md_content.append(f"- Impedancja linii: R={relay.Z_line_R:.2f} Ohm, X={relay.Z_line_X:.2f} Ohm")
|
||||
md_content.append(f"- Kat linii: {relay.line_angle:.1f} st.")
|
||||
if hasattr(relay, 'z1_reach'):
|
||||
md_content.append(f"- Strefa 1: {relay.z1_reach*100:.0f}% ({relay.t_z1}ms)")
|
||||
md_content.append(f"- Strefa 2: {relay.z2_reach*100:.0f}% ({relay.t_z2}ms)")
|
||||
md_content.append(f"- Strefa 3: {relay.z3_reach*100:.0f}% ({relay.t_z3}ms)")
|
||||
else:
|
||||
md_content.append(f"- Strefa 1: R={relay.Z1_R:.2f} Ohm, X={relay.Z1_X:.2f} Ohm ({relay.tZ1}ms)")
|
||||
md_content.append(f"- Strefa 2: R={relay.Z2_R:.2f} Ohm, X={relay.Z2_X:.2f} Ohm ({relay.tZ2}ms)")
|
||||
md_content.append(f"- Strefa 3: R={relay.Z3_R:.2f} Ohm, X={relay.Z3_X:.2f} Ohm ({relay.tZ3}ms)")
|
||||
md_content.append("")
|
||||
|
||||
# Sprawdz czy bylo zwarcie
|
||||
trip_any = any(trip_history_L1) or any(trip_history_L2) or any(trip_history_L3)
|
||||
|
||||
if trip_any:
|
||||
md_content.append("## Wykrycie zwarcia")
|
||||
md_content.append("")
|
||||
md_content.append("**Zwarcie wykryte - zadzialanie zabezpieczenia**")
|
||||
md_content.append("")
|
||||
|
||||
# Znajdz czas pierwszego zadzialania
|
||||
fault_time = None
|
||||
fault_phase = None
|
||||
|
||||
md_content.append("## Wykrycie zwarcia: TAK")
|
||||
fault_time, fault_phase, fault_idx = -1, "Brak", -1
|
||||
for i, (t1, t2, t3) in enumerate(zip(trip_history_L1, trip_history_L2, trip_history_L3)):
|
||||
if t1 or t2 or t3:
|
||||
fault_time = t[N + i]
|
||||
if t1:
|
||||
fault_phase = "L1-E"
|
||||
elif t2:
|
||||
fault_phase = "L2-E"
|
||||
elif t3:
|
||||
fault_phase = "L3-E"
|
||||
fault_idx = i
|
||||
if t1: fault_phase = "L1"
|
||||
elif t2: fault_phase = "L2"
|
||||
else: fault_phase = "L3"
|
||||
break
|
||||
|
||||
if fault_time is not None:
|
||||
md_content.append(f"- Czas wykrycia: {fault_time:.4f} s")
|
||||
md_content.append(f"- Czas wykrycia: {fault_time * 1000:.2f} ms")
|
||||
md_content.append(f"- Faza: {fault_phase}")
|
||||
md_content.append("")
|
||||
|
||||
# Wartosci impedancji w momencie zwarcia
|
||||
idx = int((fault_time - t[N]) * Fs) if Fs > 0 else 0
|
||||
idx = max(0, min(idx, len(z1_r_history) - 1))
|
||||
z_r, z_x = z1_r_history[fault_idx], z1_x_history[fault_idx]
|
||||
z_mag = math.sqrt(z_r**2 + z_x**2)
|
||||
z_angle = math.degrees(math.atan2(z_x, z_r))
|
||||
|
||||
if fault_phase == "L1-E":
|
||||
z_r, z_x = z1_r_history[idx], z1_x_history[idx]
|
||||
elif fault_phase == "L2-E":
|
||||
z_r, z_x = z2_r_history[idx], z2_x_history[idx]
|
||||
md_content.append("## Wartości w momencie zwarcia")
|
||||
md_content.append(f"- R = {z_r:.4f} Ohm, X = {z_x:.4f} Ohm")
|
||||
md_content.append(f"- |Z| = {z_mag:.4f} Ohm, Kat Z = {z_angle:.2f} st.")
|
||||
else:
|
||||
z_r, z_x = z3_r_history[idx], z3_x_history[idx]
|
||||
md_content.append("## Wykrycie zwarcia: NIE")
|
||||
|
||||
z_mag = math.sqrt(z_r**2 + z_x**2) if z_r or z_x else 0
|
||||
z_angle = math.degrees(math.atan2(z_x, z_r)) if z_r else 0
|
||||
report_filename = f"{os.path.splitext(base_name)[0]}_rezultat.md"
|
||||
with open(report_filename, 'w', encoding='utf-8') as f:
|
||||
f.write("\n".join(md_content))
|
||||
print(f"Raport zapisany do {report_filename}")
|
||||
|
||||
md_content.append("## Wartosci w momencie wykrycia zwarcia")
|
||||
md_content.append(f"- R = {z_r:.4f} Ohm")
|
||||
md_content.append(f"- X = {z_x:.4f} Ohm")
|
||||
md_content.append(f"- |Z| = {z_mag:.4f} Ohm")
|
||||
md_content.append(f"- Kat Z = {z_angle:.2f} st.")
|
||||
else:
|
||||
md_content.append("## Wykrycie zwarcia")
|
||||
md_content.append("")
|
||||
md_content.append("**Brak wykrycia zwarcia**")
|
||||
md_content.append("")
|
||||
md_content.append("Zabezpieczenie nie zadzialalo w okresie rejestracji.")
|
||||
generate_result_md(t, trip_history_L1, trip_history_L2, trip_history_L3,
|
||||
z1_r_history, z1_x_history, relay, base_name)
|
||||
|
||||
md_content.append("")
|
||||
md_content.append("---")
|
||||
md_content.append("*Wygenerowano automatycznie przez tester zabezpieczenia odleglosciowego*")
|
||||
print("Analiza zakończona.")
|
||||
|
||||
return "\n".join(md_content)
|
||||
|
||||
# Generuj i zapisz rezultat.md
|
||||
result_md = generate_result_md(
|
||||
t, trip_history_L1, trip_history_L2, trip_history_L3,
|
||||
z1_r_history, z1_x_history, z2_r_history, z2_x_history, z3_r_history, z3_x_history,
|
||||
Z_line_R, Z_line_X, relay
|
||||
)
|
||||
|
||||
with open(f'rezultat_{ALGORITHM_NAME}.md', 'w', encoding='utf-8') as f:
|
||||
f.write(result_md)
|
||||
|
||||
print(f"Zapisano rezultat_{ALGORITHM_NAME}.md")
|
||||
|
||||
Reference in New Issue
Block a user