Skip to content

Commit

Permalink
Merge pull request #120 from legend-exp/patch_sipm-simple-peakfinder
Browse files Browse the repository at this point in the history
Patch `sipm_simple_calibration`
  • Loading branch information
theHenks authored Feb 26, 2025
2 parents 4179a69 + 8c62c6a commit 33f3e3d
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 11 deletions.
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ RadiationSpectra = "4f207c7e-01da-51d7-a1a0-c8c06dd1d883"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
SavitzkyGolay = "c4bf5708-b6a6-4fbe-bcd0-6850ed671584"
SnoopPrecompile = "66db9d55-30c0-4569-8b51-7e840670fc0c"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Expand Down Expand Up @@ -67,9 +68,9 @@ InverseFunctions = "0.1.8"
IrrationalConstants = "0.1.1, 0.2"
KernelDensity = "0.6.4"
LaTeXStrings = "1.3"
LogExpFunctions = "0.3.16"
LinearAlgebra = "<0.0.1, 1"
LinearRegression = "0.2"
LogExpFunctions = "0.3.16"
LsqFit = "0.14, 0.15"
Measurements = "2.5"
Measures = "0.3"
Expand All @@ -85,6 +86,7 @@ Random = "<0.0.1, 1"
RecipesBase = "1.3.4"
Roots = "2"
SnoopPrecompile = "1"
SavitzkyGolay = "0.9"
SpecialFunctions = "2.1.4"
Statistics = "<0.0.1, 1"
StatsBase = "0.33.7, 0.34"
Expand Down
1 change: 1 addition & 0 deletions src/LegendSpecFits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ using PropDicts
using RadiationSpectra
using RadiationSpectra: peakfinder
using Roots
using SavitzkyGolay
using SpecialFunctions
using StatsBase
using StructArrays
Expand Down
51 changes: 41 additions & 10 deletions src/sipm_simple_calibration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,33 +35,64 @@ function sipm_simple_calibration(pe_uncal::Vector{<:Real};
# Initial peak search
cuts_1pe = cut_single_peak(pe_uncal, initial_min_amp, initial_max_amp, relative_cut=relative_cut_noise_cut)

bin_width_cut_min = cuts_1pe.max+n_fwhm_noise_cut*(cuts_1pe.high - cuts_1pe.max)
bin_width_cut_min = if n_fwhm_noise_cut == 0.0
initial_min_amp
else
cuts_1pe.max+n_fwhm_noise_cut*(cuts_1pe.high - cuts_1pe.max)
end
bin_width_cut = get_friedman_diaconis_bin_width(filter(in(bin_width_cut_min..quantile(pe_uncal, initial_max_bin_width_quantile)), pe_uncal))
peakpos = []
for bin_width_scale in exp10.(range(0, stop=-3, length=50))
@debug "Using bin width: $(bin_width_cut)"

bin_width_cut_scaled = bin_width_cut * bin_width_scale
@debug "Using bin width: $(bin_width_cut_scaled)"
h_uncal_cut = fit(Histogram, pe_uncal, bin_width_cut_min:bin_width_cut_scaled:initial_max_amp)
if peakfinder_σ <= 0.0
peakfinder_σ = round(Int, 2*(cuts_1pe.high - cuts_1pe.max) / bin_width_cut_scaled / 2.355)
peakfinder_σ_scaled = if peakfinder_σ <= 0.0
round(Int, 2*(cuts_1pe.high - cuts_1pe.max) / bin_width_cut_scaled / (2 * sqrt(2 * log(2))) )
else
rount(Int, peakfinder_σ)
end
@debug "Peakfinder σ: $(peakfinder_σ)"
@debug "Peakfinder σ: $(peakfinder_σ_scaled)"
try
c, h_deconv, peakpos, threshold = RadiationSpectra.determine_calibration_constant_through_peak_ratios(h_uncal_cut, collect(range(min_pe_peak, max_pe_peak, step=1)),
min_n_peaks = 2, max_n_peaks = max_pe_peak, threshold=peakfinder_threshold, rtol=peakfinder_rtol, α=peakfinder_α, σ=peakfinder_σ)
# use SavitzkyGolay filter to smooth the histogram
sg_uncal_cut = savitzky_golay(h_uncal_cut.weights, ifelse(isodd(peakfinder_σ_scaled), peakfinder_σ_scaled, peakfinder_σ_scaled + 1), 3)
h_uncal_cut_sg = Histogram(h_uncal_cut.edges[1], sg_uncal_cut.y)
_, _, peakpos, _ = RadiationSpectra.determine_calibration_constant_through_peak_ratios(h_uncal_cut_sg, collect(range(min_pe_peak, max_pe_peak, step=1)),
min_n_peaks = 2, max_n_peaks = max_pe_peak, threshold=peakfinder_threshold, rtol=peakfinder_rtol, α=peakfinder_α, σ=peakfinder_σ_scaled)
catch e
@warn "Failed to find peaks with bin width scale $(bin_width_scale): $(e)"
continue
else
@debug "Found peaks with bin width scale $(bin_width_scale)"
if !isempty(peakpos)
if !isempty(peakpos) && length(peakpos) >= 2
break
end
end
end

if isempty(peakpos) || length(peakpos) < 2
if length(peakpos) < 2
@warn "Failed to find peaks with peakfinder method, use alternative"
bin_width_cut_scaled = bin_width_cut * 0.5
@debug "Using bin width: $(bin_width_cut_scaled)"

h_uncal_cut = fit(Histogram, pe_uncal, bin_width_cut_min:bin_width_cut_scaled:initial_max_amp)
peakfinder_σ_scaled = if peakfinder_σ <= 0.0
round(Int, 2*(cuts_1pe.high - cuts_1pe.max) / bin_width_cut_scaled / (2 * sqrt(2 * log(2))) )
else
rount(Int, peakfinder_σ)
end

# use SavitzkyGolay filter to smooth the histogram
sg_uncal_cut = savitzky_golay(h_uncal_cut.weights, ifelse(isodd(peakfinder_σ_scaled), peakfinder_σ_scaled, peakfinder_σ_scaled + 1), 3)
edges = StatsBase.midpoints(first(h_uncal_cut.edges)) # use midpoints as x values
counts_sg = sg_uncal_cut.y
# get local maxima
min_i_prominence = round(Int, peakfinder_σ_scaled / 2)
is_local_maximum(i, y) = i > min_i_prominence && i < length(y) - min_i_prominence &&
all(y[i] .> y[i-min_i_prominence:i-1]) && all(y[i] .> y[i+1:i+min_i_prominence])
peakpos = edges[findall(is_local_maximum.(eachindex(counts_sg), Ref(counts_sg)))]
end

if length(peakpos) < 2
throw(ErrorException("Failed to find peaks"))
end

Expand Down

0 comments on commit 33f3e3d

Please sign in to comment.