Skip to content

Commit 51d80bf

Browse files
authored
Merge pull request #35 from JuliaSMLM/feature/sigma-xy-covariance
Add covariance fields to Emitter2DFit and Emitter3DFit (v0.6.0)
2 parents 919326b + 801e8b7 commit 51d80bf

File tree

5 files changed

+84
-23
lines changed

5 files changed

+84
-23
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "SMLMData"
22
uuid = "5488f106-40b8-4660-84c5-84a168990d1b"
33
authors = ["klidke@unm.edu"]
4-
version = "0.5.1"
4+
version = "0.6.0"
55

66
[deps]
77
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"

api_overview.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ mutable struct Emitter2DFit{T} <: AbstractEmitter
8787
bg::T # fitted background in photons/pixel
8888
σ_x::T # uncertainty in x position in microns
8989
σ_y::T # uncertainty in y position in microns
90+
σ_xy::T # covariance between x and y (microns², 0 = axis-aligned)
9091
σ_photons::T # uncertainty in photon count
9192
σ_bg::T # uncertainty in background level
9293
frame::Int # frame number in acquisition sequence
@@ -105,6 +106,9 @@ mutable struct Emitter3DFit{T} <: AbstractEmitter
105106
σ_x::T # uncertainty in x position in microns
106107
σ_y::T # uncertainty in y position in microns
107108
σ_z::T # uncertainty in z position in microns
109+
σ_xy::T # covariance between x and y (microns², 0 = uncorrelated)
110+
σ_xz::T # covariance between x and z (microns², 0 = uncorrelated)
111+
σ_yz::T # covariance between y and z (microns², 0 = uncorrelated)
108112
σ_photons::T # uncertainty in photon count
109113
σ_bg::T # uncertainty in background level
110114
frame::Int # frame number in acquisition sequence
@@ -138,6 +142,7 @@ emitter_2d_fit = Emitter2DFit{Float64}(
138142
1000.0, 10.0, # photons detected, background photons/pixel
139143
0.01, 0.01, # σ_x, σ_y: position uncertainties in microns
140144
50.0, 2.0; # σ_photons, σ_bg: photon count uncertainties
145+
σ_xy=0.005, # covariance (optional, default=0 for axis-aligned uncertainty)
141146
frame=5, # frame number in acquisition (1-based, default=1)
142147
dataset=1, # dataset identifier for multi-acquisition experiments
143148
track_id=2, # tracking ID for linked localizations (default=0 = unlinked)

docs/src/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ mutable struct Emitter2DFit{T} <: AbstractEmitter
7171
bg::T # fitted background in photons/pixel
7272
σ_x::T # uncertainty in x position in microns
7373
σ_y::T # uncertainty in y position in microns
74+
σ_xy::T # covariance between x and y (microns², 0 = axis-aligned)
7475
σ_photons::T # uncertainty in photon count
7576
σ_bg::T # uncertainty in background level
7677
frame::Int # frame number in acquisition sequence
@@ -88,6 +89,9 @@ mutable struct Emitter3DFit{T} <: AbstractEmitter
8889
σ_x::T # uncertainty in x position in microns
8990
σ_y::T # uncertainty in y position in microns
9091
σ_z::T # uncertainty in z position in microns
92+
σ_xy::T # covariance between x and y (microns², 0 = uncorrelated)
93+
σ_xz::T # covariance between x and z (microns², 0 = uncorrelated)
94+
σ_yz::T # covariance between y and z (microns², 0 = uncorrelated)
9195
σ_photons::T # uncertainty in photon count
9296
σ_bg::T # uncertainty in background level
9397
frame::Int # frame number in acquisition sequence
@@ -118,6 +122,7 @@ emitter_2d_fit = Emitter2DFit{Float64}(
118122
1000.0, 10.0, # photons, background
119123
0.01, 0.01, # σ_x, σ_y (uncertainties in μm)
120124
50.0, 2.0; # σ_photons, σ_bg (uncertainties)
125+
σ_xy=0.005, # covariance (optional, 0 = axis-aligned)
121126
frame=5, # frame number
122127
dataset=1, # dataset identifier
123128
track_id=2, # tracking identifier (0 = unlinked)
@@ -130,6 +135,7 @@ emitter_3d_fit = Emitter3DFit{Float64}(
130135
1000.0, 10.0, # photons, background
131136
0.01, 0.01, 0.02, # σ_x, σ_y, σ_z (uncertainties in μm)
132137
50.0, 2.0; # σ_photons, σ_bg (uncertainties)
138+
σ_xy=0.005, σ_xz=0.002, σ_yz=0.003, # covariances (optional, 0 = uncorrelated)
133139
frame=5, # frame number
134140
dataset=1, # dataset identifier
135141
track_id=2, # tracking identifier (0 = unlinked)

src/types/emitters.jl

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Represents fitted 2D localization results with uncertainties and temporal/tracki
5252
- `bg::T`: fitted background in photons/pixel
5353
- `σ_x::T`: uncertainty in x position in microns
5454
- `σ_y::T`: uncertainty in y position in microns
55+
- `σ_xy::T`: covariance between x and y uncertainties (microns², 0 = axis-aligned)
5556
- `σ_photons::T`: uncertainty in photon count
5657
- `σ_bg::T`: uncertainty in background in photons/pixel
5758
- `frame::Int`: frame number in acquisition sequence
@@ -66,6 +67,7 @@ mutable struct Emitter2DFit{T} <: AbstractEmitter
6667
bg::T
6768
σ_x::T
6869
σ_y::T
70+
σ_xy::T
6971
σ_photons::T
7072
σ_bg::T
7173
frame::Int
@@ -88,6 +90,9 @@ Represents fitted 3D localization results with uncertainties and temporal/tracki
8890
- `σ_x::T`: uncertainty in x position in microns
8991
- `σ_y::T`: uncertainty in y position in microns
9092
- `σ_z::T`: uncertainty in z position in microns
93+
- `σ_xy::T`: covariance between x and y (microns², 0 = uncorrelated)
94+
- `σ_xz::T`: covariance between x and z (microns², 0 = uncorrelated)
95+
- `σ_yz::T`: covariance between y and z (microns², 0 = uncorrelated)
9196
- `σ_photons::T`: uncertainty in photon count
9297
- `σ_bg::T`: uncertainty in background in photons/pixel
9398
- `frame::Int`: frame number in acquisition sequence
@@ -104,6 +109,9 @@ mutable struct Emitter3DFit{T} <: AbstractEmitter
104109
σ_x::T
105110
σ_y::T
106111
σ_z::T
112+
σ_xy::T
113+
σ_xz::T
114+
σ_yz::T
107115
σ_photons::T
108116
σ_bg::T
109117
frame::Int
@@ -115,7 +123,7 @@ end
115123

116124
"""
117125
Emitter2DFit{T}(x, y, photons, bg, σ_x, σ_y, σ_photons, σ_bg;
118-
frame=0, dataset=1, track_id=0, id=0) where T
126+
σ_xy=zero(T), frame=1, dataset=1, track_id=0, id=0) where T
119127
120128
Convenience constructor for 2D localization fit results with optional identification parameters.
121129
@@ -131,6 +139,7 @@ Convenience constructor for 2D localization fit results with optional identifica
131139
- `σ_bg::T`: uncertainty in background level
132140
133141
## Optional Keywords
142+
- `σ_xy::T=0`: covariance between x and y uncertainties (microns², 0 = axis-aligned)
134143
- `frame::Int=1`: frame number in acquisition sequence
135144
- `dataset::Int=1`: identifier for specific acquisition/dataset
136145
- `track_id::Int=0`: identifier for linking localizations across frames
@@ -146,23 +155,24 @@ emitter = Emitter2DFit{Float64}(
146155
50.0, 2.0 # σ_photons, σ_bg
147156
)
148157
149-
# Create emitter with specific frame and dataset
158+
# Create emitter with covariance for rotated uncertainty ellipse
150159
emitter = Emitter2DFit{Float64}(
151160
1.0, 2.0, 1000.0, 10.0, 0.01, 0.01, 50.0, 2.0;
152-
frame=5, dataset=2
161+
σ_xy=0.005, frame=5, dataset=2
153162
)
154163
```
155164
"""
156-
function Emitter2DFit{T}(x::T, y::T, photons::T, bg::T,
165+
function Emitter2DFit{T}(x::T, y::T, photons::T, bg::T,
157166
σ_x::T, σ_y::T, σ_photons::T, σ_bg::T;
158-
frame::Int=1, dataset::Int=1, track_id::Int=0, id::Int=0) where T
159-
Emitter2DFit{T}(x, y, photons, bg, σ_x, σ_y, σ_photons, σ_bg,
167+
σ_xy::T=zero(T), frame::Int=1, dataset::Int=1, track_id::Int=0, id::Int=0) where T
168+
Emitter2DFit{T}(x, y, photons, bg, σ_x, σ_y, σ_xy, σ_photons, σ_bg,
160169
frame, dataset, track_id, id)
161170
end
162171

163172
"""
164173
Emitter3DFit{T}(x, y, z, photons, bg, σ_x, σ_y, σ_z, σ_photons, σ_bg;
165-
frame=0, dataset=1, track_id=0, id=0) where T
174+
σ_xy=zero(T), σ_xz=zero(T), σ_yz=zero(T),
175+
frame=1, dataset=1, track_id=0, id=0) where T
166176
167177
Convenience constructor for 3D localization fit results with optional identification parameters.
168178
@@ -180,6 +190,9 @@ Convenience constructor for 3D localization fit results with optional identifica
180190
- `σ_bg::T`: uncertainty in background level
181191
182192
## Optional Keywords
193+
- `σ_xy::T=0`: covariance between x and y (microns², 0 = uncorrelated)
194+
- `σ_xz::T=0`: covariance between x and z (microns², 0 = uncorrelated)
195+
- `σ_yz::T=0`: covariance between y and z (microns², 0 = uncorrelated)
183196
- `frame::Int=1`: frame number in acquisition sequence
184197
- `dataset::Int=1`: identifier for specific acquisition/dataset
185198
- `track_id::Int=0`: identifier for linking localizations across frames
@@ -195,17 +208,18 @@ emitter = Emitter3DFit{Float64}(
195208
50.0, 2.0 # σ_photons, σ_bg
196209
)
197210
198-
# Create emitter with specific frame and tracking
211+
# Create emitter with full 3D covariance
199212
emitter = Emitter3DFit{Float64}(
200213
1.0, 2.0, -0.5, 1000.0, 10.0, 0.01, 0.01, 0.02, 50.0, 2.0;
201-
frame=5, track_id=1
214+
σ_xy=0.005, σ_xz=0.002, σ_yz=0.003, frame=5, track_id=1
202215
)
203216
```
204217
"""
205-
function Emitter3DFit{T}(x::T, y::T, z::T, photons::T, bg::T,
218+
function Emitter3DFit{T}(x::T, y::T, z::T, photons::T, bg::T,
206219
σ_x::T, σ_y::T, σ_z::T, σ_photons::T, σ_bg::T;
220+
σ_xy::T=zero(T), σ_xz::T=zero(T), σ_yz::T=zero(T),
207221
frame::Int=1, dataset::Int=1, track_id::Int=0, id::Int=0) where T
208-
Emitter3DFit{T}(x, y, z, photons, bg, σ_x, σ_y, σ_z, σ_photons, σ_bg,
222+
Emitter3DFit{T}(x, y, z, photons, bg, σ_x, σ_y, σ_z, σ_xy, σ_xz, σ_yz, σ_photons, σ_bg,
209223
frame, dataset, track_id, id)
210224
end
211225

@@ -263,6 +277,7 @@ function Base.show(io::IO, ::MIME"text/plain", e::Emitter2DFit{T}) where T
263277
println(io, " Uncertainties:")
264278
println(io, " σ_x: $(e.σ_x) μm")
265279
println(io, " σ_y: $(e.σ_y) μm")
280+
e.σ_xy != 0 && println(io, " σ_xy: $(e.σ_xy) μm²")
266281
println(io, " σ_photons: $(e.σ_photons)")
267282
println(io, " σ_bg: $(e.σ_bg)")
268283
println(io, " Frame: $(e.frame)")
@@ -289,6 +304,13 @@ function Base.show(io::IO, ::MIME"text/plain", e::Emitter3DFit{T}) where T
289304
println(io, " σ_x: $(e.σ_x) μm")
290305
println(io, " σ_y: $(e.σ_y) μm")
291306
println(io, " σ_z: $(e.σ_z) μm")
307+
has_cov = e.σ_xy != 0 || e.σ_xz != 0 || e.σ_yz != 0
308+
if has_cov
309+
println(io, " Covariances:")
310+
e.σ_xy != 0 && println(io, " σ_xy: $(e.σ_xy) μm²")
311+
e.σ_xz != 0 && println(io, " σ_xz: $(e.σ_xz) μm²")
312+
e.σ_yz != 0 && println(io, " σ_yz: $(e.σ_yz) μm²")
313+
end
292314
println(io, " σ_photons: $(e.σ_photons)")
293315
println(io, " σ_bg: $(e.σ_bg)")
294316
println(io, " Frame: $(e.frame)")

test/test_emitters.jl

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,55 +27,83 @@ end
2727
1.0, 2.0, # x, y
2828
1000.0, 10.0, # photons, bg
2929
0.01, 0.01, # σ_x, σ_y
30+
0.005, # σ_xy (covariance)
3031
50.0, 2.0, # σ_photons, σ_bg
3132
1, 1, 0, 1 # frame, dataset, track_id, id
3233
)
3334
@test e2df.x == 1.0
3435
@test e2df.σ_x == 0.01
36+
@test e2df.σ_xy == 0.005
3537
@test e2df.frame == 1
3638
@test e2df.track_id == 0
37-
38-
# Test convenience constructor
39+
40+
# Test convenience constructor (σ_xy defaults to 0)
3941
e2df_simple = Emitter2DFit{Float64}(
4042
1.0, 2.0, 1000.0, 10.0, 0.01, 0.01, 50.0, 2.0
4143
)
4244
@test e2df_simple.frame == 1 # default value
4345
@test e2df_simple.dataset == 1 # default value
4446
@test e2df_simple.track_id == 0 # default value
4547
@test e2df_simple.id == 0 # default value
48+
@test e2df_simple.σ_xy == 0.0 # default covariance
49+
50+
# Test convenience constructor with σ_xy
51+
e2df_cov = Emitter2DFit{Float64}(
52+
1.0, 2.0, 1000.0, 10.0, 0.01, 0.01, 50.0, 2.0;
53+
σ_xy=0.003
54+
)
55+
@test e2df_cov.σ_xy == 0.003
4656
end
4757

4858
@testset "3D Fit" begin
4959
# Test full constructor
5060
e3df = Emitter3DFit{Float64}(
51-
1.0, 2.0, 3.0, # x, y, z
52-
1000.0, 10.0, # photons, bg
53-
0.01, 0.01, 0.02, # σ_x, σ_y, σ_z
54-
50.0, 2.0, # σ_photons, σ_bg
55-
1, 1, 0, 1 # frame, dataset, track_id, id
61+
1.0, 2.0, 3.0, # x, y, z
62+
1000.0, 10.0, # photons, bg
63+
0.01, 0.01, 0.02, # σ_x, σ_y, σ_z
64+
0.005, 0.002, 0.003, # σ_xy, σ_xz, σ_yz (covariances)
65+
50.0, 2.0, # σ_photons, σ_bg
66+
1, 1, 0, 1 # frame, dataset, track_id, id
5667
)
5768
@test e3df.z == 3.0
5869
@test e3df.σ_z == 0.02
59-
60-
# Test convenience constructor
70+
@test e3df.σ_xy == 0.005
71+
@test e3df.σ_xz == 0.002
72+
@test e3df.σ_yz == 0.003
73+
74+
# Test convenience constructor (covariances default to 0)
6175
e3df_simple = Emitter3DFit{Float64}(
62-
1.0, 2.0, 3.0, 1000.0, 10.0,
76+
1.0, 2.0, 3.0, 1000.0, 10.0,
6377
0.01, 0.01, 0.02, 50.0, 2.0
6478
)
6579
@test e3df_simple.frame == 1
6680
@test e3df_simple.dataset == 1
81+
@test e3df_simple.σ_xy == 0.0
82+
@test e3df_simple.σ_xz == 0.0
83+
@test e3df_simple.σ_yz == 0.0
84+
85+
# Test convenience constructor with full 3D covariance
86+
e3df_cov = Emitter3DFit{Float64}(
87+
1.0, 2.0, 3.0, 1000.0, 10.0,
88+
0.01, 0.01, 0.02, 50.0, 2.0;
89+
σ_xy=0.003, σ_xz=0.001, σ_yz=0.002
90+
)
91+
@test e3df_cov.σ_xy == 0.003
92+
@test e3df_cov.σ_xz == 0.001
93+
@test e3df_cov.σ_yz == 0.002
6794
end
6895
end
6996

7097
@testset "Type Stability" begin
7198
# Test that operations maintain type stability
7299
e2d = Emitter2D{Float64}(1.0, 2.0, 1000.0)
73100
@test typeof(e2d.x) === Float64
74-
101+
75102
e2df = Emitter2DFit{Float32}(
76103
1.0f0, 2.0f0, 1000.0f0, 10.0f0,
77104
0.01f0, 0.01f0, 50.0f0, 2.0f0
78105
)
79106
@test typeof(e2df.x) === Float32
80107
@test typeof(e2df.σ_x) === Float32
108+
@test typeof(e2df.σ_xy) === Float32
81109
end

0 commit comments

Comments
 (0)