{"spec_id":"spectrogram-basic","library":"makie","language":"julia","code":"# anyplot.ai\n# spectrogram-basic: Spectrogram Time-Frequency Heatmap\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 89/100 | Created: 2026-09-09\n\nusing CairoMakie\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\n# --- Theme tokens (see prompts/default-style-guide.md \"Theme-adaptive Chrome\")\nconst THEME    = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG  = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst INK      = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\n\n# --- Data: simulated gearbox vibration signal --------------------------------\n# Shaft speeds up steadily (chirp) while a bearing fault produces a brief\n# high-frequency impact burst partway through the run.\nsample_rate = 2000.0\nduration = 5.0\nn_samples = round(Int, sample_rate * duration)\nt = (0:(n_samples - 1)) ./ sample_rate\n\nf_start, f_end = 60.0, 340.0\nshaft_phase = 2π .* (f_start .* t .+ (f_end - f_start) / (2 * duration) .* t .^ 2)\nshaft_vibration = sin.(shaft_phase)\n\nfault_center = 3.0\nfault_width = 0.15\nfault_envelope = exp.(-((t .- fault_center) .^ 2) ./ (2 * fault_width^2))\nfault_tone = fault_envelope .* sin.(2π .* 620.0 .* t)\n\nnoise = 0.05 .* randn(n_samples)\nsignal = shaft_vibration .+ 1.2 .* fault_tone .+ noise\n\n# --- Short-time Fourier transform (manual DFT — no FFT package in this env) -\nnfft = 256\nhopsize = 32\nhalf = nfft ÷ 2\nhann_window = 0.5 .* (1 .- cos.(2π .* (0:(nfft - 1)) ./ (nfft - 1)))\nn_frames = (n_samples - nfft) ÷ hopsize + 1\nsample_idx = 0:(nfft - 1)\n\nfreqs = (0:half) .* (sample_rate / nfft)\ntimes = ((0:(n_frames - 1)) .* hopsize .+ nfft / 2) ./ sample_rate\npower = zeros(half + 1, n_frames)\n\nfor frame in 1:n_frames\n    frame_start = (frame - 1) * hopsize + 1\n    windowed = signal[frame_start:(frame_start + nfft - 1)] .* hann_window\n    for k in 0:half\n        angle = -2π .* k .* sample_idx ./ nfft\n        re = sum(windowed .* cos.(angle))\n        im = sum(windowed .* sin.(angle))\n        power[k + 1, frame] = re^2 + im^2\n    end\nend\n\npower_db = 10 .* log10.(power .+ 1e-12)\npower_db .-= maximum(power_db)\npower_db = clamp.(power_db, -50.0, 0.0)\n\n# --- Plot ---------------------------------------------------------------\nfig = Figure(\n    size = (1600, 900),\n    fontsize = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title = \"spectrogram-basic · julia · makie · anyplot.ai\",\n    titlesize = 24,\n    titlecolor = INK,\n    xlabel = \"Time (s)\",\n    ylabel = \"Frequency (Hz)\",\n    xlabelsize = 14,\n    ylabelsize = 14,\n    xlabelcolor = INK,\n    ylabelcolor = INK,\n    xticklabelsize = 12,\n    yticklabelsize = 12,\n    xticklabelcolor = INK_SOFT,\n    yticklabelcolor = INK_SOFT,\n    xtickcolor = INK_SOFT,\n    ytickcolor = INK_SOFT,\n    backgroundcolor = PAGE_BG,\n    topspinevisible = false,\n    rightspinevisible = false,\n    leftspinecolor = INK_SOFT,\n    bottomspinecolor = INK_SOFT,\n    xgridvisible = false,\n    ygridvisible = false,\n)\n\nimprint_seq = cgrad([colorant\"#009E73\", colorant\"#4467A3\"])\n\nhm = heatmap!(ax, times, freqs, power_db'; colormap = imprint_seq, colorrange = (-50.0, 0.0))\n\nColorbar(\n    fig[1, 2],\n    hm;\n    label = \"Power (dB)\",\n    labelcolor = INK,\n    labelsize = 14,\n    ticks = -50:10:0,\n    ticklabelsize = 12,\n    ticklabelcolor = INK_SOFT,\n    tickcolor = INK_SOFT,\n)\n\n# --- Fault-burst annotation (distinctive Makie touch) ------------------------\nfault_freq = 620.0\nscatter!(\n    ax,\n    [fault_center],\n    [fault_freq];\n    color = :transparent,\n    strokecolor = INK,\n    strokewidth = 2,\n    markersize = 22,\n)\ntext!(\n    ax,\n    fault_center,\n    fault_freq;\n    text = \"bearing fault\",\n    align = (:left, :bottom),\n    offset = (10, 8),\n    color = INK,\n    fontsize = 12,\n)\n\n# --- Save -------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}