Commit 1e7ae33b authored by Éric Thiébaut's avatar Éric Thiébaut
Browse files

Change type name and provide higher level API for control loop

Change AbstractWavefrontSensorMeasure to AbstractWavefrontMeasure.

The `initialize` method is no longer defined, `reset` is sufficient
parent 4b22d1cd
......@@ -54,17 +54,6 @@ function stop end
function subimages_bounding_boxes end
function suspend end
"""
Tao.initialize(alg)
initializes algorithm `alg`. In a control loop, this method is called once
before entering the loop.
See also: [`Tao.measure!`](@ref) and [`Tao.postprocess`](@ref).
"""
function initialize end
"""
Tao.measure!(dest, alg, [wgt,] img) -> dest
......@@ -75,9 +64,34 @@ In a control loop, this method is called immediately after each acquired image
and it shall deliver the measurements as quickly as possible. If additional
processing is required, they can be performed by the method `Tao.postprocess`
which is called after sending the commands and before waiting for the next
image.
image. The method `Tao.reset` is called on the algorithm `alg` on entry of the
loop.
A control loop looks like:
reset(alg)
while true
wgt, img = timedwait(WeightedImage, cam, timeout)
measure!(meas, alg, wgt, img)
... # <--- compute command and send it to the deformable mirror
postprocess(alg)
end
with `cam` is the wavefront sensor camera and `meas` is the storage for the
measurements.
Using the higher level interface, this simplifies to:
reset(wfs)
while true
meas = timedwait(wfs, timeout)
... # compute command and send it to the deformable mirror
end
with `wfs` the wavefront sensor which encapsulate and algoritm, a camera and
storage for the measurments.
See also: [`Tao.initialize`](@ref) and [`Tao.postprocess`](@ref),
See also: [`Tao.reset`](@ref) and [`Tao.postprocess`](@ref),
"""
function measure! end
......
......@@ -21,7 +21,7 @@
"""
struct ShackHartmannGeometry
dims::NTuple{2,Int} # wavefront sensor image dimensions
dims::Dims{2} # wavefront sensor image dimensions
boxes::Vector{BoundingBox{Int}} # bounding boxes of the sub-images
inds::Matrix{Int} # indexed layout
function ShackHartmannGeometry(dims::NTuple{2,Integer},
......@@ -42,7 +42,7 @@ struct ShackHartmannGeometry
end
(imin == 1 && imax == cnt) || error("invalid layout indice(s)")
length(boxes) == cnt || error("invalid number of bounding-boxes")
imagebox = BoundingBox(1:dims[1], 1:dims[2])
imagebox = BoundingBox{Int}(1:dims[1], 1:dims[2])
for box in boxes
if isempty(box) || !(box imagebox)
error("invalid sub-image bounding-box:", box)
......@@ -66,10 +66,10 @@ function ShackHartmannGeometry(dims::NTuple{2,Integer},
end
# FIXME: doc!
struct ShackHartmannSensor{T,
S<:AbstractWavefrontSensorMeasure{T},
A<:AbstractWavefrontSensorAlgorithm{S},
C<:AbstractCamera{T}} <: AbstractWavefrontSensor{S}
mutable struct ShackHartmannSensor{T,
S<:AbstractWavefrontMeasure{T},
A<:AbstractWavefrontSensorAlgorithm{S},
C<:AbstractCamera{T}} <: AbstractWavefrontSensor{S}
geom::ShackHartmannGeometry
cam::C # image provider connected to the wavefront sensor camera
alg::A # wavefront sensor algorithm
......@@ -79,6 +79,7 @@ struct ShackHartmannSensor{T,
# an array that is owned by the wavefront sensor object (much like the
# image provider which caches the pre-processed image and its weights).
meas::Vector{S} # cached measurements
counter::Int # loop counter
function ShackHartmannSensor{T,S,A,C}(geom::ShackHartmannGeometry,
cam::C,
......@@ -86,27 +87,29 @@ struct ShackHartmannSensor{T,
ref::AbstractVector{<:Point{<:Real}},
meas::AbstractVector{S}) where {
T,
S<:AbstractWavefrontSensorMeasure{T},
S<:AbstractWavefrontMeasure{T},
A<:AbstractWavefrontSensorAlgorithm{S},
C<:AbstractCamera{T}
}
# Minimal check to make sure that indices are not out of bounds.
len = length(geom)
length(alg) == len || error("invalid number of sub-images in algorithm")
length(ref) == len || error("invalid number of reference positions")
length(meas) == len || error("invalid number of measurements")
new{T,S,A,C}(geom, cam, alg, ref, meas)
new{T,S,A,C}(geom, cam, alg, ref, meas, 0)
end
end
# Constructors.
function ShackHartmannSensor(geom::ShackHartmannGeometry,
cam::C,
alg::A,
ref::AbstractVector{<:Point{<:Real}}) where {
T<:AbstractFloat,
S<:AbstractWavefrontSensorMeasure{T},
A<:AbstractWavefrontSensorAlgorithm{S},
C<:AbstractCamera{T}}
function ShackHartmannSensor(
geom::ShackHartmannGeometry,
cam::C,
alg::A,
ref::AbstractVector{<:Point{<:Real}} = default_reference(Point{T}, geom)) where {
T<:AbstractFloat,
S<:AbstractWavefrontMeasure{T},
A<:AbstractWavefrontSensorAlgorithm{S},
C<:AbstractCamera{T}}
ShackHartmannSensor{T,S,A,C}(geom, cam, alg, ref,
Vector{S}(undef, length(ref)))
end
......@@ -130,3 +133,17 @@ set_reference!(wfs::ShackHartmannSensor, ref::AbstractVector{<:Point}) = begin
end
subimages_bounding_boxes(wfs::ShackHartmannSensor) =
subimages_bounding_boxes(geometry(wfs))
function default_reference(T::Type{<:Point{<:AbstractFloat}},
geom::ShackHartmannGeometry)
default_reference(T, Tao.subimages_bounding_boxes(geom))
end
function default_reference(T::Type{<:Point{<:AbstractFloat}},
boxes::AbstractVector{<:BoundingBox{<:Integer}})
ref = Vector{T}(undef, length(boxes))
for i in eachindex(ref, boxes)
ref[i] = center(boxes[i])
end
return ref
end
......@@ -16,7 +16,7 @@ module WavefrontSensors
export
AbstractWavefrontSensor,
AbstractWavefrontSensorAlgorithm,
AbstractWavefrontSensorMeasure,
AbstractWavefrontMeasure,
ShackHartmannGeometry,
ShackHartmannSensor,
WavefrontSlope,
......@@ -27,6 +27,7 @@ export
device,
image_size,
layout,
measure!,
measurements,
reference,
reset,
......@@ -48,6 +49,7 @@ import ..Tao:
device,
image_size,
layout,
measure!,
measurements,
reference,
reset,
......@@ -67,7 +69,7 @@ import Base: write
"""
`Tao.AbstractWavefrontSensorMeasure{T}` is the super-type of the various
`Tao.AbstractWavefrontMeasure{T}` is the super-type of the various
concrete measure types provided by wavefront sensors. Parameter `T` is the
floating-point type of the measurements.
......@@ -77,7 +79,7 @@ types of wavefront sensor measurements.
Method [`Tao.floating_point_type`](@ref) yields `T`.
"""
abstract type AbstractWavefrontSensorMeasure{T<:AbstractFloat} end
abstract type AbstractWavefrontMeasure{T<:AbstractFloat} end
"""
......@@ -89,7 +91,7 @@ Basic method `eltype` applied to a wavefront sensor algorithm yields the
type of measurements given be the algorithm.
"""
abstract type AbstractWavefrontSensorAlgorithm{S<:AbstractWavefrontSensorMeasure} end
abstract type AbstractWavefrontSensorAlgorithm{S<:AbstractWavefrontMeasure} end
"""
......@@ -101,7 +103,7 @@ Basic method `eltype` applied to a wavefront sensor yields the
type of measurements given be the wavefront sensor.
"""
abstract type AbstractWavefrontSensor{S<:AbstractWavefrontSensorMeasure} end
abstract type AbstractWavefrontSensor{S<:AbstractWavefrontMeasure} end
"""
......@@ -116,7 +118,7 @@ Instances of descendant types have fields `x` and `y`. Method
types descendant of`Tao.AbstractWavefrontSlope{T}`.
"""
abstract type AbstractWavefrontSlope{T} <: AbstractWavefrontSensorMeasure{T} end
abstract type AbstractWavefrontSlope{T} <: AbstractWavefrontMeasure{T} end
# FIXME: doc!
struct WavefrontSlope{T} <: AbstractWavefrontSlope{T}
......@@ -189,7 +191,7 @@ Base.iterate(itr::AbstractWavefrontSlope, state::Tuple{Tuple,Int}) = begin
end
for X in (:AbstractWavefrontSensor,
:AbstractWavefrontSensorMeasure,
:AbstractWavefrontMeasure,
:AbstractWavefrontSensorAlgorithm)
@eval begin
floating_point_type(::T) where {T<:$X} = floating_point_type(T)
......@@ -321,10 +323,25 @@ resume(wfs::AbstractWavefrontSensor) = resume(camera(wfs))
resets the measurement algorithm used by the wavefront sensor `wfs`.
"""
reset(wfs::AbstractWavefrontSensor) = reset(algorithm(wfs))
reset(wfs::AbstractWavefrontSensor) = begin
wfs.counter = 0
reset(algorithm(wfs))
end
include("shackhartmann.jl")
Base.timedwait(wfs::AbstractWavefrontSensor, timeout) = begin
# If we are between 2 iterations of the loop, apply the algorithm
# post-processing.
if wfs.counter > 0
postprocess(algorithm(wfs))
end
# Wait for next processed image and return the measured slopes.
wgt, img = timedwait(WeightedImage, camera(wfs), timeout)
wfs.counter += 1
return measure!(measurements(wfs), algorithm(wfs), wgt, img)
end
"""
Tao.flatten(A) -> B
......@@ -449,7 +466,7 @@ for (W,M) in ((:WavefrontSlope, 2),
end
function write(path::AbstractString,
A::AbstractArray{<:AbstractWavefrontSensorMeasure};
A::AbstractArray{<:AbstractWavefrontMeasure};
overwrite::Bool=false, kwds...)
(overwrite == false && exists(path)) &&
throw_file_already_exists(path, "call `write!` or use `overwrite=true`")
......@@ -459,7 +476,7 @@ function write(path::AbstractString,
end
function write!(path::AbstractString,
A::AbstractArray{<:AbstractWavefrontSensorMeasure};
A::AbstractArray{<:AbstractWavefrontMeasure};
kwds...)
FitsIO(path, "w!") do io
write(io, A; kwds...)
......@@ -467,7 +484,7 @@ function write!(path::AbstractString,
end
function write(io::FitsIO,
A::AbstractArray{<:AbstractWavefrontSensorMeasure};
A::AbstractArray{<:AbstractWavefrontMeasure};
kwds...)
name, vers = hduname(A)
write(io, flatten(A);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment