E.2 Primer vistazo a los datos

E · Caso transversal: un edificio de tres plantas

Ver el código
datos = Dict(e => readdlm(RUTA * "escenario_$(e).csv", ';', skipstart=1) for e in ("A", "B", "C"))
fig = Figure(size=(780, 360))
ax = Axis(fig[1, 1]; xlabel="f (Hz)", ylabel="PSD (m/s²)²/Hz", yscale=log10, limits=(0.3, 6, nothing, nothing))
vlines!(ax, f3; color=GRIS, linestyle=:dash)
for (e, col) in (("A", AZUL), ("B", VERDE), ("C", NARANJA))
    x = datos[e][:, 4]
    f, P = psd_welch(x .- mean(x), 100.0; nseg=2048)
    lines!(ax, f, P; color=col, linewidth=1.5, label="escenario $e")
end
axislegend(ax; position=:rt)
fig
Tres curvas de densidad espectral con tres picos cada una, en torno a 1,1, 2,9 y 4,4 hercios. Las curvas de los escenarios A y B casi coinciden y la del escenario C está desplazada ligeramente hacia frecuencias menores, sobre todo en el primer y el tercer pico.
Figura 1: Densidad espectral de potencia (Welch, segmentos de 2048 muestras) de la aceleración de la cubierta en los tres escenarios. Las líneas grises son las frecuencias verdaderas del escenario A. Los tres picos están presentes en los tres registros y se desplazan poco; el desplazamiento del escenario C es visible en el primer y el tercer modo.

Para ver si el cambio se puede detectar, se estima la frecuencia de cada pico en 10 bloques de 60 s por escenario (Welch con interpolación parabólica del máximo) y se mira la media y la dispersión:

Ver el código
function pico(f, P, f0)
    idx = findall(x -> abs(x - f0) < 0.4, f)
    k = idx[argmax(P[idx])]
    a, b, c = log(P[k-1]), log(P[k]), log(P[k+1])
    return f[k] + 0.5 * (a - c) / (a - 2b + c) * (f[2] - f[1])
end
est = Dict()
for e in ("A", "B", "C")
    m = zeros(10, 3)
    for b in 1:10
        seg = datos[e][(b-1)*6000+1:b*6000, 4]
        f, P = psd_welch(seg .- mean(seg), 100.0; nseg=2048)
        for j in 1:3
            m[b, j] = pico(f, P, f3[j])
        end
    end
    est[e] = m
end
# frecuencias verdaderas de cada escenario (las de E.1)
verdad = Dict(e => modos_propios(edificio_tres_plantas(escenario=Symbol(e))[[3, 1]]...)[1] for e in ("A", "B", "C"))
filas = String[]
for e in ("A", "B", "C"), j in 1:3
    push!(filas, "| $e | $j | $(coma(verdad[e][j]; d=3)) | $(coma(mean(est[e][:, j]); d=3)) ± $(coma(std(est[e][:, j]); d=3)) |")
end
Markdown.parse("| Escenario | Modo | f verdadera (Hz) | f estimada (Hz) |\n|:--:|:--:|--:|:--|\n" * join(filas, "\n"))
Tabla 1: Frecuencia estimada de cada pico en bloques de 60 s de la aceleración de la cubierta: media ± desviación típica entre los 10 bloques de cada escenario, frente al valor verdadero.
Escenario Modo f verdadera (Hz) f estimada (Hz)
A 1 1,105 1,108 ± 0,009
A 2 2,939 2,943 ± 0,018
A 3 4,390 4,416 ± 0,038
B 1 1,099 1,108 ± 0,023
B 2 2,924 2,933 ± 0,015
B 3 4,368 4,374 ± 0,027
C 1 1,084 1,087 ± 0,009
C 2 2,931 2,924 ± 0,021
C 3 4,254 4,267 ± 0,034

Tres lecciones, con los números de la Tabla 1:

Es la antesala de M12: la detección útil exige cuantificar la incertidumbre del estimador y compararla con la variabilidad del estado sano, y no basta con ver que un número cambia.