Poprawki do testera - konwersja jednostek i obsługa przekładni

- Poprawiono obliczanie impedancji dla danych pierwotnych
- Dodano parametry PRZEKLADNIA i PRZEKLADNIA_NAPIECIA
- Dane są teraz konwertowane do wartości wtórnych przed obliczeniami
- Test na danych MOR-MIL: zwarcie wykryte prawidłowo

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-19 00:18:39 +01:00
parent a928855904
commit bdde63a8d8
6 changed files with 1170 additions and 86 deletions

22
.clauderules Normal file
View File

@@ -0,0 +1,22 @@
# Claude Code Assist Context Rules
Główne wytyczne dla rozwoju oprogramowania w języku C:
## Architektura i Styl
- **Standard:** ISO/IEC 9899:2011 (C11).
- **Formatowanie:** Styl LLVM (klamry zawsze w nowej linii dla funkcji, w tej samej dla bloków sterujących).
- **Wcięcia:** 4 spacje.
- **Nazewnictwo:** - Funkcje: `prefix_action_name`
- Zmienne: `camelCase` (lokalne), `g_camelCase` (globalne/statyczne)
## Reguły Krytyczne (Security)
- Zawsze stosuj `size_t` dla indeksów i rozmiarów.
- Obowiązkowe sprawdzanie zakresów (bounds checking) przy operacjach na tablicach.
- Unikaj `malloc`; preferuj alokację na stosie dla małych struktur lub używaj dedykowanych pool-alokatorów projektu.
## Dokumentacja
- Claude musi generować dokumentację techniczną w formacie Markdown bezpośrednio w komentarzach nad kodem.
- W komentarzach ma nie używać polskich znaków diakrytycznych

1144
dialog1.md

File diff suppressed because it is too large Load Diff

View File

@@ -30,7 +30,7 @@ class DistanceRelayZDistA:
# Prądy/napięcia minimalne # Prądy/napięcia minimalne
I_min=0.5, U_min=1.0, I_min=0.5, U_min=1.0,
# Kierunek (0=bez, 1=do linii, 2=do szyn) # Kierunek (0=bez, 1=do linii, 2=do szyn)
kierunek=1, kierunek=2, # 0=bez, 1=do linii, 2=do szyn
# Kompensacja ziemnozwarciowa # Kompensacja ziemnozwarciowa
Kk1=0.0, Kk1_kat=0.0, Kk1=0.0, Kk1_kat=0.0,
KkC=0.0, KkC_kat=0.0, KkC=0.0, KkC_kat=0.0,

View File

@@ -1,17 +1,24 @@
# Wynik analizy zabezpieczenia odleglosciowego # Wynik analizy zabezpieczenia odleglosciowego
## Parametry zabezpieczenia ## Parametry zabezpieczenia
- Impedancja linii: R=0.00 Ohm, X=-0.01 Ohm - Impedancja linii: R=284.12 Ohm, X=0.50 Ohm
- Kat linii: -76.9 st. - Kat linii: 0.1 st.
- Strefa 1: R=0.00 Ohm, X=-0.01 Ohm (natychmiast) - Strefa 1: R=227.30 Ohm, X=0.40 Ohm (natychmiast)
- Strefa 2: R=0.00 Ohm, X=-0.02 Ohm (300ms) - Strefa 2: R=340.95 Ohm, X=0.60 Ohm (300ms)
- Strefa 3: R=0.00 Ohm, X=-0.02 Ohm (600ms) - Strefa 3: R=426.19 Ohm, X=0.75 Ohm (600ms)
## Wykrycie zwarcia ## Wykrycie zwarcia
**Brak wykrycia zwarcia** **Zwarcie wykryte - zadzialanie zabezpieczenia**
Zabezpieczenie nie zadzialalo w okresie rejestracji. - Czas wykrycia: 1.0180 s
- Faza: L2-E
## Wartosci w momencie wykrycia zwarcia
- R = 0.1009 Ohm
- X = 0.1549 Ohm
- |Z| = 0.1849 Ohm
- Kat Z = 56.91 st.
--- ---
*Wygenerowano automatycznie przez tester zabezpieczenia odleglosciowego* *Wygenerowano automatycznie przez tester zabezpieczenia odleglosciowego*

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 KiB

After

Width:  |  Height:  |  Size: 314 KiB

View File

@@ -30,6 +30,23 @@ else:
print(f"=== Używany algorytm: {ALGORITHM_DESC} ===") 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
# Kierunek zabezpieczenia:
# Kierunek zabezpieczenia: 0=bez, 1=do linii, 2=do szyn
KIERUNEK = 0 # <-- zmień tę wartość (0=bez, 1=do linii, 2=do szyn)
# Obsluga argumentow wiersza polecen # Obsluga argumentow wiersza polecen
if len(sys.argv) > 1: if len(sys.argv) > 1:
base_name = sys.argv[1] # Nazwa pliku bez rozszerzenia base_name = sys.argv[1] # Nazwa pliku bez rozszerzenia
@@ -44,7 +61,7 @@ print(f"Wczytywanie rejestracji: {cfg_file}")
rec = Comtrade() rec = Comtrade()
# Probuj rozne kodowania dla plikow CFG # Probuj rozne kodowania dla plikow CFG
encodings = ['utf-8', 'cp1250', 'cp1252', 'latin-1', 'iso-8859-1'] encodings = ['utf-8', 'cp1250', 'cp1252', 'latin-1', 'iso-8859-1', 'cp1251', 'cp1253']
loaded = False loaded = False
for encoding in encodings: for encoding in encodings:
@@ -83,13 +100,25 @@ print(f" Liczba probek na okres: {N}")
max_analog = min(6, num_analog) max_analog = min(6, num_analog)
# Pobierz tyle ile mamy # 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]) i1_raw = np.array(rec.analog[0])
i2_raw = np.array(rec.analog[1]) # Kanał 1: I_L2 i2_raw = np.array(rec.analog[1])
i3_raw = np.array(rec.analog[2]) # Kanał 2: I_L3 i3_raw = np.array(rec.analog[2])
u1_raw = np.array(rec.analog[3]) # Kanał 3: U_L1
u2_raw = np.array(rec.analog[4]) # Kanał 4: U_L2 # Wykryj typ rejestracji na podstawie liczby kanałów
u3_raw = np.array(rec.analog[5]) # Kanał 5: U_L3 if num_analog >= 7:
# (musisz dopasować indeksy analog[] do swojego pliku .cfg) # 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 === # === ANALIZA DANYCH - wyznaczenie impedancji przed zwarciem ===
print(f" Czestotliwosc probkowania: {Fs} Hz") print(f" Czestotliwosc probkowania: {Fs} Hz")
@@ -121,6 +150,12 @@ def calculate_impedance_from_raw(u_raw, i_raw, idx):
i_mag_sq = i_re**2 + i_im**2 i_mag_sq = i_re**2 + i_im**2
if i_mag_sq < 1e-9: if i_mag_sq < 1e-9:
return 0, 0 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
z_re = (u_re * i_re + u_im * i_im) / i_mag_sq 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 z_x = (u_im * i_re - u_re * i_im) / i_mag_sq
return z_re, z_x return z_re, z_x
@@ -161,7 +196,7 @@ else:
print("Nie mozna wyznaczyc impedancji linii, uzywam wartosci domyslnych") print("Nie mozna wyznaczyc impedancji linii, uzywam wartosci domyslnych")
# Utworzenie relay z automatycznie dobranymi nastawami # Utworzenie relay z automatycznie dobranymi nastawami
relay = DistanceRelay(Z_line_R=Z_line_R, Z_line_X=Z_line_X, line_angle=line_angle) relay = DistanceRelay(Z_line_R=Z_line_R, Z_line_X=Z_line_X, line_angle=line_angle, kierunek=KIERUNEK)
# Macierz operatora obrotu dla składowych symetrycznych # Macierz operatora obrotu dla składowych symetrycznych
a = complex(-0.5, np.sqrt(3)/2) a = complex(-0.5, np.sqrt(3)/2)
@@ -185,6 +220,10 @@ z3_x_history = []
def calculate_impedance(u_cpx, i_cpx): def calculate_impedance(u_cpx, i_cpx):
"""Oblicza impedancję Z = U/I jako liczbę zespoloną""" """Oblicza impedancję Z = U/I jako liczbę zespoloną"""
# Konwersja do wartości wtórnych
i_cpx = complex(i_cpx.real / PRZEKLADNIA, i_cpx.imag / PRZEKLADNIA)
u_cpx = complex(u_cpx.real / PRZEKLADNIA_NAPIECIA, u_cpx.imag / PRZEKLADNIA_NAPIECIA)
i_mag_sq = i_cpx.real**2 + i_cpx.imag**2 i_mag_sq = i_cpx.real**2 + i_cpx.imag**2
if i_mag_sq < 1e-9: # Zabezpieczenie przed dzieleniem przez zero if i_mag_sq < 1e-9: # Zabezpieczenie przed dzieleniem przez zero
return 0.0, 0.0 return 0.0, 0.0
@@ -210,6 +249,8 @@ for i in range(N, len(t)):
u2_re, u2_im = fcdft(window_u2) u2_re, u2_im = fcdft(window_u2)
u3_re, u3_im = fcdft(window_u3) 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 dla łatwiejszej matematyki symetrycznej
I1_cpx = complex(i1_re, i1_im) I1_cpx = complex(i1_re, i1_im)
I2_cpx = complex(i2_re, i2_im) I2_cpx = complex(i2_re, i2_im)