diff --git a/Project.toml b/Project.toml index 3ba08a6..dd4a78e 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "SMLMData" uuid = "5488f106-40b8-4660-84c5-84a168990d1b" authors = ["klidke@unm.edu"] -version = "0.5.0" +version = "0.5.1" [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" diff --git a/src/types/cameras.jl b/src/types/cameras.jl index 9b8d929..13e77b8 100644 --- a/src/types/cameras.jl +++ b/src/types/cameras.jl @@ -422,7 +422,7 @@ Construct sCMOS camera from pixel dimensions and calibration parameters. - `gain::Union{T, Matrix{T}} = 1`: Conversion gain in e⁻/ADU - `qe::Union{T, Matrix{T}} = 1`: Quantum efficiency (0-1) -Each parameter can be scalar (uniform) or Matrix{T} with size (nx, ny). +Each parameter can be scalar (uniform) or Matrix{T} with size (ny, nx) following Julia's [row, col] convention. # Examples ```julia @@ -483,7 +483,7 @@ Construct sCMOS camera with custom pixel edge positions. - `gain::Union{T, Matrix{T}} = 1`: Conversion gain in e⁻/ADU - `qe::Union{T, Matrix{T}} = 1`: Quantum efficiency (0-1) -Matrix parameters must have size (nx, ny) where nx = length(pixel_edges_x) - 1. +Matrix parameters must have size (ny, nx) following Julia's [row, col] convention, where nx = length(pixel_edges_x) - 1 and ny = length(pixel_edges_y) - 1. # Example ```julia @@ -515,9 +515,11 @@ function SCMOSCamera( end # Validation helper +# Matrix parameters use Julia standard (row, col) = (y, x) convention +# So for a camera with nx columns and ny rows, matrices should be (ny, nx) function _validate_camera_param(param::AbstractMatrix, nx, ny, name) - size(param) == (nx, ny) || - throw(DimensionMismatch("$name size $(size(param)) must match ($nx, $ny)")) + size(param) == (ny, nx) || + throw(DimensionMismatch("$name size $(size(param)) must match ($ny, $nx) [rows, cols]")) end _validate_camera_param(param::Real, nx, ny, name) = nothing diff --git a/test/test_cameras.jl b/test/test_cameras.jl index a02bc9c..5e55355 100644 --- a/test/test_cameras.jl +++ b/test/test_cameras.jl @@ -252,10 +252,12 @@ end @test cam.readnoise === 1.5 @test cam.gain === 0.5 - # Matrix parameters - noise_map = ones(Float64, 10, 5) .* 1.2 + # Matrix parameters - size must be (ny, nx) = (rows, cols) following Julia convention + # edges_x has 11 elements → nx = 10 columns + # edges_y has 6 elements → ny = 5 rows + noise_map = ones(Float64, 5, 10) .* 1.2 # (ny, nx) = (5, 10) cam2 = SCMOSCamera(edges_x, edges_y, readnoise=noise_map) - @test size(cam2.readnoise) == (10, 5) + @test size(cam2.readnoise) == (5, 10) end @testset "Type stability" begin @@ -286,6 +288,27 @@ end @test_throws DimensionMismatch SCMOSCamera(10, 10, 0.1, 1.5, qe=wrong_size_map) end + @testset "Matrix convention (ny, nx) for rectangular cameras" begin + # Rectangular camera: 512 columns (x), 256 rows (y) + # Matrix must be (ny, nx) = (256, 512) following Julia [row, col] convention + nx, ny = 512, 256 + + # Create noise map with a marker at known position + noise_map = ones(Float64, ny, nx) # (256, 512) = (rows, cols) + noise_map[100, 300] = 5.0 # row 100, col 300 → pixel (x=300, y=100) + + cam = SCMOSCamera(nx, ny, 0.1, noise_map) + @test size(cam.readnoise) == (ny, nx) + @test size(cam.readnoise) == (256, 512) + + # Verify semantic access: map[y, x] gives value for pixel at (x, y) + @test cam.readnoise[100, 300] == 5.0 + + # Transposed matrix should fail + wrong_map = ones(Float64, nx, ny) # (512, 256) - WRONG + @test_throws DimensionMismatch SCMOSCamera(nx, ny, 0.1, wrong_map) + end + @testset "Realistic use cases" begin # ORCA-Flash4.0 V3 cam_flash = SCMOSCamera(