### A Pluto.jl notebook ### # v0.20.4 using Markdown using InteractiveUtils # ╔═╡ 7c69d12c-80a5-11ef-2674-e155a3483342 begin using Pkg Pkg.activate(".") # Pkg.status() true || include("../src/PSBoardDataBase.jl") end # ╔═╡ effa7ed9-2ac4-4468-a474-e2bb662580fe begin using PSBoardDataBase using SQLite using DataFrames using FHist using DBInterface using Tables using CairoMakie using ColorSchemes using Statistics using PlutoUI using Dates using Random using Printf end # ╔═╡ f25e7e08-8a73-4cac-ac7c-d310725c558d md""" # Detailed research on clock skew measurement - distribution of clock skews - consistency of multiple measurement on the same board """ # ╔═╡ 1a6322d4-9deb-4709-aa2e-df7d8be5b16f TableOfContents(depth = 4) # ╔═╡ 11537f91-e16b-45f0-9768-6df842371d36 db = SQLite.DB("../psboard_qaqc.db") # ╔═╡ 268d3015-b8d3-48d9-b74a-062e258e0ec1 SQLite.tables(db) # ╔═╡ 62105832-df1f-4834-8da6-c542e22207d1 md""" ## Single runs """ # ╔═╡ dea6f143-7916-4765-92f6-2bfb97a72835 qaqc_single_results = DBInterface.execute(db, sql"select * from qaqc_single_run_results") |> DataFrame # ╔═╡ 41543c0c-d7c4-447b-a268-0d356c88d92c md""" ## PS Board list """ # ╔═╡ 633ecdee-7e2f-4de8-833a-21cd0351c1f1 DBInterface.execute( db, sql""" select * from ps_boards """, ) |> DataFrame # ╔═╡ 87f1966e-3b07-4f9d-8fc4-7b7aa4319d50 md""" ## Run list """ # ╔═╡ f379d43c-9300-41f4-b0fc-3c9d749e3105 qaqc_runs = let df df = DBInterface.execute(db, sql"select * from qaqc_runs") |> DataFrame transform!(df, :run_datetime => ByRow(passmissing(s -> DateTime(s))) => :run_datetime) df end # ╔═╡ 33e099bc-ac4b-4b5f-88e7-20f4463c98ef md""" ## Positions """ # ╔═╡ 0e13f848-0efb-4775-9e3e-518b32588a79 qaqc_positions = DBInterface.execute(db, sql"select * from qaqc_positions") |> DataFrame # ╔═╡ 181c3fe6-d087-42e2-b175-3fb84c42e3e8 position_id_skew_map = select(qaqc_positions, [:id, :rising_ns]) |> Tables.rowtable |> Dict # ╔═╡ dd669f14-989b-45ee-87d8-5d9cf282fafd md""" ## Dispatch """ # ╔═╡ 1e9c3944-0cd4-40da-9014-a9153d4e95ed qaqc_dispatch = DBInterface.execute(db, sql"select * from qaqc_dispatch") |> DataFrame # ╔═╡ 322cb530-65a5-4973-86f8-01ccc2439cc4 md""" # Clock Analysis main part """ # ╔═╡ c1caca5f-4cfd-4f22-82b4-7925002359e6 clk_files = readdir("../test/input/slavelogs/main/", join = true) |> filter(endswith("_clk.txt")) |> filter(!contains("nagoya")) |> filter(!contains("630_190")) |> filter(!contains("627_344")) # ╔═╡ 3e5607fd-2a8a-4a1a-9e7b-3f23ef216fad """ Get `(psbid, runid)`. """ function parse_filename(filename::AbstractString) m = match(r"(?\d+)_(?\d+)_clk\.txt", filename) parse(Int64, m[:psbid]), parse(Int64, m[:runid]) end # ╔═╡ c1b9c0c3-00f8-4199-b07f-8888f1be625c parse_filename("190_23_clk.txt") # ╔═╡ d6d04013-e0e4-49d5-a450-07ae164bfaa3 # Get skew and rise up time from clock measurement files # Use measurements recorded in qaqc_single_results df_rawskews = clk_files .|> ( file -> begin skew_width = PSBoardDataBase.ClockParser.get_skew_and_riseup(file) riseup = PSBoardDataBase.ClockParser.count_riseup(file) psbid, runid = parse_filename(file) ( psbid = psbid, runid = runid, skew = skew_width[1], width = skew_width[2], riseup = riseup, ) end ) |> filter( x -> filter( [:psboard_id, :runid] => ((psbid, runid) -> (psbid == x.psbid && runid == x.runid)), qaqc_single_results, ) |> !isempty, ) |> DataFrame # ╔═╡ 0e680044-e4e1-4f39-a5c5-afa5c53fc7a7 clk_files |> filter(contains("168")) .|> PSBoardDataBase.ClockParser.get_skew_and_riseup # ╔═╡ d7541b93-4c49-4dcd-bda0-91e447f44596 # substract result of measurements of position dependency df_skews = let df = leftjoin( df_rawskews, @view(qaqc_single_results[!, [:psboard_id, :runid, :position]]), on = [:psbid => :psboard_id, :runid], ) leftjoin!(df, @view(qaqc_positions[!, [:id, :rising_ns]]), on = [:position => :id]) transform!(df, [:skew, :rising_ns] => ByRow((x, y) -> x - y) => :skew) select!(df, Not(:rising_ns)) select!(df, Not(:position)) end # ╔═╡ e7faa647-79cd-4247-a3f2-9868c7b9d4ca md""" ## skewの分布 ``skew = rising\_time_{psbid, position} - rising\_time_{position}`` """ # ╔═╡ 3a412a98-4a2d-4bfb-8053-b0f480fae921 let skews = skipmissing(df_skews.skew) |> collect npsbid = df_skews.psbid |> unique |> length fig = Figure() ax = Axis( fig[1, 1], title = "skews of all measurements (n_meas = $(length(skews)), n_psb = $(npsbid))", xlabel = "skew / ns", ) stephist!(ax, skews, bins = range(minimum(skews), maximum(skews), step = 1 / 56)) fig end # ╔═╡ b38bbed4-8721-4e92-a546-f7926cc07dd3 md""" ## 立ち上がり時間の分布(生) """ # ╔═╡ 420dce0e-4757-48d9-84ec-7ddfac2fdff6 let skew_widths = df_skews.width |> skipmissing |> collect bins = range(0, maximum(skew_widths) + 1 / 56, step = 1 / 56)# .- 0.01 hist( skew_widths, bins = bins, bar_labels = :y, label_size = 14, label_formatter = x -> "$(round(Int, x))", axis = ( title = "clock rise span distribution", xlabel = "rise up span / ns", ylabel = "counts", limits = ((0, 0.33), (0, nothing)), # xticks = (bins, string.(round.(bins, digits = 3))), # xticklabelrotation = π / 3, ), ) end # ╔═╡ 99902640-fee3-4502-9c7e-cb08834bad0b maximum(skipmissing(df_skews.width)) / (1 / 56) # ╔═╡ c79c6684-1b03-41b5-aa90-ef8c7a8eb69c md""" この結果を元に、クロック試験のしきい値は$(round(9 * 1 / 56; digits = 2))ns以上に設定 """ # ╔═╡ a1056aba-e484-4594-908b-4709896d0da0 let fig = Figure() ax = Axis( fig[1, 1], limits = ((-0.5, 1), nothing), title = "turn on curves for PSBID 1166", xlabel = "delay / ns (position dependency is removed)", ylabel = "counts", ) clk_files_1166 = filter(clk_files) do filename psbid, runid = parse_filename(filename) psbid == 1166 end for clk_file in clk_files_1166 psbid, runid = parse_filename(clk_file) single_runs = filter( [:psboard_id, :runid] => ( (ref_psbid, ref_runid) -> begin psbid == ref_psbid && runid == ref_runid end ), qaqc_single_results, ) offset_pos = let qaqc_positions.rising_ns[single_runs.position[1]] end points = eachline(clk_file) .|> PSBoardDataBase.ClockParser._parse_line .|> (x -> (x[1] - offset_pos, x[2])) @info "" single_runs points stds = map(points) do ((time, count)) sqrt(count * (1000 - count) / 1000) end scatterlines!(ax, points, label = "psbid $(psbid), runid $(runid)") errorbars!(ax, points, stds) end axislegend(ax, position = :rb) fig end # ╔═╡ 875bec26-e576-4f48-ba14-464bce503d75 filter(:width => (x -> ismissing(x) || x < 0.06), df_skews) # ╔═╡ ec774495-c0be-47a4-9d2c-b48159c07013 md""" ## 各PSBoardごとの統計 """ # ╔═╡ d082e07c-3b42-4362-bebf-63356979a49b gdf_skews_on_psbid = groupby(df_skews, :psbid) # ╔═╡ 2d41c98b-630e-41e7-9332-25394a6285e8 md""" ### 同じPSBoardで同じ場所で複数回測定し、測定のばらつきが大きかったもの すべて異常個体リストで把握済み """ # ╔═╡ 6ff9f397-5db9-45af-9bca-7a8d7756f8da combine(filter(groupby(qaqc_single_results, [:psboard_id, :position])) do sdf nrow(dropmissing(sdf, [:lvds_tx_skew])) > 1 end) do sdf sdf = dropmissing(sdf, [:lvds_tx_skew]) # @info "" select(sdf, [:psboard_id, :position, :lvds_tx_skew]) ( skew_mean = mean(sdf.lvds_tx_skew), skew_std = std(sdf.lvds_tx_skew), nrow = nrow(sdf), ) end |> (df -> begin filter(:skew_std => >(0.5), df) end) # ╔═╡ 25688d24-5aee-43d3-aff9-b9efa0556070 combine(nrow, gdf_skews_on_psbid) # ╔═╡ 0d3f7f0a-1713-4e22-acbb-7d370fabf5a7 combine(gdf_skews_on_psbid, :skew => (v -> all(ismissing, v)) => :hasmissing) |> (df -> sort(df, :hasmissing, rev = true)) # ╔═╡ 239a808c-0411-4542-ae68-6ae6af333bd2 df_nrow_ordered = let df = combine(nrow, gdf_skews_on_psbid) sort!(df, :nrow, rev = true) end # ╔═╡ 8e57bde1-5f97-483d-906e-8ebfb65016d0 @view(df_nrow_ordered[findall(>(1), df_nrow_ordered.nrow), :]) # ╔═╡ 92c2ac3f-8034-4e9e-aadb-8bb166fbc948 df_skew_stats = let df = combine( gdf_skews_on_psbid, sdf -> begin if nrow(sdf) == 1 (; mean_skew = mean(sdf.skew), std_skew = missing, n = 1) else (; mean_skew = mean(sdf.skew), std_skew = std(sdf.skew), n = nrow(sdf)) end end, ) dropmissing!(df) df end # ╔═╡ 893253c3-f0b2-401f-b892-b23291bcf5c1 fig_skew_stats = let fig, ax, sc = scatter( df_skew_stats.mean_skew, df_skew_stats.std_skew, marker = :x, color = (Makie.wong_colors()[1], 0.8), axis = ( title = "mean vs std of multiple skew measurements for same PS Boards", xlabel = "mean / ns", ylabel = "std / ns", ), ) text!( ax, df_skew_stats.mean_skew, df_skew_stats.std_skew, text = string.(df_skew_stats.psbid), color = (:gray, 0.5), ) fig end # ╔═╡ 6467dcaa-6bd6-45c7-8c08-b310a09b8b0b save("clock_skew_stats.svg", fig_skew_stats) # ╔═╡ 19f85f1b-07d3-48c2-9ca6-a5a8eb1ab746 let fig, ax, sc = scatter( df_skew_stats.mean_skew, df_skew_stats.std_skew, marker = :x, color = (Makie.wong_colors()[1], 0.8), axis = ( title = "mean vs std of multiple skew measurements for same PS Boards", xlabel = "mean / ns", ylabel = "std / ns", limits = ((-0.6, 1.2), (-0.01, 0.09)), ), ) text!( ax, df_skew_stats.mean_skew, df_skew_stats.std_skew, text = string.(df_skew_stats.psbid), color = (:gray, 0.5), ) fig end # ╔═╡ 0d758cdf-0dda-4dc3-b489-35831812b718 md""" ### 異常個体リスト - 分散が1より大きいもの """ # ╔═╡ 79e2f5d8-4609-4e9f-949e-6dc1f88c0b19 df_skew_stats_abnormals = let df = filter([:mean_skew, :std_skew] => ((m, s) -> s > 1), df_skew_stats) sort!(df, :psbid) df end # ╔═╡ eae649db-6b2b-4530-83a8-3438f29423cc let df = filter(:psboard_id => in(df_skew_stats_abnormals.psbid), qaqc_single_results) select!(df, [:runid, :psboard_id, :lvds_tx_skew, :note]) df end # ╔═╡ d607e10e-854f-4652-9a34-9e22a188e315 let df = df_skew_stats_abnormals fig, ax, sc = scatter( df.mean_skew, df.std_skew, marker = :x, color = (Makie.wong_colors()[1], 0.8), axis = ( title = "mean vs std of multiple skew measurements for same PS Boards", xlabel = "mean / ns", ylabel = "std / ns", ), ) text!( ax, df.mean_skew, df.std_skew, text = string.(df.psbid) .* "," .* string.(df.n), color = (:gray, 0.7), ) fig end # ╔═╡ 5bef43cf-0f9b-40a2-bd47-620f42c36d8d gdf_skews_on_psbid[(psbid = 215,)] # ╔═╡ 2795fd06-2f59-4e5b-829d-a8e428646790 md""" ### 分散が異常に大きいやつ 基本的に予想通り、分散は小さく複数回の測定で整合的な結果が得られているが、いくつか例外があった。 はじめはpsbid 127(4回測定)が含まれていたが、これはデータベースの編集ミスであることがわかり、修正した結果、消えた。 !!! todo 他の例外も確認する。 `df_skew_stats_abnormals`を確認 #### psbid: 215 - run: 43, 47 - run 43で"QSPI device ID does not match. inclueded in RUN45-, RUN47と49で問題が無いことを確認" - run 47を使用? #### psbid: 291 - run: 83, 94 - 83でcommunication error(SFP半抜け) #### psbid: 442 - run: 103, 132 - 103の結果がinvalid(460と同じ) #### psbid: 460 - run: 105, 132 - psbid 444と同じく電源の抜き差しによってクロックの0と1000が繰り返されたパターン - 追試に送られてる #### psbid: 462 - run: 105, 132 - psbid 460と同じく105がだめ #### psbid: 545 - run: 126, 132 - どちらも測定結果自体には変なところはない - どちらも1回だけ立ち上がりがある - 立ち上がりもそれほど長くない - 126でQSPIpが失敗してるので結果は使わない、132を使う - 126が電源が不安定なときだったかもしれないが、記録がない #### psbid: 799 - run: 217, 236 - 217の結果が壊れてる #### psbid: 802 - run: 217, 236 - 217の結果が壊れてる #### psbid: 1001 - run: 319, 299 - 299でQSPIpが失敗している。319を使う #### psbid: 1034 - run: 305, 319 - 305で振動、319を使う """ # ╔═╡ 26976b6c-3954-4a41-a99b-c1aaebdc645d md""" ### skewの分布 """ # ╔═╡ 38d472ca-6347-4096-828d-fd1256130a59 df_skews_selected = let df df = combine( gdf_skews_on_psbid, sdf -> begin all(ismissing, sdf.skew) && @info "" sdf if nrow(sdf) == 1 # TODO: remove 1563 bypass sdf.psbid[1] == 1563 || @assert sdf.skew |> first |> !ismissing sdf ( skew = sdf.skew |> first, width = sdf.width |> first, riseup = sdf.riseup |> first, runid = sdf.runid |> first, ) else if sdf.psbid[1] == 291 df = filter(:runid => ==(94), sdf) @assert nrow(df) == 1 ( skew = df.skew |> first, width = sdf.width |> first, riseup = sdf.riseup |> first, runid = sdf.runid |> first, ) elseif sdf.psbid[1] == 460 df = filter(:runid => ==(132), sdf) @assert nrow(df) == 1 ( skew = df.skew |> first, width = sdf.width |> first, riseup = sdf.riseup |> first, runid = sdf.runid |> first, ) elseif sdf.psbid[1] == 545 df = filter(:runid => ==(132), sdf) @assert nrow(df) == 1 ( skew = df.skew |> first, width = sdf.width |> first, riseup = sdf.riseup |> first, runid = sdf.runid |> first, ) else # assume that runid is chronological i = argmax(sdf.runid .|> (id -> ismissing(id) ? -1 : id)) ( skew = sdf.skew[i], width = sdf.width[i], riseup = sdf.riseup[i], runid = sdf.runid[i], ) end end end, ) leftjoin!(df, select(qaqc_runs, [:id, :campaign_id]), on = :runid => :id) df end # ╔═╡ 310710da-ebb2-4f54-b238-38d493a6a533 let skews = df_skews_selected.skew |> skipmissing |> collect fig = Figure() ax = Axis(fig[1, 1], title = "skews (n = $(length(skews)))", xlabel = "skew / ns") stephist!(ax, skews, bins = range(minimum(skews), maximum(skews), step = 1 / 56)) fig end # ╔═╡ d92e0f9f-ed53-4ad6-a390-5a395e8ab8bc md""" #### 異常に小さい値 (psbid: 444, 1215) psbid: 444 - 出荷済み psbid: 1215 - QSPIp fail - 未出荷 """ # ╔═╡ e9964184-1a2a-4ab9-bc22-2705a25393ec filter(:skew => (x -> !ismissing(x) && x < -2), df_skews_selected) # ╔═╡ bedf8dff-e109-4757-82e5-3232fcad752d md""" #### 欠損値(psbid: 255) """ # ╔═╡ f2d0ea9b-ede7-496a-8d1f-9f748f9d1666 transform( filter(:skew => ismissing, df_skews_selected), :psbid => ByRow(psbid -> begin psbid in qaqc_dispatch.psb_id end) => :is_dispatched, ) # ╔═╡ f5bc8b1a-3fee-48ed-9910-367a1cda632e md""" - psbid: 255 - Si not locked """ # ╔═╡ 106b8abe-0040-48f1-b663-c00ca7673520 filter(:riseup => !=(1), df_skews_selected) # ╔═╡ a06d16ee-a4be-40de-8dac-fd818754373c md""" #### 立ち上がりが複数回(psbid: 255, 435, 444, 460) skew結果として使った測定について、立ち上がり回数が1ではないもののリスト ##### psbid: 435 - 立ち上がり後途中で何故か0が入ってる - 出荷済み """ # ╔═╡ 9f3f780d-da6e-44b4-a002-c2f088681e9c df_skews_selected_sorted = let df = sort(df_skews_selected, :skew) dropmissing!(df, :skew) df end # ╔═╡ 5c74d0a8-f856-4988-b8f4-d2e02dc26f52 sort(df_skews_selected_sorted, :skew, order = Base.Order.Reverse) # ╔═╡ 07342d98-3889-4a19-8419-6d113fffb42e md""" #### 立ち上がり時間の分布 """ # ╔═╡ 939aba6b-b03c-42b6-83b3-9cea5f4eb858 let skew_widths = df_skews_selected.width |> skipmissing |> collect bins = range(0, maximum(skew_widths), step = 1 / 56)# .- 0.01 hist( skew_widths, bins = bins, bar_labels = :y, label_size = 14, label_formatter = x -> "$(round(Int, x))", axis = ( title = "clock rise span distribution", xlabel = "rise up span / ns", ylabel = "counts", limits = ((0, 0.28), (0, nothing)), # xticks = (bins, string.(round.(bins, digits = 3))), # xticklabelrotation = π / 3, ), ) end # ╔═╡ aa9b78bc-8d66-4df2-bd06-1cbf21190488 filter(:width => (x -> ismissing(x) || x < 0.06), df_skews_selected) # ╔═╡ 76f44129-34c6-451d-af3f-4593dd1dda5c md""" ## skewの時間依存性 以下のrun - 382: ファームウェア最新 """ # ╔═╡ 0dd4c5fe-71d0-45d0-897e-51d1aa06bd3b df_extra_measurements = let df_configs = DataFrame( position_name = ["B-$(i)-$(j)" for j in 1:9 for i in 0:1], psbid = [ 001142, 000973, 000990, 000992, 001113, 001030, 001121, 001141, 001050, 001053, 001110, 001248, 001242, 001276, 000872, 000861, 000525, 000862, ], position = [1, 10, 2, 11, 3, 12, 4, 13, 5, 14, 6, 15, 7, 16, 8, 17, 9, 18], ) @info "" df_configs combine( groupby(df_configs, :psbid), AsTable(:) => ( sdf -> begin @assert nrow(sdf) == 1 map([382, 404]) do runid clkfile = "../test/input/slavelogs/main/$(sdf.psbid[1])_$(runid)_clk.txt" skew, width = PSBoardDataBase.ClockParser.get_skew_and_riseup(clkfile) offset = qaqc_positions.rising_ns[findfirst( ==(sdf.position[1]), qaqc_positions.id, )] return (; position_name = sdf.position_name |> first, psbid = sdf.psbid |> first, position = sdf.position |> first, skew = skew - offset, width, runid, campaign_id = 6, ) end end ) => [ :position_name, :psbid, :position, :skew, :width, :runid, :campaign_id, ], ) end # ╔═╡ 148e42fc-d168-4e07-b4f8-f9c3f8c18efc df_compare = let df_old_measurements = filter(:psbid => in(df_extra_measurements.psbid), df_skews_selected) left_cols = [:psbid, :skew, :width, :runid, :campaign_id] df = vcat( select!(df_old_measurements, left_cols), select(df_extra_measurements, left_cols), ) sort!(df, :runid) end # ╔═╡ 3266d1fd-b8f0-4eb0-9a8e-2050bc9a626f # "comparison of multiple measurements of clock skew for 18 PS Boards" was deleted # because of new measurements for all 18 boards in campaign 6.5 let fig = Figure(size = (600, 500)) grd1 = fig[1, 1] = GridLayout() Label( grd1[0, 1:2], "comparison of multiple measurements of clock skew for 18 PS Boards", tellwidth = false, ) ax1 = Axis( grd1[1, 1], limits = ((-0.15, 2.35), nothing), xticks = (0:2, ["old", "new(382)", "new(404)"]), ylabel = "skew / ns", ) ax2 = Axis( grd1[1:2, 2], limits = ((2.9, 6.7), nothing), ylabel = "Δskew / ns", xticks = (3:6, string.(3:6)), xlabel = "campaign", yminorticksvisible = true, yminorgridvisible = true, ) colsize!(grd1, 2, Relative(0.4)) for (key, sdf) in pairs(groupby(df_compare, :psbid)) @info "" sdf.runid # @assert sdf.runid[2] == 382 && sdf.runid[3] == 404 scatterlines!( ax1, 0:1:2, sdf.skew, color = Makie.wong_colors()[sdf.campaign_id[1] |> Int64], alpha = 0.7, ) scatter!( ax2, sdf.campaign_id[1], mean(@view(sdf.skew[2:3])) - sdf.skew[1], marker = :x, color = Makie.wong_colors()[sdf.campaign_id[1] |> Int64], alpha = 0.7, ) errorbars!( ax2, [sdf.campaign_id[1]], [mean(@view(sdf.skew[2:3])) - sdf.skew[1]], [std(@view(sdf.skew[2:3]))], color = Makie.wong_colors()[sdf.campaign_id[1] |> Int64], alpha = 0.4, whiskerwidth = 5, ) text!( ax1, 2, sdf.skew |> last, text = string(sdf.psbid[1]), color = (:black, 0.5), align = (:left, :center), ) text!( ax2, sdf.campaign_id[1], mean(@view(sdf.skew[2:3])) - sdf.skew[1], text = string(sdf.psbid[1]), color = (:black, 0.5), align = (:left, :center), ) end campaigns = df_compare.campaign_id |> unique |> sort! .|> ceil .|> Int64 Legend( grd1[2, 1], [ [LineElement(color = color), MarkerElement(color = color, marker = :circle)] for color in Makie.wong_colors()[campaigns] ], string.(campaigns), "campaign id for old measurements", orientation = :horizontal, ) # fig end # ╔═╡ 660f2bd1-d4bc-45a8-9cf6-4e875aa9f7a2 let df = filter(:campaign_id => ==(6), df_skews_selected) leftjoin!(df, select(qaqc_runs, [:id, :run_datetime]), on = :runid => :id) # from UTC to JST(+9h) transform!(df, :run_datetime => ByRow(dt -> dt + Hour(9)) => :run_datetime) @assert all(!ismissing, df.run_datetime) dropmissing!(df, :run_datetime) transform!(df, :run_datetime => ByRow(Date) => :run_date) fig = Figure() gdf = groupby(df, :run_date) for (i, sdf) in enumerate(gdf) unit_converter = Makie.DateTimeConversion(Time) ax = Axis( fig[i, 1], title = string(keys(gdf)[i]), dim1_conversion = unit_converter, limits = ( ( Makie.convert_dim_value(unit_converter, Time(9)), Makie.convert_dim_value(unit_converter, Time(20)), ), (-2, 1), ), ) scatter!(ax, sdf.run_datetime .|> Time, sdf.skew, markersize = 7, alpha = 0.7) mean_runs = Union{Float64, Missing}[] std_runs = Union{Float64, Missing}[] datetime_runs = Time[] for sdf_samerun in groupby(sdf, :runid) push!(mean_runs, mean(sdf_samerun.skew |> skipmissing)) push!(std_runs, std(sdf_samerun.skew |> skipmissing)) push!(datetime_runs, sdf_samerun.run_datetime |> first) end scatterlines!( ax, datetime_runs, mean_runs, marker = :hline, markersize = 10, color = Makie.wong_colors()[2], ) errorbars!(ax, datetime_runs, mean_runs, std_runs, color = Makie.wong_colors()[2]) end fig end # ╔═╡ 86437ee6-ccea-43fa-bd93-d86fe055f28d md""" # プロットまとめ - 何らかの異常が見られたものをすべて除外してプロット !!! todo skew測定が使い物になるかのフラグをデータベースにいれる? """ # ╔═╡ 2a24c277-6679-49f3-b387-6937b7661a25 invalid_measurements = [215, 291, 442, 460, 462, 545, 799, 802, 444, 255, 435, 1213, 1215, 1563] #= TODO: remove =# # ╔═╡ 13b4112f-96ab-41a1-8ef1-d940771f6ece df_skews_selected_valids = let df = filter(:psbid => !in(invalid_measurements), df_skews_selected) df end # ╔═╡ 2dde2b39-8f8c-473b-8fed-393a9e3286d8 sort(df_skews_selected_valids, :skew) # ╔═╡ 2a579bc2-79f8-4773-8588-a413acb8a6d6 sort(df_skews_selected_valids, :skew, rev = true) # ╔═╡ cf658de8-a4c5-413e-b5e3-56b77a80336f sort(df_skews_selected, :width) # ╔═╡ 7efd380b-a976-4a86-8dff-8afd551f03fb sort(df_skews_selected, :width, rev = true) # ╔═╡ 6a856a55-2611-41d0-a2c7-3645c066fc3c begin @assert all(!ismissing, df_skews_selected_valids.skew) @assert all(!ismissing, df_skews_selected_valids.width) @assert all(==(1), df_skews_selected_valids.riseup) end # ╔═╡ 4f45c81e-df2d-481f-9d30-580e44e03c72 let rng = Random.Xoshiro(1000) example_results = rand(rng, eachrow(df_skews_selected_valids), 5) fig = Figure(size = (600, 500)) ax_1 = Axis( fig[1, 1], title = "example clock skew measurement result", xlabel = "offset / ns", ylabel = "count", limits = ((10, 16), nothing), ) ax_2 = Axis( fig[2, 1], title = "example clock after substracting position contribution", xlabel = "offset / ns", ylabel = "count", limits = ((-3, 3), nothing), ) for example_result in example_results psbid = example_result.psbid runid = example_result.runid single_run = filter( [:psboard_id, :runid] => ( (ref_psbid, ref_runid) -> begin psbid == ref_psbid && runid == ref_runid end ), qaqc_single_results, ) |> first pos_offset = qaqc_positions.rising_ns[single_run.position] rawfilename = "../test/input/slavelogs/main/$(psbid)_$(runid)_clk.txt" raw_points = map(eachline(rawfilename)) do line PSBoardDataBase.ClockParser._parse_line(line) end stds = map(raw_points) do ((time, count)) sqrt(count * (1000 - count) / 1000) end collected_points = map(raw_points) do ((time, count)) (time - pos_offset, count) end scatterlines!(ax_1, raw_points, markersize = 6, label = basename(rawfilename)) scatterlines!(ax_2, collected_points, markersize = 6, label = basename(rawfilename)) errorbars!(ax_1, raw_points, stds, whiskerwidth = 10) errorbars!(ax_2, collected_points, stds, whiskerwidth = 10) end axislegend(ax_2, position = :lt) fig end # ╔═╡ 92d701aa-ab90-4c91-977d-2ce92823d130 md""" ## skew分布 """ # ╔═╡ 4a4ef945-b312-44ed-ab62-ce01fc33f926 let bins = range( minimum(df_skews_selected_valids.skew) - 5 / 56, maximum(df_skews_selected_valids.skew) + 5 / 56, step = 2 / 56, ) fig = Figure() ax = Axis( fig[1, 1], title = "skews", limits = (nothing, (nothing, nothing)), xlabel = "skew / ns", ) sh1 = stephist!(ax, df_skews_selected_valids.skew, bins = bins) Legend( fig[1, 1], [sh1], [""" n = $(nrow(df_skews_selected_valids)) μ = $(@sprintf "%.2g" mean(df_skews_selected_valids.skew)) σ = $(@sprintf "%.2g" std(df_skews_selected_valids.skew)) """], tellwidth = false, tellheight = false, halign = :right, valign = :top, margin = (10, 10, 10, 10), ) save("psboard_skew_histogram.svg", fig) fig end # ╔═╡ bf62eaca-dd23-4470-9c02-20ce6f9f34d7 let df_with_raw = leftjoin( df_skews_selected_valids, select(df_rawskews, [:psbid, :runid, :skew]); on = [:psbid, :runid], renamecols = (identity => (s -> s * "_raw")), ) fig = Figure(size = (600, 600)) Label( fig[0, 1], "PS board clock skews measured in QAQC", tellwidth = false, fontsize = 20, ) ax_raw = Axis( fig[1, 1], limits = ((10, 16), nothing), title = "before substracting position contrib.", ) ax_new = Axis( fig[2, 1], limits = ((-3, 3), nothing), title = "after substracting position contrib.", xlabel = "skew / ns", ) sh1 = stephist!( ax_raw, df_with_raw.skew_raw, color = Makie.wong_colors()[2], bins = range(10, 16, step = 2 / 56), ) sh2 = stephist!( ax_new, df_with_raw.skew, color = Makie.wong_colors()[1], bins = range(-3, 3, step = 2 / 56), ) Legend( fig[1, 1], [sh1], [""" n = $(nrow(df_with_raw)) μ = $(@sprintf "%.4g" mean(df_with_raw.skew_raw)) σ = $(@sprintf "%.2g" std(df_with_raw.skew_raw)) """], tellwidth = false, tellheight = false, halign = :right, valign = :top, margin = (10, 10, 10, 10), ) Legend( fig[2, 1], [sh2], [""" n = $(nrow(df_skews_selected_valids)) μ = $(@sprintf "%.2g" mean(df_skews_selected_valids.skew)) σ = $(@sprintf "%.2g" std(df_skews_selected_valids.skew)) """], tellwidth = false, tellheight = false, halign = :right, valign = :top, margin = (10, 10, 10, 10), ) save("plots/skew_distrib_before_after.svg", fig) fig end # ╔═╡ 82063c4b-c0cf-4524-83fe-5207bb8363d8 md""" ### skew分布のcampaign依存性 """ # ╔═╡ dff359b1-4827-40c6-86e4-0915974ef27d let bins = range( minimum(df_skews_selected_valids.skew) - 5 / 56, maximum(df_skews_selected_valids.skew) + 5 / 56, step = 8 / 56, ) fig = Figure() ax = Axis( fig[1, 1], title = "skews", limits = (nothing, (nothing, nothing)), xlabel = "skew / ns", ) hists = Hist1D[] for gdf in groupby(df_skews_selected_valids, :campaign_id, sort = true) push!(hists, Hist1D(gdf.skew, binedges = bins)) end @info "" hists |> length sh1 = stackedhist!(ax, hists, error_color = (:black, 0), color = ColorSchemes.tab10) labels = ["campaign $i" for i in [1:6; 6.5; 7; 7.5]] elements = [PolyElement(polycolor = sh1.attributes.color[][i]) for i in 1:length(labels)] Legend( fig[1, 1], elements, labels, [""" n = $(nrow(df_skews_selected_valids)) μ = $(@sprintf "%.2g" mean(df_skews_selected_valids.skew)) σ = $(@sprintf "%.2g" std(df_skews_selected_valids.skew)) """], tellwidth = false, tellheight = false, halign = :right, valign = :top, margin = (10, 10, 10, 10), ) save("plots/skew_distrib_campaings.svg", fig) fig end # ╔═╡ 7920b03b-1d1a-4b51-bfc0-86d1361f2ff1 let fig = Figure() ax = Axis( fig[1, 1], xlabel = "psbid", ylabel = "skew / ns", title = "clock skew time dependency", ) scatter!(ax, df_skews_selected_valids.psbid, df_skews_selected_valids.skew) fig end # ╔═╡ e640424b-7f7b-4cca-a634-92749ceee170 let fig = Figure() ax = Axis( fig[1, 1], xlabel = "runid", ylabel = "skew / ns", title = "clock skew time dependency", ) @info "" qaqc_runs df_campaign_runlimits = let df = combine(groupby(qaqc_runs, :campaign_id), :id => extrema) dropmissing!(df) df end @info "" df_campaign_runlimits scatter!(ax, df_skews_selected_valids.runid, df_skews_selected_valids.skew) rangebars!(ax, 2.2, df_campaign_runlimits.id_extrema, direction = :x, color = :black, whiskerwidth = 10, ) text!( ax, df_campaign_runlimits.id_extrema .|> mean, fill(2.3, nrow(df_campaign_runlimits)), text = df_campaign_runlimits.campaign_id .|> string, align = (:center, :center) ) save("plots/skew_vs_runid.svg", fig) fig end # ╔═╡ c3236e51-12a3-43e1-afc4-71be54c0a869 let fig = Figure() ax = Axis( fig[1, 1], xlabel = "runid", ylabel = "skew / ns", title = "clock skew time dependency", limits = ((290, 320), nothing), xminorticksvisible = true, xminorgridvisible = true, ) scatter!(ax, df_skews_selected_valids.runid, df_skews_selected_valids.skew) text!( ax, df_skews_selected_valids.runid, df_skews_selected_valids.skew |> disallowmissing, text = string.(df_skews_selected_valids.psbid), color = (:black, 0.3), align = (:left, :center), ) df_byruns = combine( groupby(df_skews_selected_valids, :runid), AsTable(:) => (sdf -> begin (mean = mean(sdf.skew), std = std(sdf.skew)) end) => [:mean, :std], ) scatter!(ax, df_byruns.runid, df_byruns.mean, label = "mean") # vlines!(ax, [304]) let rangebars!( ax, [-1, -1], [293, 305], [304, 329], direction = :x, whiskerwidth = 10, color = :black, ) text!(ax, [(293 + 304) / 2, (305 + 329) / 2], [-1, -1], text = ["11-11", "11-12"]) end df_highlighted = filter( :psbid => in([973, 990, 992, 1030, 1050, 1053, 1110, 1113, 1121, 1141, 1142]), df_skews_selected_valids, ) @info "" df_highlighted scatter!( ax, df_highlighted.runid, df_highlighted.skew |> disallowmissing, marker = :x, markersize = 20, alpha = 0.3, ) axislegend(ax) fig end # ╔═╡ 126f5825-25c1-4628-b4ae-ffbd9830833c let df = leftjoin( df_skews_selected_valids, select(qaqc_runs, [:id, :run_datetime]), on = :runid => :id, ) # from UTC to JST(+9h) transform!(df, :run_datetime => ByRow(dt -> dt + Hour(9)) => :run_datetime) @assert all(!ismissing, df.run_datetime) dropmissing!(df, :run_datetime) transform!(df, :run_datetime => ByRow(Date) => :run_date) fig = Figure(size = (600, 900)) gdf = groupby(df, :campaign_id) for (i, sdf) in enumerate(gdf) unit_converter = Makie.DateTimeConversion(Time) ax = Axis( fig[i, 1], title = string(keys(gdf)[i]), dim1_conversion = unit_converter, limits = ( ( Makie.convert_dim_value(unit_converter, Time(0)), Makie.convert_dim_value(unit_converter, Time(23, 59, 59)), ), # (-2, 2), nothing, ), ) sdf = transform(sdf, :run_datetime => ByRow(Time) => :run_time) sort!(sdf, :run_time) scatter!(ax, sdf.run_datetime .|> Time, sdf.skew, markersize = 7, alpha = 0.7) df_runs = combine( groupby(sdf, :runid), AsTable(:) => ( sdf -> begin (; mean = mean(sdf.skew |> skipmissing), std = std(sdf.skew |> skipmissing), run_time = first(sdf.run_time), ) end ) => [:mean, :std, :run_time], ) sort!(df_runs, :run_time) scatterlines!( ax, df_runs.run_time, df_runs.mean, marker = :hline, markersize = 10, color = Makie.wong_colors()[2], ) errorbars!( ax, df_runs.run_time, df_runs.mean, df_runs.std, color = Makie.wong_colors()[2], ) end fig end # ╔═╡ 46b2a3cd-d2e6-4277-8b65-9c61f25f69e8 3 / 56 # ╔═╡ 55bad662-cfdd-45c8-81bf-4e65e5c8434e md""" ## 立ち上がり時間分布 """ # ╔═╡ 13bb4978-b98d-44a3-a4b6-4241cadc609b let bins = range( minimum(df_skews_selected_valids.width) - 1 / 56, maximum(df_skews_selected_valids.width) + 2 / 56, step = 1 / 56, ) fig = Figure() ax = Axis( fig[1, 1], title = "distribution of rise up spans", xlabel = "time / ns", xticks = (bins, string.(round.(bins, digits = 3))), xticklabelrotation = π / 3, ) h1 = hist!( ax, df_skews_selected_valids.width, bins = bins, bar_labels = :y, label_formatter = x -> "$(round(Int, x))", flip_labels_at = 330, ) Legend( fig[1, 1], [h1], [""" n = $(nrow(df_skews_selected_valids)) μ = $(@sprintf "%.2g" mean(df_skews_selected_valids.width)) σ = $(@sprintf "%.2g" std(df_skews_selected_valids.width)) """], tellwidth = false, tellheight = false, halign = :right, valign = :top, margin = (10, 10, 10, 10), ) save("psboard_clock_rise_span_histogram.svg", fig) fig end # ╔═╡ 2835ff7c-d6cc-49d8-b35c-0071a8364376 scatter( df_skews_selected_valids.runid, df_skews_selected_valids.width, markersize = 7, alpha = 0.2, axis = (xlabel = "runid", ylabel = "width"), ) # ╔═╡ 6c3c7669-d594-425d-bf05-9aa217c7656e md""" # turn on curves - lines on - the minimum and maximum skews - the minimum and maximum widths """ # ╔═╡ e9b3f541-d87d-4424-8b82-be1b7b3273d8 let psbid_width_min, psbid_width_max, psbid_width_typical = let df_normal = filter(:width => >(0.06), df_skews_selected_sorted) sort!(df_normal, :width) df_typical = filter(:width => (x -> 0.08 < x < 0.11), df_normal) rng = Random.Xoshiro(123) id_rand_typical = rand(rng, 1:nrow(df_typical)) first(df_normal).psbid, last(df_normal).psbid, df_typical[id_rand_typical, :psbid] end psbid_with_lines = [psbid_width_max, psbid_width_min, psbid_width_typical] fig = Figure() ax = Axis( fig[1, 1], title = "clock turn on curves", subtitle = "aligned on the last count = 0 points", xlabel = "ns", ylabel = "counts", limits = ((-0.05, 0.15), (0, 1000)), ) for file in clk_files psbid, runid = parse_filename(file) if psbid == 255 @info "Si not locked: skipped" psbid continue end single_runs = filter( [:psboard_id, :runid] => ( (ref_psbid, ref_runid) -> begin psbid == ref_psbid && runid == ref_runid end ), qaqc_single_results, ) if nrow(single_runs) != 1 if nrow(single_runs) != 0 @info "skipped" psbid runid nrow(single_runs) end continue end # offset = qaqc_positions.rising_ns[single_runs.position[1]] offset_pos = let # df = filter(:psbid => ==(psbid), df_skews_selected_sorted) # @assert nrow(df) == 1 "nrow: $(nrow(df)), psbid: $(psbid)" # df.skew[1] + qaqc_positions.rising_ns[single_runs.position[1]] end if psbid in psbid_with_lines points = eachline(file) .|> PSBoardDataBase.ClockParser._parse_line .|> (x -> (x[1] - offset_pos, x[2])) id_first_over0 = findfirst(points) do ((time, count)) count > 0 end points = map(points) do ((time, count)) time - points[id_first_over0][1], count end stds = map(points) do ((time, count)) sqrt(count * (1000 - count) / 1000) end label, color = if psbid == psbid_width_max "longest ($psbid)", (:red, 0.8) elseif psbid == psbid_width_min "shortest ($psbid)", (:blue, 0.8) elseif psbid == psbid_width_typical "typical ($psbid)", (:green, 0.8) end scatterlines!(ax, points, label = label, color = color) errorbars!(ax, points, stds, whiskerwidth = 10, color = color) end end axislegend(ax, position = :rb) save("psboard_clock_turnoncurve.svg", fig) fig end # ╔═╡ Cell order: # ╟─f25e7e08-8a73-4cac-ac7c-d310725c558d # ╠═7c69d12c-80a5-11ef-2674-e155a3483342 # ╠═effa7ed9-2ac4-4468-a474-e2bb662580fe # ╠═1a6322d4-9deb-4709-aa2e-df7d8be5b16f # ╠═11537f91-e16b-45f0-9768-6df842371d36 # ╠═268d3015-b8d3-48d9-b74a-062e258e0ec1 # ╟─62105832-df1f-4834-8da6-c542e22207d1 # ╠═dea6f143-7916-4765-92f6-2bfb97a72835 # ╟─41543c0c-d7c4-447b-a268-0d356c88d92c # ╠═633ecdee-7e2f-4de8-833a-21cd0351c1f1 # ╟─87f1966e-3b07-4f9d-8fc4-7b7aa4319d50 # ╠═f379d43c-9300-41f4-b0fc-3c9d749e3105 # ╟─33e099bc-ac4b-4b5f-88e7-20f4463c98ef # ╠═0e13f848-0efb-4775-9e3e-518b32588a79 # ╠═181c3fe6-d087-42e2-b175-3fb84c42e3e8 # ╟─dd669f14-989b-45ee-87d8-5d9cf282fafd # ╠═1e9c3944-0cd4-40da-9014-a9153d4e95ed # ╟─322cb530-65a5-4973-86f8-01ccc2439cc4 # ╠═c1caca5f-4cfd-4f22-82b4-7925002359e6 # ╠═3e5607fd-2a8a-4a1a-9e7b-3f23ef216fad # ╠═c1b9c0c3-00f8-4199-b07f-8888f1be625c # ╠═d6d04013-e0e4-49d5-a450-07ae164bfaa3 # ╠═0e680044-e4e1-4f39-a5c5-afa5c53fc7a7 # ╠═d7541b93-4c49-4dcd-bda0-91e447f44596 # ╟─e7faa647-79cd-4247-a3f2-9868c7b9d4ca # ╠═3a412a98-4a2d-4bfb-8053-b0f480fae921 # ╟─b38bbed4-8721-4e92-a546-f7926cc07dd3 # ╠═420dce0e-4757-48d9-84ec-7ddfac2fdff6 # ╠═99902640-fee3-4502-9c7e-cb08834bad0b # ╠═c79c6684-1b03-41b5-aa90-ef8c7a8eb69c # ╠═a1056aba-e484-4594-908b-4709896d0da0 # ╠═875bec26-e576-4f48-ba14-464bce503d75 # ╟─ec774495-c0be-47a4-9d2c-b48159c07013 # ╠═d082e07c-3b42-4362-bebf-63356979a49b # ╟─2d41c98b-630e-41e7-9332-25394a6285e8 # ╠═6ff9f397-5db9-45af-9bca-7a8d7756f8da # ╠═25688d24-5aee-43d3-aff9-b9efa0556070 # ╠═0d3f7f0a-1713-4e22-acbb-7d370fabf5a7 # ╠═239a808c-0411-4542-ae68-6ae6af333bd2 # ╠═8e57bde1-5f97-483d-906e-8ebfb65016d0 # ╠═92c2ac3f-8034-4e9e-aadb-8bb166fbc948 # ╠═893253c3-f0b2-401f-b892-b23291bcf5c1 # ╠═6467dcaa-6bd6-45c7-8c08-b310a09b8b0b # ╠═19f85f1b-07d3-48c2-9ca6-a5a8eb1ab746 # ╟─0d758cdf-0dda-4dc3-b489-35831812b718 # ╠═79e2f5d8-4609-4e9f-949e-6dc1f88c0b19 # ╠═eae649db-6b2b-4530-83a8-3438f29423cc # ╠═d607e10e-854f-4652-9a34-9e22a188e315 # ╠═5bef43cf-0f9b-40a2-bd47-620f42c36d8d # ╠═2795fd06-2f59-4e5b-829d-a8e428646790 # ╟─26976b6c-3954-4a41-a99b-c1aaebdc645d # ╠═38d472ca-6347-4096-828d-fd1256130a59 # ╠═310710da-ebb2-4f54-b238-38d493a6a533 # ╟─d92e0f9f-ed53-4ad6-a390-5a395e8ab8bc # ╠═e9964184-1a2a-4ab9-bc22-2705a25393ec # ╟─bedf8dff-e109-4757-82e5-3232fcad752d # ╠═f2d0ea9b-ede7-496a-8d1f-9f748f9d1666 # ╠═f5bc8b1a-3fee-48ed-9910-367a1cda632e # ╠═106b8abe-0040-48f1-b663-c00ca7673520 # ╠═a06d16ee-a4be-40de-8dac-fd818754373c # ╠═9f3f780d-da6e-44b4-a002-c2f088681e9c # ╠═5c74d0a8-f856-4988-b8f4-d2e02dc26f52 # ╠═07342d98-3889-4a19-8419-6d113fffb42e # ╠═939aba6b-b03c-42b6-83b3-9cea5f4eb858 # ╠═aa9b78bc-8d66-4df2-bd06-1cbf21190488 # ╠═76f44129-34c6-451d-af3f-4593dd1dda5c # ╠═0dd4c5fe-71d0-45d0-897e-51d1aa06bd3b # ╠═148e42fc-d168-4e07-b4f8-f9c3f8c18efc # ╠═3266d1fd-b8f0-4eb0-9a8e-2050bc9a626f # ╠═660f2bd1-d4bc-45a8-9cf6-4e875aa9f7a2 # ╠═86437ee6-ccea-43fa-bd93-d86fe055f28d # ╠═2a24c277-6679-49f3-b387-6937b7661a25 # ╠═13b4112f-96ab-41a1-8ef1-d940771f6ece # ╠═2dde2b39-8f8c-473b-8fed-393a9e3286d8 # ╠═2a579bc2-79f8-4773-8588-a413acb8a6d6 # ╠═cf658de8-a4c5-413e-b5e3-56b77a80336f # ╠═7efd380b-a976-4a86-8dff-8afd551f03fb # ╠═6a856a55-2611-41d0-a2c7-3645c066fc3c # ╠═4f45c81e-df2d-481f-9d30-580e44e03c72 # ╟─92d701aa-ab90-4c91-977d-2ce92823d130 # ╠═4a4ef945-b312-44ed-ab62-ce01fc33f926 # ╠═bf62eaca-dd23-4470-9c02-20ce6f9f34d7 # ╟─82063c4b-c0cf-4524-83fe-5207bb8363d8 # ╠═dff359b1-4827-40c6-86e4-0915974ef27d # ╠═7920b03b-1d1a-4b51-bfc0-86d1361f2ff1 # ╠═e640424b-7f7b-4cca-a634-92749ceee170 # ╠═c3236e51-12a3-43e1-afc4-71be54c0a869 # ╠═126f5825-25c1-4628-b4ae-ffbd9830833c # ╠═46b2a3cd-d2e6-4277-8b65-9c61f25f69e8 # ╟─55bad662-cfdd-45c8-81bf-4e65e5c8434e # ╠═13bb4978-b98d-44a3-a4b6-4241cadc609b # ╠═2835ff7c-d6cc-49d8-b35c-0071a8364376 # ╠═6c3c7669-d594-425d-bf05-9aa217c7656e # ╠═e9b3f541-d87d-4424-8b82-be1b7b3273d8