Modelling features in the power spectrum

While this package is designed to model broadband power spectral densities that are power-law-like, we can add narrow features using basis functions.

This feature is currently experimental and may not work properly. Use it at your own risk!

Defining the model and simulating form the model

we defined a power spectral model as sum of two QPOs and a bending power-law.

using Plots
using Pioran
using Random
using Distributions
cont = SingleBendingPowerLaw(0.5,1., 3.6)
q1 =  QPO(7.3,0.1,2)
q2 = QPO(9e-4,2,11)
𝓟 = cont + q1 + q2
f = 10 .^range(-3,1,1000)
p1 = Plots.plot(f,𝓟.(f),xlabel="Frequency (day^-1)",ylabel="Power Spectral Density",legend=true,framestyle = :box,xscale=:log10,yscale=:log10,lw=2,ylim=(1e-5,1e3),label="total")
p1 = Plots.plot!(f,q1.(f),label="QPO1",linestyle=:dash)
Plots.plot!(p1,f,q2.(f),label="QPO2",linestyle=:dot)
Plots.plot!(f,cont.(f),label="cont",linestyle=:dash)
p1
Example block output

We now simulate time series from this process. To do so we will use the GP method by approximating the bending power-law with basis functions.

t = range(0.,1e3,step=0.1)
yerr = 0.3*ones(length(t));
using QuadGK

In this example power spectrum is normalised by its integral (so its integral is the same as the model after approximation) to make proper comparison with the model.

f_min,f_max = 1/t[end],1/2/diff(t)[1]
norm = quadgk(x->𝓟(x),f_min,f_max,rtol=1e-14)[1]/2

𝓡 = approx(𝓟, f_min, f_max, 35, norm, basis_function="DRWCelerite")
GP = ScalableGP(0.0, 𝓡)
GPc = GP(t,yerr.^2)
AbstractGPs.FiniteGP{ScalableGP{AbstractGPs.GP{AbstractGPs.ConstMean{Float64}, Pioran.SumOfCelerite{StructArrays.StructArray{<:Pioran.SemiSeparable}}}, Pioran.SumOfCelerite{StructArrays.StructArray{<:Pioran.SemiSeparable}}, Symbol}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, LinearAlgebra.Diagonal{Float64, Vector{Float64}}}(
f: ScalableGP{AbstractGPs.GP{AbstractGPs.ConstMean{Float64}, Pioran.SumOfCelerite{StructArrays.StructArray{<:Pioran.SemiSeparable}}}, Pioran.SumOfCelerite{StructArrays.StructArray{<:Pioran.SemiSeparable}}, Symbol}(AbstractGPs.GP{AbstractGPs.ConstMean{Float64}, Pioran.SumOfCelerite{StructArrays.StructArray{<:Pioran.SemiSeparable}}}(AbstractGPs.ConstMean{Float64}(0.0), Pioran.SumOfCelerite{StructArrays.StructArray{<:Pioran.SemiSeparable}}(Celerite[Celerite(0.0009614055938121361, 0.0016652033351635463, 0.00015707963267948965, 0.00027206990463513265), Celerite(0.000943702123654745, 0.0016345400253806655, 0.00024068237516929115, 0.00041687410227956624), Celerite(0.0011991212851879655, 0.0020769389903828456, 0.00036878113813348153, 0.0006387476681202663), Celerite(0.001481605425813006, 0.002566215874277847, 0.0005650581092502792, 0.000978709354450289), Celerite(0.0018327924551438252, 0.0031744896520380073, 0.0008657998845752573, 0.0014996093892716152), Celerite(0.002271144616330877, 0.003933737866821604, 0.0013266059328395682, 0.0022977488773004377), Celerite(0.002807465526403659, 0.00486267293222924, 0.002032667516360898, 0.0035206834132319176), Celerite(0.003481056878954383, 0.006029367378386134, 0.0031145173783633665, 0.005394502340381571), Celerite(0.0042999546321537425, 0.007447739893131424, 0.004772161911404874, 0.008265626892498249), Celerite(0.005336439255850745, 0.009242983922638542, 0.0073120572281508926, 0.0126648546270086)  …  Celerite(0.006048948336661939, 0.0, 31.689033009267337, 0.0), Celerite(0.001991269374271665, 0.0, 48.55493739949656, 0.0), Celerite(0.0006559917555174591, 0.0, 74.39740888210642, 0.0), Celerite(0.00021665253656047155, 0.0, 113.99406002382602, 0.0), Celerite(7.085296004053316e-5, 0.0, 174.66529971907454, 0.0), Celerite(2.42515454439101e-5, 0.0, 267.62768971977687, 0.0), Celerite(6.642219806795628e-6, 0.0, 410.06760026143485, 0.0), Celerite(4.1047060733927795e-6, 0.0, 628.3185307179587, 0.0), Celerite(2.2938494605646897, 0.5922693839649275, 0.15707963267948966, 0.6083668013960418), Celerite(0.031108369396699222, 0.0014154798193870928, 0.5711986642890533, 12.553382114129409)], [0.0009614055938121361, 0.000943702123654745, 0.0011991212851879655, 0.001481605425813006, 0.0018327924551438252, 0.002271144616330877, 0.002807465526403659, 0.003481056878954383, 0.0042999546321537425, 0.005336439255850745  …  0.006048948336661939, 0.001991269374271665, 0.0006559917555174591, 0.00021665253656047155, 7.085296004053316e-5, 2.42515454439101e-5, 6.642219806795628e-6, 4.1047060733927795e-6, 2.2938494605646897, 0.031108369396699222], [0.0016652033351635463, 0.0016345400253806655, 0.0020769389903828456, 0.002566215874277847, 0.0031744896520380073, 0.003933737866821604, 0.00486267293222924, 0.006029367378386134, 0.007447739893131424, 0.009242983922638542  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5922693839649275, 0.0014154798193870928], [0.00015707963267948965, 0.00024068237516929115, 0.00036878113813348153, 0.0005650581092502792, 0.0008657998845752573, 0.0013266059328395682, 0.002032667516360898, 0.0031145173783633665, 0.004772161911404874, 0.0073120572281508926  …  31.689033009267337, 48.55493739949656, 74.39740888210642, 113.99406002382602, 174.66529971907454, 267.62768971977687, 410.06760026143485, 628.3185307179587, 0.15707963267948966, 0.5711986642890533], [0.00027206990463513265, 0.00041687410227956624, 0.0006387476681202663, 0.000978709354450289, 0.0014996093892716152, 0.0022977488773004377, 0.0035206834132319176, 0.005394502340381571, 0.008265626892498249, 0.0126648546270086  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.6083668013960418, 12.553382114129409])), Pioran.SumOfCelerite{StructArrays.StructArray{<:Pioran.SemiSeparable}}(Celerite[Celerite(0.0009614055938121361, 0.0016652033351635463, 0.00015707963267948965, 0.00027206990463513265), Celerite(0.000943702123654745, 0.0016345400253806655, 0.00024068237516929115, 0.00041687410227956624), Celerite(0.0011991212851879655, 0.0020769389903828456, 0.00036878113813348153, 0.0006387476681202663), Celerite(0.001481605425813006, 0.002566215874277847, 0.0005650581092502792, 0.000978709354450289), Celerite(0.0018327924551438252, 0.0031744896520380073, 0.0008657998845752573, 0.0014996093892716152), Celerite(0.002271144616330877, 0.003933737866821604, 0.0013266059328395682, 0.0022977488773004377), Celerite(0.002807465526403659, 0.00486267293222924, 0.002032667516360898, 0.0035206834132319176), Celerite(0.003481056878954383, 0.006029367378386134, 0.0031145173783633665, 0.005394502340381571), Celerite(0.0042999546321537425, 0.007447739893131424, 0.004772161911404874, 0.008265626892498249), Celerite(0.005336439255850745, 0.009242983922638542, 0.0073120572281508926, 0.0126648546270086)  …  Celerite(0.006048948336661939, 0.0, 31.689033009267337, 0.0), Celerite(0.001991269374271665, 0.0, 48.55493739949656, 0.0), Celerite(0.0006559917555174591, 0.0, 74.39740888210642, 0.0), Celerite(0.00021665253656047155, 0.0, 113.99406002382602, 0.0), Celerite(7.085296004053316e-5, 0.0, 174.66529971907454, 0.0), Celerite(2.42515454439101e-5, 0.0, 267.62768971977687, 0.0), Celerite(6.642219806795628e-6, 0.0, 410.06760026143485, 0.0), Celerite(4.1047060733927795e-6, 0.0, 628.3185307179587, 0.0), Celerite(2.2938494605646897, 0.5922693839649275, 0.15707963267948966, 0.6083668013960418), Celerite(0.031108369396699222, 0.0014154798193870928, 0.5711986642890533, 12.553382114129409)], [0.0009614055938121361, 0.000943702123654745, 0.0011991212851879655, 0.001481605425813006, 0.0018327924551438252, 0.002271144616330877, 0.002807465526403659, 0.003481056878954383, 0.0042999546321537425, 0.005336439255850745  …  0.006048948336661939, 0.001991269374271665, 0.0006559917555174591, 0.00021665253656047155, 7.085296004053316e-5, 2.42515454439101e-5, 6.642219806795628e-6, 4.1047060733927795e-6, 2.2938494605646897, 0.031108369396699222], [0.0016652033351635463, 0.0016345400253806655, 0.0020769389903828456, 0.002566215874277847, 0.0031744896520380073, 0.003933737866821604, 0.00486267293222924, 0.006029367378386134, 0.007447739893131424, 0.009242983922638542  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5922693839649275, 0.0014154798193870928], [0.00015707963267948965, 0.00024068237516929115, 0.00036878113813348153, 0.0005650581092502792, 0.0008657998845752573, 0.0013266059328395682, 0.002032667516360898, 0.0031145173783633665, 0.004772161911404874, 0.0073120572281508926  …  31.689033009267337, 48.55493739949656, 74.39740888210642, 113.99406002382602, 174.66529971907454, 267.62768971977687, 410.06760026143485, 628.3185307179587, 0.15707963267948966, 0.5711986642890533], [0.00027206990463513265, 0.00041687410227956624, 0.0006387476681202663, 0.000978709354450289, 0.0014996093892716152, 0.0022977488773004377, 0.0035206834132319176, 0.005394502340381571, 0.008265626892498249, 0.0126648546270086  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.6083668013960418, 12.553382114129409]), :celerite)
x: 0.0:0.1:1000.0
Σy: [0.09 0.0 … 0.0 0.0; 0.0 0.09 … 0.0 0.0; … ; 0.0 0.0 … 0.09 0.0; 0.0 0.0 … 0.0 0.09]
)

We can sample realisations from this process:

rng = MersenneTwister(12)
y = [rand(rng,GPc) for i in 1:100]
Plots.plot(t,y[1:3],xlabel="Time",ylabel="Value",legend=false,framestyle = :box,ms=3)
Example block output

As it is not very informative to look at the time series, let's compute the periodogram using Tonari.jl.

using Tonari
x_GP = mapreduce(permutedims,vcat,y)
fP,I = periodogram(t,x_GP',apply_end_matching=false)
([0.000999900009999, 0.001999800019998, 0.0029997000299970002, 0.003999600039996, 0.004999500049995, 0.0059994000599940004, 0.006999300069993001, 0.007999200079992, 0.008999100089991, 0.00999900009999  …  4.99050094990501, 4.991500849915008, 4.992500749925007, 4.993500649935006, 4.9945005499450055, 4.995500449955005, 4.996500349965004, 4.997500249975002, 4.998500149985001, 4.999500049995], [47.158918780790685, 31.619410701359232, 26.334414392890416, 22.813761933617734, 25.61309815363729, 21.631188458887678, 21.735630877192804, 17.21150334043438, 20.919977005713474, 18.62706226412852  …  0.024250648792226798, 0.022468689479134826, 0.02592744583340088, 0.019456092303547577, 0.025548656336306416, 0.022275069391926184, 0.024284000846524354, 0.022215277775232405, 0.022347186433492126, 0.024696826556816175])
Δt = t[2]-t[1]
noise_level = 2Δt*mean(yerr.^2)

Plots.plot(fP,I,yscale=:log10,xscale=:log10,xlabel="Frequency (Hz)",ylabel="Power",label="Periodogram",framestyle=:box)
Plots.plot!(f,𝓟.(f),label="Model",linewidth=2)
hline!([noise_level],label="Noise level",linewidth=2,linestyle=:dash,ylim=(noise_level/10,1e3),)
Example block output

We can even compare the periodogram to the one of simulations using Timmer and König. See the documentation of Tonari.jl for more details:

T, Δt = 504.2, 0.132
simu = Simulation(𝓟, 1e3, 0.1, 20, 20)
rng = MersenneTwister(42)
N = 100
t_TK, x_TK, yerr_TK = sample(rng, simu, N, error_size = 0.25)
fP_TK,I_TK = periodogram(t_TK,x_TK,apply_end_matching=false)
([0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009000000000000001, 0.01  …  4.9910000000000005, 4.992, 4.993, 4.994, 4.995, 4.996, 4.997, 4.998, 4.999, 5.0], [50.60840630598973, 20.281774070297036, 30.834240939618464, 25.807963999220195, 15.697843014051099, 19.179527178870774, 16.5902728983377, 21.37396707249356, 29.145020347851812, 20.11771612020057  …  0.023900335603256564, 0.022882969906295212, 0.024639147281892895, 0.027820229883572162, 0.02987817536149938, 0.030568122632746844, 0.028762870394919517, 0.02454477593557762, 0.03355210991990242, 0.030121193090363232])

The periodograms agree with the input power spectrum.

Δt = t[2]-t[1]
noise_level = 2Δt*mean(yerr.^2)
noise_level_TK = 2Δt*mean(yerr_TK.^2)

Plots.plot(fP,I,yscale=:log10,xscale=:log10,xlabel="Frequency (Hz)",ylabel="Power",framestyle=:box,label="Periodogram GP",alpha=1,lw=.5)
Plots.plot!(fP_TK,I_TK,label="Periodogram TK",alpha=0.2)
Plots.plot!(f,𝓟.(f),label="Model",linewidth=2)
hline!([noise_level],label="Noise level",linewidth=2,linestyle=:dash,ylim=(noise_level/4,2e2),)
Example block output