Preprosessering
Fra TK-data til intervallsensurert data¶
For å kunne bruke tidsserier av TK-data til å estimere oppholdstider i de ulike TKene, må dataene tilpasses modellen som benyttes. Siden TKer kun registreres ved inspeksjoner, er overgangstidspunktet mellom to TKer ikke kjent eksakt. Man vet bare at overgangen har skjedd mellom to inspeksjoner, noe som gir intervalsensurerte data. Kode for å gjøre om tidsserier av TK-data til intervallsensurert data er demonstrert under.
MERK: Denne metoden krever at data stiger monotont, det vil si, TK-serien kan ikke innneholde overganger fra høyere TK til lavere TK. I virkeligheten vil slike overganger kunne finnes i TK-data på grunn av støy og/eller måleusikkerhet. Vi ser på måter å behandle dette lengre ned.
Source
# importer nødvendige python-moduler
import numpy as np
import matplotlib.pyplot as plt
%config InlineBackend.figure_format = 'retina'
import matplotlib as mpl
mpl.rcParams.update({
"figure.facecolor": "none",
"axes.facecolor": "none",
"savefig.facecolor": "none",})Fontconfig error: No writable cache directories
Anta at du har en serie av TKer og tilsvarende serie som angir tidspunkt for inspeksjon. Vi skriver om serien på formatet (TK, TK, dt)
TK_raw = [1,1,1,2,2,2,3,4]
t = [0,8,10,12,19,25,28,29] # 0:1990
fig = plt.figure(figsize=(4,3))
plt.plot([i+1990 for i in t],TK_raw,'-o');
plt.xlabel('Tid (år)');plt.ylabel('TK');plt.grid();plt.title('Kaplan turbin')
plt.show()
trans = [
(TK_raw[i-1],
TK_raw[i],
t[i] - t[i-1])
for i in range(1, len(TK_raw))
]
print(f'TK transisjoner og tidsdifferanse: {trans}')
TK transisjoner og tidsdifferanse: [(1, 1, 8), (1, 1, 2), (1, 2, 2), (2, 2, 7), (2, 2, 6), (2, 3, 3), (3, 4, 1)]
Deretter definerer vi en funksjon som regner ut minimum og maksimum oppholdstid i hver karakter.
def state_intervals(trans, absorbing_state=5):
"""
trans: list of (state_prev, state_now, dt)
returns:
list of (state, tmin, tmax)
Håndterer:
- intervallsensurering
- hopp over tilstander (f.eks. TK1 -> TK3)
- høyresensurering av siste tilstand
- absorberende sluttilstand (f.eks. TK5)
"""
result = []
time_in_state = 0
for prev_state, curr_state, dt in trans:
if prev_state == curr_state:
time_in_state += dt
else:
# Tilstanden som forlates
result.append(
(
prev_state,
time_in_state,
time_in_state + dt
)
)
# Eventuelle tilstander som hoppes over
for state in range(prev_state + 1, curr_state):
result.append(
(
state,
0,
dt
)
)
time_in_state = 0
# Siste observerte tilstand
last_state = trans[-1][1]
# Ikke modeller oppholdstid i absorberende tilstand
if last_state != absorbing_state:
result.append(
(
last_state,
0,
np.inf
)
)
return resultinterval = state_intervals(trans)
print(f'min og max oppholdstid per TK: {interval}')min og max oppholdstid per TK: [(1, 10, 12), (2, 13, 16), (3, 0, 1), (4, 0, inf)]
Dersom man har flere serier av TK-data kan man repetere prosessen og få ut en liste av minimum og maksimum oppholdstid per TK.
Source
TK_raw1 = [1,1,1,2,2,2,3,4]
TK_raw2 = [1,1,1,1,1,1,1,3]
TK_raw3 = [1,1,2,2,3,3,4,5]
t = [0,8,10,12,19,25,28,29]
TK_raw_all = [TK_raw1, TK_raw2, TK_raw3]
fig = plt.figure(figsize=(4,3))
for k in range(3):
plt.plot([i+1990 for i in t],TK_raw_all[k],'-o',label=f'Kaplan {k+1}');
plt.xlabel('Tid (år)');plt.ylabel('TK');plt.grid();plt.legend();
plt.show()
all_intervals = []
for k, TK_raw in enumerate(TK_raw_all):
trans = [
(
TK_raw[i-1],
TK_raw[i],
t[i] - t[i-1]
)
for i in range(1, len(TK_raw))
]
intervals = state_intervals(trans)
print(f"Intervaller for serie {k+1}: {intervals}")
all_intervals.extend(intervals)
# Finn hvilke TK-er som finnes
states = sorted(set(state for state, _, _ in all_intervals))
# Opprett min/max-arrays per TK
minT = {state: [] for state in states}
maxT = {state: [] for state in states}
for state, tmin, tmax in all_intervals:
minT[state].append(tmin)
maxT[state].append(tmax)
print("\nIntervallsensurerte data per TK:")
for state in states:
print(f"\nTK {state}")
print("minT =", minT[state])
print("maxT =", maxT[state])
Intervaller for serie 1: [(1, 10, 12), (2, 13, 16), (3, 0, 1), (4, 0, inf)]
Intervaller for serie 2: [(1, 28, 29), (2, 0, 1), (3, 0, inf)]
Intervaller for serie 3: [(1, 8, 10), (2, 2, 9), (3, 6, 9), (4, 0, 1)]
Intervallsensurerte data per TK:
TK 1
minT = [10, 28, 8]
maxT = [12, 29, 10]
TK 2
minT = [13, 0, 2]
maxT = [16, 1, 9]
TK 3
minT = [0, 0, 6]
maxT = [1, inf, 9]
TK 4
minT = [0, 0]
maxT = [inf, 1]
Filtrering av støy fra TK-data¶
Dersom støy og/eller måleusikkerhet fører til en ikke-monotont stigende TK-trend, må vi behandle dataen før vi bruker koden beskrevet over. Dette kan gjøres ved å bruke filtre som jevner ut trenden. Her bruker vi isoton regresjon, en metode som finner kurven som ligger nærmest de observerte TKene i minste kvadraters forstand. Metoden endrer data så lite som mulig, men fjerner alle brudd på monotoni.
MERK: Registrerte overganger fra høyere til lavere TK kan være et resultat av “normalt vedlikehold”. Vi anser dette som vedlikeholdoppgaver som må gjøres for å holde komponenten i drift (utbedring av oljelekkasje, smøring av lager osv), men som ikke direkte påvirker komponentens levetid. Ved å filtrere bort denne type data antar vi dermed at vi ikke mister informasjon om levetid. Eksempler som demonstrerer effekten av isoton regresjon er vist under:
Source
from sklearn.isotonic import IsotonicRegression
TK_non_monotone = [1,1,1,2,1,1,2,2]
iso = IsotonicRegression(y_min=1, y_max=5,increasing=True)
TK_monotone = iso.fit_transform(t, TK_non_monotone)
TK_int = np.round(TK_monotone).astype(int) # make integer
TK_int = np.maximum.accumulate(TK_int)
fig = plt.figure(figsize=(4,3))
plt.plot([2002],[2],'r^',markersize=12,label='oljelekkasje oppdaget')
plt.plot([i+1990 for i in t],TK_non_monotone,'--ko',label='TK ved inspeksjon');
plt.plot([i+1990 for i in t],TK_int,'-m',label='Filtrert');
plt.ylim([0,4]);plt.yticks(range(5));
plt.xlabel('Tid (år)');plt.ylabel('TK');plt.grid();plt.legend();
plt.show()
Source
TK_non_monotone = [1,1,1,3,3,1,1,3]
iso = IsotonicRegression(y_min=1, y_max=5,increasing=True)
TK_monotone = iso.fit_transform(t, TK_non_monotone)
TK_int = np.round(TK_monotone).astype(int) # make integer
TK_int = np.maximum.accumulate(TK_int)
fig = plt.figure(figsize=(4,3))
#plt.plot([2002],[2],'r^',markersize=12,label='oljelekkasje 2002')
plt.plot([i+1990 for i in t],TK_non_monotone,'--ko',label='TK ved inspeksjon');
plt.plot([i+1990 for i in t],TK_int,'-m',label='Filtrert');
plt.ylim([0,4]);plt.yticks(range(5));
plt.xlabel('Tid (år)');plt.ylabel('TK');plt.grid();plt.legend();
plt.show()
Source
TK_non_monotone = [1,1,2,1,1,2,3,2]
iso = IsotonicRegression(y_min=1, y_max=5,increasing=True)
TK_monotone = iso.fit_transform(t, TK_non_monotone)
TK_int = np.round(TK_monotone).astype(int) # make integer
TK_int = np.maximum.accumulate(TK_int)
fig = plt.figure(figsize=(4,3))
#plt.plot([2002],[2],'r^',markersize=12,label='oljelekkasje 2002')
plt.plot([i+1990 for i in t],TK_non_monotone,'--ko',label='TK ved inspeksjon');
plt.plot([i+1990 for i in t],TK_int,'-m',label='Filtrert');
plt.ylim([0,4]);plt.yticks(range(5));
plt.xlabel('Tid (år)');plt.ylabel('TK');plt.grid();plt.legend();
plt.show()