|
| 1 | + |
| 2 | +#TODO: Create blazed pattern for any angle and using MLSLM structure instead of an inputted phase array |
| 3 | + |
| 4 | + |
| 5 | +function genblazed!(slm::MLSLM, is_vert::Bool=true, period::Int=32; blaze_start::Int=1, blaze_end::Int=-1) #Units are pixels |
| 6 | + #Create array of size of SLM |
| 7 | + width = slm.width |
| 8 | + height = slm.height |
| 9 | + |
| 10 | + #Create array of size of SLM |
| 11 | + phase_pattern = zeros(Float64, width, height) |
| 12 | + |
| 13 | + if period == 1 |
| 14 | + blaze_values = zeros(2) |
| 15 | + else |
| 16 | + blaze_values = LinRange(1, 0, period) #creates a range from 0 to 1 with the period specified |
| 17 | + end |
| 18 | + |
| 19 | + if is_vert |
| 20 | + pattern_start::Int = (blaze_start) |
| 21 | + |
| 22 | + if blaze_end < 0. || (blaze_end) > height |
| 23 | + blaze_end = height |
| 24 | + else |
| 25 | + pattern_end::Int = (blaze_end) |
| 26 | + end |
| 27 | + |
| 28 | + for j in pattern_start:pattern_end |
| 29 | + phase_pattern[:, j] .= blaze_values[(j-1)%period+1] |
| 30 | + end |
| 31 | + else |
| 32 | + pattern_start = (blaze_start) |
| 33 | + |
| 34 | + if blaze_end < 0. || (blaze_end) > width |
| 35 | + blaze_end = width |
| 36 | + else |
| 37 | + pattern_end = (blaze_end) |
| 38 | + end |
| 39 | + |
| 40 | + for i in pattern_start:pattern_end |
| 41 | + phase_pattern[i, :] .= blaze_values[(i-1)%period+1] |
| 42 | + end |
| 43 | + end |
| 44 | + slm.phase = phase_pattern |
| 45 | +end |
| 46 | + |
| 47 | +function genzernike!(slm::MLSLM, radial_order::Int, coefficients::Vector{Float64}, radius::Int, x_center::Int, y_center::Int) |
| 48 | + phase_array = zeros(Float64, slm.width, slm.height) |
| 49 | + |
| 50 | + x_zernike = LinRange(-1,1, radius*2) |
| 51 | + y_zernike = LinRange(-1,1, radius*2) |
| 52 | + |
| 53 | + zernike_array = [(x^2 + y^2 > 1 ? 0.0 : (zernike_sum(x, y, radial_order, coefficients))) for x in x_zernike, y in y_zernike] |
| 54 | + |
| 55 | + reverse!(zernike_array, dims=2) #Reverses along the x axis, so the pattern is drawn correctly on the SLM |
| 56 | + |
| 57 | + zernike_array = zernike_array .% 2pi #Ranges from -2pi to 2pi |
| 58 | + |
| 59 | + for j in 1:size(zernike_array)[2] #Converts negative phase to positive phase |
| 60 | + for i in 1:size(zernike_array)[1] |
| 61 | + if zernike_array[i, j] < 0 |
| 62 | + zernike_array[i, j] = 2pi + zernike_array[i, j] |
| 63 | + end |
| 64 | + end |
| 65 | + end |
| 66 | + |
| 67 | + zernike_array = zernike_array ./ 2pi |
| 68 | + #TODO: Handle if radius is too large, only draw area that is on SLM |
| 69 | + if x_center - radius < 1 || x_center + radius - 1 > slm.width || y_center - radius < 1 || y_center + radius - 1 > slm.height |
| 70 | + |
| 71 | + if x_center-radius < 1 |
| 72 | + slm_x_start = 1 |
| 73 | + zernike_x_start = 2 + radius-x_center |
| 74 | + else |
| 75 | + slm_x_start = x_center-radius |
| 76 | + zernike_x_start = 1 |
| 77 | + end |
| 78 | + |
| 79 | + if x_center + radius - 1 > slm.width |
| 80 | + slm_x_end = slm.width |
| 81 | + zernike_x_end = radius * 2 + (slm.width - (x_center + radius - 1)) |
| 82 | + else |
| 83 | + slm_x_end = x_center + radius - 1 |
| 84 | + zernike_x_end = radius*2 |
| 85 | + end |
| 86 | + |
| 87 | + if y_center-radius < 1 |
| 88 | + slm_y_start = 1 |
| 89 | + zernike_y_start = 2 + radius-y_center |
| 90 | + else |
| 91 | + slm_y_start = y_center-radius |
| 92 | + zernike_y_start = 1 |
| 93 | + end |
| 94 | + |
| 95 | + if y_center + radius - 1 > slm.height |
| 96 | + slm_y_end = slm.height |
| 97 | + zernike_y_end = radius * 2 + (slm.height - (y_center + radius - 1)) |
| 98 | + else |
| 99 | + slm_y_end = y_center + radius - 1 |
| 100 | + zernike_y_end = radius*2 |
| 101 | + end |
| 102 | + |
| 103 | + println( slm_x_start, " ", slm_x_end) |
| 104 | + println( slm_y_start, " ",slm_y_end) |
| 105 | + println( zernike_x_start, " ", zernike_x_end) |
| 106 | + println( zernike_y_start, " ",zernike_y_end) |
| 107 | + |
| 108 | + phase_array[slm_x_start:slm_x_end, slm_y_start:slm_y_end] = zernike_array[zernike_x_start:zernike_x_end, zernike_y_start:zernike_y_end] |
| 109 | + else |
| 110 | + phase_array[x_center-radius:x_center+radius-1, y_center-radius:y_center+radius-1] = zernike_array[:,:] |
| 111 | + end |
| 112 | + slm.phase = phase_array |
| 113 | +end |
| 114 | + |
| 115 | + |
| 116 | +#= |
| 117 | +This function will use the reccurence reltaions defined in "Efficient and robust recurrence relations for the Zernike circle polynomials and their derivatives in Cartesian coordinates" |
| 118 | +It will return an array of values corresponding to the values of a specified number of zernike polynomials. |
| 119 | +These are in the order of OSA Zernike polynomials |
| 120 | +=# |
| 121 | + function zernike_recurs(x, y, order::Int) |
| 122 | + number_functions::Int = ((order + 1) * (order + 2)) / 2 |
| 123 | + zern_polys = Array{Float64,1}(undef, number_functions) |
| 124 | + #Value of x and y lies inside unit disk |
| 125 | + zern_polys[1] = 1 |
| 126 | + zern_polys[2] = y |
| 127 | + zern_polys[3] = x |
| 128 | + |
| 129 | + if order > 1 |
| 130 | + #values useful for indexing |
| 131 | + cur_indx = 4 #Index in array |
| 132 | + ps_indx = 2 #Index for for first polynomial of previous radial power (n-1) |
| 133 | + tps_indx = 1 #Index for for first polynomial of second revious radial power (n-2) |
| 134 | + for n = 2:order #Note: values of n = 0 and n=1 are given, the rest are calculated using the formulas in the paper |
| 135 | + for m = 0:n |
| 136 | + if m == 0 |
| 137 | + zern_polys[cur_indx] = x * zern_polys[ps_indx+(0)] + y * zern_polys[ps_indx+(n-1)] |
| 138 | + elseif m == n |
| 139 | + zern_polys[cur_indx] = x * zern_polys[ps_indx+(n-1)] - y * zern_polys[ps_indx+(0)] |
| 140 | + elseif m == n / 2 |
| 141 | + zern_polys[cur_indx] = 2 * x * zern_polys[ps_indx+(m)] + 2 * y * zern_polys[ps_indx+(m-1)] - zern_polys[tps_indx+(m-1)] |
| 142 | + elseif m == (n - 1) / 2 |
| 143 | + zern_polys[cur_indx] = y * zern_polys[ps_indx+(n-1-m)] + x * zern_polys[ps_indx+(m-1)] - y * zern_polys[ps_indx+(n-m)] - zern_polys[tps_indx+(m-1)] |
| 144 | + elseif m == ((n - 1) / 2) + 1 |
| 145 | + zern_polys[cur_indx] = x * zern_polys[ps_indx+(m)] + y * zern_polys[ps_indx+(n-1-m)] + x * zern_polys[ps_indx+(m-1)] - zern_polys[tps_indx+(m-1)] |
| 146 | + else |
| 147 | + zern_polys[cur_indx] = x * zern_polys[ps_indx+(m)] + y * zern_polys[ps_indx+(n-1-m)] + x * zern_polys[ps_indx+(m-1)] - y * zern_polys[ps_indx+(n-m)] - zern_polys[tps_indx+(m-1)] |
| 148 | + end |
| 149 | + cur_indx += 1 |
| 150 | + end |
| 151 | + tps_indx += n - 1 |
| 152 | + ps_indx += n |
| 153 | + end |
| 154 | + end |
| 155 | + return zern_polys |
| 156 | +end |
| 157 | + |
| 158 | +#= |
| 159 | +Given an order of zernike polynomials, calculate an array containing their normalization coefficients |
| 160 | +=# |
| 161 | +function zernike_norm(order) |
| 162 | + #we will use the equation described in the paper to calculate the normalization coefficients |
| 163 | + number_functions::Int = ((order + 1) * (order + 2)) / 2 |
| 164 | + norm_coef = Array{Float64,1}(undef, number_functions) |
| 165 | + index = 1 |
| 166 | + for n = 0:order |
| 167 | + for m = 0:n |
| 168 | + if n == 2m |
| 169 | + norm_coef[index] = sqrt(n + 1) |
| 170 | + else |
| 171 | + norm_coef[index] = sqrt((2)(n + 1)) |
| 172 | + end |
| 173 | + index += 1 |
| 174 | + end |
| 175 | + end |
| 176 | + return norm_coef |
| 177 | +end |
| 178 | + |
| 179 | +#= |
| 180 | +Sums the value of each zernike polynomial multiplied by their respecitve normilaztion coefficient and weight |
| 181 | +=# |
| 182 | +function zernike_sum(x, y, order, weights::Vector{Float64}) |
| 183 | + return sum(zernike_recurs(x, y, order) .* zernike_norm(order) .* weights) |
| 184 | +end |
0 commit comments