14 (declaim (optimize (speed 2) (debug 3) (safety 3)))
17 (sb-alien:define-alien-routine j0
19 (x sb-alien
:double-float
))
21 (sb-alien:define-alien-routine j1
23 (x sb-alien
:double-float
))
25 (sb-alien:define-alien-routine jn
28 (x sb-alien
:double-float
)))
31 (sb-alien:define-alien-routine
("j0f" j0
)
33 (x sb-alien
:single-float
))
35 (sb-alien:define-alien-routine
("j1f" j1
)
37 (x sb-alien
:single-float
))
39 (sb-alien:define-alien-routine
("jnf" jn
)
42 (x sb-alien
:single-float
)))
44 (deftype my-float-helper
()
47 (deftype my-float
(&optional
(low '*) (high '*))
48 `(single-float ,(if (eq low
'*)
50 (coerce low
'my-float-helper
))
53 (coerce high
'my-float-helper
))))
55 (defconstant +one
+ #.
(coerce 1 'my-float
))
58 (declare ((complex my-float
) z
)
59 (values my-float
&optional
))
60 (let* ((x (realpart z
))
65 (declaim (type fixnum n
)
66 (type my-float
/sin-alpha
/sin-alpha2 sin-alpha2
)
67 (type (my-float -
1 1) sin-alpha
)
68 (type (simple-array my-float
1) ac as as^
2 ac2
))
72 (defparameter ac
(make-array n
:element-type
'my-float
))
73 (defparameter as
(make-array n
:element-type
'my-float
))
74 (defparameter as^
2 (make-array n
:element-type
'my-float
))
75 (defparameter ac2
(make-array n
:element-type
'my-float
))
76 (defparameter sin-alpha
(coerce .4 'my-float
))
77 (defparameter sin-alpha2
(* sin-alpha sin-alpha
))
78 (defparameter /sin-alpha
(/ sin-alpha
))
79 (defparameter /sin-alpha2
(/ sin-alpha2
)))
81 (defun init (&key
(numerical-aperture (coerce 1.38 'my-float
))
82 (immersion-index (coerce 1.515 'my-float
))
83 (integrand-evaluations 31))
84 (declare (my-float numerical-aperture immersion-index
)
85 (fixnum integrand-evaluations
)
86 (values null
&optional
))
87 (setf n
(+ 1 (* 2 (floor integrand-evaluations
2))) ;; make sure its odd
88 ac
(make-array n
:element-type
'my-float
)
89 as
(make-array n
:element-type
'my-float
)
90 as^
2 (make-array n
:element-type
'my-float
)
91 ac2
(make-array n
:element-type
'my-float
)
92 sin-alpha
(/ numerical-aperture immersion-index
)
93 sin-alpha2
(* sin-alpha sin-alpha
)
94 /sin-alpha
(/ sin-alpha
)
95 /sin-alpha2
(/ sin-alpha2
))
96 (let* ((alpha (asin sin-alpha
))
100 (let* ((theta (the (my-float 0d0
2d0
) (* dalpha iter
)))
105 (declare ((my-float 0 1) ct
)) ;; for the sqrt
106 (setf (aref ac iter
) ct
108 (aref as^
2 iter
) st^
2
109 (aref ac2 iter
) ct2
)))))
113 ;; k = omega/c = 2 pi / lambda
114 ;; u = k z sin(alpha)^2
115 ;; v = k sqrt(x^2+y^2) sin(alpha)
117 ;; for small angular aperture alpha << 1
119 ;; v ~ k (a/R) sqrt(x^2+y^2)
120 ;; with a .. radius of the exit pupil and
121 ;; R .. distance between exit pupil and focal plane
123 (defun transform-xyz-to-uv (x y z
&key
(immersion-index (coerce 1.515 'my-float
))
124 (numerical-aperture (coerce 1.38 'my-float
))
125 (wavelength (coerce .480 'my-float
)))
126 "Return the cylindrical coordinates u and v of a given 3D point. All
127 lengths in micrometer."
128 (declare (my-float x y z immersion-index numerical-aperture wavelength
)
129 (values my-float my-float
&optional
))
130 (let* ((k (/ (* #.
(coerce 2 'my-float
) (coerce pi
'my-float
) immersion-index
)
132 (sina (/ numerical-aperture
134 (u (* k z sina sina
))
135 (v (* k
(sqrt (+ (* x x
) (* y y
))) sina
)))
139 (transform-xyz-to-uv 0.0 1.0 1.0)
141 (defun intermediate-integrals-point (u v
)
142 "Calculate the three integrals I1, I2 and I3 at a point u,v."
143 (declare (my-float u v
)
144 (values (complex my-float
) (complex my-float
)
145 (complex my-float
) &optional
))
146 (let* ((zero #.
(complex (coerce 0 'my-float
)))
152 (let* ((s (aref as iter
))
155 (vv (* v s
/sin-alpha
))
156 (uu (* u c
/sin-alpha2
))
157 (e (exp (complex #.
(coerce 0 'my-float
) uu
)))
158 (cmul0 (* scale e
(* c2 s
(+ 1 c
) (j0 vv
))))
159 (cmul1 (* scale e
(* c2
(aref as^
2 iter
) (j1 vv
))))
160 (cmul2 (* scale e
(* c2 s
(- 1 c
) (jn 2 vv
)))))
164 (cond ((eq iter
0) (setf scale
2))
165 ((eq iter
(- n
2)) (setf scale
1))
166 ((eq scale
2) (setf scale
4))
167 ((eq scale
4) (setf scale
2))))))
168 (let* ((s (* n
#.
(coerce 3 'my-float
))))
169 (values (* s i0
) (* s i1
) (* s i2
)))))
172 (init :integrand-evaluations
301)
174 (intermediate-integrals-point .0 .0)
176 (defun energy-density (u v
)
177 (declare (my-float u v
)
178 (values my-float
&optional
))
179 (multiple-value-bind (i0 i1 i2
)
180 (intermediate-integrals-point u v
)
186 (energy-density .0 .0)
188 (defun energy-density-cyl (&optional
(nu 100) (nv 100) (du #.
(coerce .1 'my-float
))
190 "Calculate a 2D image containing the energy density in cylindrical coordinates."
191 (declare (fixnum nu nv
)
193 (values (simple-array my-float
2) &optional
))
194 (let* ((res (make-array (list nu nv
)
195 :element-type
'my-float
)))
200 (setf (aref res iu iv
) (energy-density u v
))))))
203 (defun intermediate-integrals-cyl (&optional
(nu 100) (nv 100)
204 (du (coerce .1 'my-float
)) (dv du
))
205 (declare (fixnum nu nv
)
207 (values (simple-array (complex my-float
) 2)
208 (simple-array (complex my-float
) 2)
209 (simple-array (complex my-float
) 2) &optional
))
210 (let* ((dims (list nu nv
))
211 (ii0 (make-array dims
:element-type
'(complex my-float
)))
212 (ii1 (make-array dims
:element-type
'(complex my-float
)))
213 (ii2 (make-array dims
:element-type
'(complex my-float
))))
218 (multiple-value-bind (i0 i1 i2
)
219 (intermediate-integrals-point u v
)
220 (setf (aref ii0 iu iv
) i0
222 (aref ii2 iu iv
) i2
))))))
223 (values ii0 ii1 ii2
)))
231 (nradius (1+ (ceiling (* (sqrt 2d0
) (max x y
)))))
232 (nz (1+ (ceiling z
2))))
233 (multiple-value-bind (u v
)
234 (transform-xyz-to-uv size-x
0 (* .5d0 size-z
))
235 (multiple-value-bind (i0 i1 i2
)
236 (intermediate-integrals-cyl nz nradius
(/ u nz
) (/ v nradius
))
237 (vol::interpolate2-cdf i0
2d0
2d0
))))
239 ;; size radius is either the extend in x or y (in um) depending on what is bigger
240 (defun electric-field-psf
241 (z y x size-z size-radius
&key
(numerical-aperture (coerce 1.38 'my-float
))
242 (immersion-index (coerce 1.515 'my-float
))
243 (wavelength (coerce .480 'my-float
))
244 (integrand-evaluations 31))
245 (declare (fixnum z y x integrand-evaluations
)
246 (my-float size-z size-radius numerical-aperture immersion-index
248 (values (simple-array (complex my-float
) 3)
249 (simple-array (complex my-float
) 3)
250 (simple-array (complex my-float
) 3) &optional
))
251 (init :numerical-aperture numerical-aperture
252 :immersion-index immersion-index
253 :integrand-evaluations integrand-evaluations
)
254 (let* ((nradius (1+ (ceiling (* (sqrt (* +one
+ 2)) (max x y
)))))
257 (e0 (make-array dims
:element-type
'(complex my-float
)))
258 (e1 (make-array dims
:element-type
'(complex my-float
)))
259 (e2 (make-array dims
:element-type
'(complex my-float
))))
260 (multiple-value-bind (u v
)
261 (transform-xyz-to-uv #.
(coerce 0 'my-float
)
262 (* (sqrt (* +one
+ 2)) size-radius
)
264 :numerical-aperture numerical-aperture
265 :immersion-index immersion-index
266 :wavelength wavelength
)
267 (multiple-value-bind (i0 i1 i2
)
268 (intermediate-integrals-cyl nz nradius
269 (/ (* +one
+ u
) nz
) (/ (* +one
+ v
) nradius
))
270 (let ((rad-a (make-array (list y x
) :element-type
'my-float
))
271 (cphi-a (make-array (list y x
) :element-type
'my-float
))
272 (c2phi-a (make-array (list y x
) :element-type
'my-float
))
273 (s2phi-a (make-array (list y x
) :element-type
'my-float
)))
274 (do-region ((j i
) (y x
))
275 (let* ((ii (- i
(floor x
2)))
276 (jj (- j
(floor y
2)))
277 (one #.
(coerce 1 'my-float
))
278 (radius (sqrt (+ (* one ii ii
) (* jj jj
))))
279 (phi (atan (* one jj
) ii
)))
280 (setf (aref rad-a j i
) radius
281 (aref cphi-a j i
) (cos phi
)
282 (aref c2phi-a j i
) (cos (* one
2 phi
))
283 (aref s2phi-a j i
) (sin (* one
2 phi
)))))
284 (let ((neg-i #.
(complex (coerce 0 'my-float
) (coerce -
1 'my-float
)))
285 (del (if (eq 1 (mod z
2))
286 #.
(coerce 0 'my-float
)
287 #.
(coerce .5 'my-float
)))) ;; add .5 if z is even
288 (do-region ((k j i
) (nz y x
))
289 (let* ((zi (- nz k
(- +one
+ del
)))
291 (v0 (interpolate i0 zi r
))
292 (v1 (interpolate i1 zi r
))
293 (v2 (interpolate i2 zi r
)))
294 (setf (aref e0 k j i
)
295 (* neg-i
(+ v0
(* v2
(aref c2phi-a j i
))))
297 (* neg-i v2
(aref s2phi-a j i
))
298 (aref e2 k j i
) (* +one
+ -
2 v1
(aref cphi-a j i
))))))
299 (do-region ((k j i
) (nz y x
))
300 (setf (aref e0
(- z k
1) j i
) (- (conjugate (aref e0 k j i
)))
301 (aref e1
(- z k
1) j i
) (- (conjugate (aref e1 k j i
)))
302 (aref e2
(- z k
1) j i
) (conjugate (aref e2 k j i
)))))))
306 (progn (electric-field-psf 10 10 10 3.0 3.0) nil
)
308 (defun intensity-psf-cyl (z radius
&key
309 (numerical-aperture #.
(coerce 1.38 'my-float
))
310 (immersion-index #.
(coerce 1.515 'my-float
))
312 (wavelength #.
(coerce .480 'my-float
))
313 (integrand-evaluations 31))
314 "Calculate 2D cylindrical PSF with axial extend Z micrometers and
315 transversal extend RADIUS micrometers."
316 (declare (fixnum nz nradius integrand-evaluations
)
317 (my-float z radius numerical-aperture immersion-index
319 (values (simple-array my-float
2) &optional
))
320 (psf:init
:numerical-aperture numerical-aperture
321 :immersion-index immersion-index
322 :integrand-evaluations integrand-evaluations
)
323 (multiple-value-bind (u v
)
324 (transform-xyz-to-uv #.
(coerce 0 'my-float
) radius z
325 :numerical-aperture numerical-aperture
326 :immersion-index immersion-index
327 :wavelength wavelength
)
328 (let* ((a (energy-density-cyl nz nradius
(/ u nz
) (/ v nradius
))))
332 (progn (intensity-psf-cyl (coerce 3 'my-float
) (coerce 1.5 'my-float
))
335 (defun intensity-psf (z y x size-z size-radius
&key
336 (numerical-aperture #.
(coerce 1.38 'my-float
))
337 (immersion-index #.
(coerce 1.515 'my-float
))
338 (integrand-evaluations 31)
339 (wavelength #.
(coerce .480 'my-float
)))
340 "Calculate an intensity point spread function for an aplanatic
341 microobjective with the given NUMERICAL-APERTURE, IMMERSION-INDEX and
342 WAVELENGTH. Distances in micrometer."
343 (declare (fixnum z y x integrand-evaluations
)
344 (my-float size-z size-radius numerical-aperture immersion-index
346 (values (simple-array (complex my-float
) 3) &optional
))
347 (let* ((psf (make-array (list z y x
) :element-type
'(complex my-float
)))
348 (nz (1+ (ceiling z
2)))
349 (nradius (1+ (ceiling (* (sqrt (* +one
+ 2)) (max x y
)))))
350 (cyl (intensity-psf-cyl
352 (* (sqrt (* +one
+ 2)) size-radius
)
353 :nz nz
:nradius nradius
:numerical-aperture numerical-aperture
354 :immersion-index immersion-index
355 :integrand-evaluations integrand-evaluations
356 :wavelength wavelength
)))
357 (let ((rad-a (make-array (list y x
) :element-type
'my-float
)))
358 (do-region ((j i
) (y x
))
359 (let* ((ii (- i
(floor x
2)))
360 (jj (- j
(floor y
2)))
361 (radius (sqrt (+ (* +one
+ ii ii
) (* jj jj
)))))
362 (setf (aref rad-a j i
) radius
)))
363 (let ((del (if (eq 1 (mod z
2)) ;; add .5 when z is even
366 (do-region ((k j i
) (nz y x
))
367 (setf (aref psf k j i
)
368 (complex (interpolate cyl
369 (- nz k
(- +one
+ del
))
370 (aref rad-a j i
))))))
371 (do-region ((k j i
) (nz y x
))
372 (setf (aref psf
(- z k
1) j i
) (aref psf k j i
))))
379 ;; cylindrical coordinates:
383 #+nil
;; print out a cross section of the psf transversal 1.5 um and
385 (let ((numerical-aperture (coerce 1.38 'my-float
))
386 (immersion-index (coerce 1.515 'my-float
)))
387 (init :numerical-aperture numerical-aperture
388 :immersion-index immersion-index
)
389 (multiple-value-bind (u v
)
390 (transform-xyz-to-uv (coerce 0 'my-float
) (coerce 1.5 'my-float
)
392 :numerical-aperture numerical-aperture
393 :immersion-index immersion-index
)
396 (a (energy-density-cyl nu nv
(/ u nu
) (/ v nv
)))
399 (destructuring-bind (uu vv
)
404 (format t
"~2d" (truncate (* scale
(aref a u v
)))))