window-integrated low concentration planar light guide solar concentrators by daniel james
TRANSCRIPT
Window-Integrated Low Concentration Planar Light Guide Solar Concentrators
by
Daniel James Lawler Williams
Submitted in Partial Fulfillment of the
Requirements for the Degree
Doctor of Philosophy
Supervised by Professor Duncan T. Moore
The Institute of Optics
Arts, Sciences and Engineering
Edmund A. Hajim School of Engineering and Applied Sciences
University of Rochester
Rochester, NY
2016
ii
Biographical Sketch
Daniel Williams was born in Newark, Delaware. He attended the University of Nebraska –
Lincoln and graduated with distinction, receiving a Bachelor of Science degree in both Physics
and Mathematics. He was awarded the Summer Undergraduate Research Fellowship by the
National Institute of Standards and Technology in 2006. He continued his education at The
Institute of Optics, University of Rochester. During graduate studies he was awarded the
Integrative Graduate Education and Research Traineeship by the National Science Foundation in
2010. He received a Master of Technical Entrepreneurship and Management degree, a joint
degree of the Simon School of Business and Hajim School of Engineering and Applied Science in
2012 and a Master of Science degree in Optics from The Institute of Optics in 2014. He pursued
his research in Optics under the direction of Professor Duncan T. Moore.
The following publications were a result of the work conducted during this doctoral study:
Yang Zhao, Daniel J. L. Williams, Peter McCarthy, et al., "Chromatic correction for a VIS-SWIR zoom lens using optical glasses", Proceedings of SPIE Vol. 9580, 95800E (2015)
Anthony J. Yee, Daniel J. L. Williams, Gustavo A. Gandara-Montano, et al., "New tools for finding first-order zoom lens solutions and the analysis of zoom lenses during the design process", Proceedings of SPIE Vol. 9580, 958006 (2015)
Peter McCarthy, Rebecca Berman, Daniel J. L. Williams, et al., "Optical design study in the 1-5μm spectral band with gradient-index materials", Proceedings of SPIE Vol. 9293, 92930X (2015)
Berman, Rebecca, et al. "Optical design study of a VIS-SWIR 3X zoom lens." SPIE Optical Engineering+ Applications. International Society for Optics and Photonics, 2015.
iii
Acknowledgements
I would like to thank my advisor, Duncan Moore, for his academic guidance and
foresight in preparing me for post-graduate life.
I would like to thank Blair Unger, Eric Christensen, and Mick Brown for their
indispensable mentorship and their work in the Moore group that made my research possible.
I would like to thank Greg Schmidt for his selflessness and absolute willingness to help
his colleagues and share his broad range of knowledge.
I would like to thank my colleagues, Rebecca Berman, Anthony Yee, and Yang Zhao for
making our office a great and friendly place to work.
I would like to thank Per Adamson for his help on numerous occasions and his incredible
drive to help the students of The Institute of Optics.
I would like to thank Lynn Doescher and Evelyn Sheffer for their support of the Moore
group and for bringing a caring atmosphere to our offices.
I would like to thank my parents, John and Kathleen, for their consistent support and
interest in my work both during and prior to my graduate studies.
I would like to thank my parents-in-law for supporting me and my wife and welcoming
me into their family.
I would like to thank my friends, especially Zack Lapin, Richard Smith, Nicole Kendrot,
and Greg Schmidt for making life outside of research so much more enjoyable.
Finally, I would like to thank my amazing wife and best friend, Jennifer Muniak, for her
incredible support and encouragement during my graduate studies, and for bringing our
wonderful daughter, Penelope, into this world.
iv
Abstract
Several novel low concentration solar concentrator photovoltaic designs are presented,
based on the planar light guide architecture pioneered by the University of Rochester. These
systems are designed for integration into windows, requiring them to be stationary and to have
a large acceptance angle since they cannot move to track the sun. The application goal is to use
solar generated electricity to offset the energy lost through the window during cold times of the
year. The systems are evaluated for their effective insulation properties given the calculated net
energy lost. Without moving parts, they optimize to have acceptance angles of about 20° to 35°
in the vertical direction and ±90° in the horizontal direction, but have peak optical efficiencies of
less than 50%. By including internally moving parts, the acceptance angle is increased to nearly
a full π steradians (the full sky from the point of view of the window) and the average optical
efficiency increases to over 50%. Systems in certain locations are not viable due to low solar
irradiance in the wintertime, e.g., Rochester, NY. Others, however, reduce net energy loss to
zero for much of the year. A prototype of one of the systems is fabricated, measured, and
modeled. The simulated and measured performance data are compared and are in close
agreement, validating the model and the evaluation methods used during system optimization.
v
Contributors and Funding Sources
This work was supervised by a dissertation committee consisting of Professors Duncan
Moore, James Zavislan, and Julie Bentley of the Institute of Optics and Matthew Yates of the
Chemical Engineering Department at the University of Rochester. The initial design work was
funded by Rambus International Ltd. under Award Number – 056105-002. Additional funding
was provided by the National Science Foundation under the Integrative Graduate Education
Research and Traineeship (IGERT) program and L-3 Communications.
vi
Table of Contents
Biographical Sketch ......................................................................................................................................... ii
Acknowledgements ........................................................................................................................................ iii
Abstract .......................................................................................................................................................... iv
Contributors and Funding Sources .................................................................................................................. v
List of Tables ................................................................................................................................................. viii
List of Figures .................................................................................................................................................. ix
Chapter 1: Background ................................................................................................................................ 1
1.1 Solar Power ...................................................................................................................... 1
1.2 Concentrating Photovoltaics (CPV) .................................................................................. 2
1.3 Concentrator Design Theory .......................................................................................... 13
1.4 Low Concentration Photovoltaics .................................................................................. 18
1.5 Examples of Existing Low Concentration Systems ......................................................... 24
1.6 Examples of Non-Concentrating BIPV ............................................................................ 29
1.7 Window Integrated LCPV Planar Light Guide Solar Concentrators ................................ 30
Chapter 2: Design ...................................................................................................................................... 31
2.1 Application ..................................................................................................................... 31
2.2 The Louver Concept ....................................................................................................... 35
2.3 Optimization and Results ............................................................................................... 39
2.4 Analysis .......................................................................................................................... 49
2.5 Conclusion ...................................................................................................................... 63
Chapter 3: Prototype and Metrology ........................................................................................................ 65
3.1 Prototype ....................................................................................................................... 65
vii
3.2 Fabrication Methods ...................................................................................................... 69
3.3 Metrology Tools ............................................................................................................. 80
Chapter 4: Measurements and Computer Model ................................................................................... 100
4.1 Component Measurements ......................................................................................... 100
4.2 Performance ................................................................................................................ 121
4.3 Conclusion .................................................................................................................... 137
Chapter 5: Conclusion ............................................................................................................................. 138
5.1 Summary ...................................................................................................................... 138
5.2 Future Work ................................................................................................................. 139
References ................................................................................................................................................... 141
Appendix A. Design Specifications ......................................................................................................... 148
Appendix B. Deflectometer MATLAB Code ........................................................................................... 156
Appendix C. Optimization Routine MATLAB Code ................................................................................ 261
viii
List of Tables
Table 2-1: Thermal conductivities for various materials [26]. ...................................................................... 54
Table 2-2: Vertical angle field of view summary. The left data column indicates the vertical angle field of
view range for each design, the center column shows the average optical efficiency over that range,
and the right column gives the peak optical efficiency. ...................................................................... 63
Table 4-1: Guide layer designed vs. measured dimensions. ...................................................................... 100
Table 4-2: Injection prism designed vs. measured dimensions. ................................................................. 106
Table 4-3: Light I-V curve parameters for both PV cells. ............................................................................ 121
Table 4-4: Summary of simulated manufacturing flaws. The flaws are added to the model in the order
shown. ............................................................................................................................................... 124
ix
List of Figures
Figure 1.1: Residential silicon flat panel PV solar installation (top) and the Solucar PS10 solar thermal
power plant near Seville, Spain (bottom, [55], originally posted to Flickr by afloresm at
http://flickr.com/photos/74424373@N00/1448540890). .................................................................... 1
Figure 1.2: Fresnel lens based CPV array on a large tracking mechanism. "Amonix7700" by Mbudzi - Own
work - https://commons.wikimedia.org/wiki/File:Amonix7700.jpg#/media/File:Amonix7700.jpg. .... 2
Figure 1.3: Spectral response of a silicon solar cell. Efficiency on the vertical axis is in units of current (A)
output per light power (W) input. The red curve is an ideal cell considering only the band
gap/photon energy differential and the blue is a measured real-world cell. [5] .................................. 5
Figure 1.4: Example IV curves. The orange curve is measured data from a silicon PV cell, and the blue is
derived from the diode law with I0 and IL adjusted to match the measured data. The areas above the
dashed lines indicate the peak power output for each curve. The fill factors for the measured and
ideal curves are 0.52 and 0.82, respectively. ......................................................................................... 7
Figure 1.5: Electrical grid demand during a hot day in California [57]. .......................................................... 9
Figure 1.6: Fresnel lens CPV system diagram with secondary concentrator. Image source: Light
Prescriptions Innovators, [59]. ............................................................................................................. 11
Figure 1.7: Planar light guide CPV form factor. Sunlight enters the large face and is guided toward one
edge (in red) where the PV chip is placed. .......................................................................................... 12
Figure 1.8: Refractive planar light guide CPV components. ......................................................................... 12
Figure 1.9: Schematic of polar plane orientation with respect to the earth (blue) and the sun on the
equinox at solar noon (yellow). ........................................................................................................... 18
Figure 1.10: Recreated from Figure 2 of ref [15]. The bold black circle is the unit circle, the green lines
represent the sun’s position throughout the day of the winter (left) and summer (right) solstices, the
x
solid vertical lines represent the sun’s path for the first day of each month from Jan 1 to June 1 from
left to right, and the dashed lines do the same for July 1 to Dec 1 from right to left, and the blue
ellipse represents the eight hours per day boundary. ......................................................................... 19
Figure 1.11: Compound parabolic concentrator profile illustrating the edge ray principle. The blue rays
come from the edge of the source and focus to a point on the edge of the dark red target surface.
The red rays come from inside the edges of the source. .................................................................... 22
Figure 1.12: Direction cosine representation of the sun's position for eight hours per day, year round (grey
shaded area) and the fields of view of trough CPCs with an index of 1 (red ellipse) and 1.5 (blue
ellipse) that are just wide enough to capture sunlight for eight hours every day without tracking. .. 23
Figure 1.13: tenKsolar's RAIS™ PV system. The deep blue colored rows are silicon solar panels and the
translucent plates are cold mirrors that concentrate convertible sunlight onto the PV cells. [16] .... 25
Figure 1.14: See-through window CPV system schematic (top) and picture of prototype (bottom, [17]). . 26
Figure 1.15: Reproduced rendering of Stellaris' window CPV module showing extruded CPC troughs [18].
............................................................................................................................................................. 26
Figure 1.16: Reproduction from [21]. A schematic for a LSC showing the incoming sunlight, a luminescent
particle (orange circle), and re-emitted light that is lost (1) and trapped in the light guide (2). ......... 27
Figure 1.17: Luminescent concentrator plates. Image courtesy Fraunhofer ISE. ........................................ 28
Figure 1.18: Prism solar BIPV modules integrated into balcony railings [22]. .............................................. 29
Figure 2.1: LCPV field of view coordinate system definition. ....................................................................... 33
Figure 2.2: Map of sun's position in azimuth and elevation for Rochester, NY (latitude = 43.12°). Yellow
dots indicate sun position at various times. The black dashed lines indicate constant vertical angle.
............................................................................................................................................................. 33
Figure 2.3: Weighting functions for three cities in the U.S. ......................................................................... 34
Figure 2.4: Shadowing advantage of the louver design space, where part of the louver (a) is designed for
greater vertical angles and other parts (b) are optimized for lesser ones. ......................................... 36
xi
Figure 2.5: Illustration of a full window LCPV system consisting of several modules stacked top to bottom.
............................................................................................................................................................. 37
Figure 2.6: Cross-section view of a suspended louver design. The horizontal grey lines on the injection
features indicate a reflective surface. ................................................................................................. 37
Figure 2.7: Cross-section of an immersed louver design. ............................................................................. 38
Figure 2.8: Cross-section of an extruded segment lens design. Grey lines indicate mirrored surfaces. ..... 39
Figure 2.9: Optimization variables for suspended (and immersed) louver designs indicated in red. .......... 41
Figure 2.10: Solutions from the suspended louver optimization for the three chosen locations. Geometry
of the reflectors and injection features are displayed across the top, and the efficiency as a function
of vertical angle is shown below. ......................................................................................................... 42
Figure 2.11: Solutions from the immersed louver optimization for the three chosen locations. Geometry
of the reflectors and injection features are displayed across the top, and the efficiency as a function
of vertical angle is shown below. ......................................................................................................... 43
Figure 2.12: Optimization variables for extruded segment lens design indicated in red lettering. Traced
rays show the additional angled fold mirror in the ESL design (ray colors indicate angle after injection
into the guide layer)............................................................................................................................. 44
Figure 2.13: Solutions from the extruded segment lens optimization for the three chosen locations.
Geometry of the reflectors and injection features are displayed across the top, and the efficiency as
a function of vertical angle is shown below. ....................................................................................... 45
Figure 2.14: Tracking louver optimization variables shown in red. .............................................................. 47
Figure 2.15: Solutions from the tracking louver optimization for the three chosen locations. Geometry of
the reflector and injection features for the Rochester design are displayed at the top for several
vertical angles, and the efficiency as a function of vertical angle is shown below for all three cities. 48
Figure 2.16: Suspended louver Rochester design performance showing injection efficiency and weighting
function. ............................................................................................................................................... 49
xii
Figure 2.17: Rochester suspended louver design normalized efficiency components as a function of
position on the system's front aperture. The total is the sum of the top and bottom cells, while the
average is the mean of the total over all positions. ............................................................................ 50
Figure 2.18: Rochester SL design average efficiency and effective concentration as a function of guide
length, both normalized at the designed guide length of 300 mm. .................................................... 51
Figure 2.19: Effective U-factor calculations for the SL Rochester design. The bold blue line represents a
sunny year and the thin green line is from “typical meteorological year” data. The red line of the U-
factor plot represents the passive U-factor of the window. ................................................................ 54
Figure 2.20: Effective U-factor calculations for the SL Rochester design. Battery storage is included and its
charge level is shown in the bottom plot. ........................................................................................... 55
Figure 2.21: Effective U-factor calculations for the immersed louver (IL) El Paso design including battery
storage. ................................................................................................................................................ 57
Figure 2.22: Effective U-factor calculations for the tracking louver Fairbanks design including battery
storage. ................................................................................................................................................ 58
Figure 2.23: Effect of backside retroreflective texture on static louver designs: rejecting direct sunlight
during summer. Left image shows high vertical angle rays striking back of louver and continuing
through the window. Right image shows rays being turned back by a retroreflective texture on the
adjacent louver rear surface. ............................................................................................................... 59
Figure 2.24: Photorealistic renderings of views through the three static designs: SL (top), IL (middle), and
ESL (bottom). ....................................................................................................................................... 61
Figure 2.25: Schematic of building with passive solar heating. Shows absorbing indoor surfaces, thermal
mass storage, and shading control eve. .............................................................................................. 62
Figure 3.1: Dimensioned cross section of prototype design (lengths in mm). Shows nomenclature for faces
of prism and guide. The dashed red line shows that the prism has minimal interference with light
xiii
that moves past the baffle and is headed for reflector. The blue dotted lines show that the prism
back can be extended without obscuring the intended optical path through the device. .................. 66
Figure 3.2: Tolerance study on prototype prism dimensions. Solid blue line shows designed shape, dashed
black lines show envelope of the tolerance study which is achieved by varying α, β, and the lengths
of the front and back edges. ................................................................................................................ 68
Figure 3.3: Error envelope of tolerance study. The blue line shows the performance of the as-designed
prototype, the orange line shows the minimum performance from the compound geometry errors,
while the grey line shows the maximum. ............................................................................................ 69
Figure 3.4: Cross-section of prism shape modified for the milling fabrication process. The red dashed line
indicates the unmodified shape. ......................................................................................................... 71
Figure 3.5: Modeled (top) and 3D printed (bottom) reflector with reflective Mylar film adhered to surface.
Printed part is a first full scale manufacturing attempt with visible flaws in the surface. .................. 72
Figure 3.6: Mylar adhesive trial. "SC" and "LT" represent glues that harden as they set, and cause the
Mylar to become diffuse as a result. "RC" (rubber cement) and "GE" (silicone sealant) both stay
somewhat flexible as they set, allowing the Mylar surfaces to remain smooth. ................................ 73
Figure 3.7: 3D printed reflector structure secured to an optical bench (top), and a roller with Mylar sheet
and protective paper layer (bottom). .................................................................................................. 74
Figure 3.8: A silicon wafer with conductive gridlines. Red box indicates ideal dicing lines and the green,
the necessary dicing lines due to the crystal lattice orientation. Dashed lines indicate extra diced cell
area that does not contact the guide layer edge in the prototype assembly, leaving room for solder
connections.......................................................................................................................................... 75
Figure 3.9: Exploded view of prototype assembly with (a) prism and guide in green, (b) reflector in grey,
(c) baffle in black, (d) structural braces in brown, (e) PV cell clamp components in yellow, (f) wire
management hanger in black, and (g) and (h) indicating the top and bottom PV cell locations,
respectively. ......................................................................................................................................... 78
xiv
Figure 3.10: PV cell optical contact trial (top) and in the prototype looking through the length of the guide
layer (bottom). Top: the darker regions of the cell are area of good optical contact with the PMMA
cover plate and the lighter areas have poor contact. Bottom: good optical contact in the prototype
assembly. ............................................................................................................................................. 79
Figure 3.11: Magnified view of PV cell surface showing a ridged texture running perpendicular to the small
gridlines. .............................................................................................................................................. 79
Figure 3.12: Deflectometer reference flat mirror. ....................................................................................... 84
Figure 3.13: Fringe Reflection deflectometer schematic showing relative positions of the monitor display,
camera, and reflective part. ................................................................................................................ 84
Figure 3.14: Camera response to monitor input values for several viewing angles using default display
settings. ............................................................................................................................................... 86
Figure 3.15: Camera and monitor response curves with modifications (top), and the calculated phase error
based on the nonlinear response (bottom). The phase error is based on a four step phase shifting
algorithm and the shaded region estimate the error based on the noise in the measured data. ...... 88
Figure 3.16: Deflectometer calibration during monitor reflection positioning step. Shows (a) drawn
fiducials on monitor, (b) reflection of drawn white fiducials and black mirror fiducials on calibration
flat, and (c) camera. ............................................................................................................................. 90
Figure 3.17: Reflection of horizontal fringes from prototype reflector as recorded by camera. From phase
shift of the fringes from left to right is 0, π/2, π, and 3π/2. ................................................................ 91
Figure 3.18: Pixel line data for the calculation of absolute position. Horizontal (left) and vertical (right)
lines are shown. These images are superimposed with another photo of the part so the part outline
is visible. ............................................................................................................................................... 92
Figure 3.19: Results of PUMA phase unwrapping algorithm performed on the horizontal fringe data for
prototype reflector. Wrapped phase [-π, π] (left) and unwrapped phase (right). ............................. 93
xv
Figure 3.20: Illustration of multiple solutions to surface position problem. The solid red line is the known
ray coming from the camera, the green patches are possible surface positions with the black arrows
indicating the surface normals. ........................................................................................................... 94
Figure 3.21: Illustration of two different slope calculations. S1 and S2 are the slopes calculated from the
monitor position reflected in the part, and S12 is the slope calculated from the positions of the data
points. In this example, to get the average of S1 and S2 to equal S12, σ2 will need to increase relative
to σ1. .................................................................................................................................................... 95
Figure 3.22: Calibration flat measured in a Zygo laser interferometer. A cylindrical bend can be seen over
the aperture of the part with a peak to valley departure of about 1 µm. The bottom graph shows the
slice chart indicated by the line in the top graph. ............................................................................... 97
Figure 3.23: Comparison of the spectral power distribution of sunlight after passing through Earth's
atmosphere and a xenon arc lamp. ..................................................................................................... 98
Figure 3.24: Schematic of solar simulator with labeled components. Path of light though system shown in
yellow. .................................................................................................................................................. 98
Figure 4.1: Laser interferometer data of the guide front face. Dark blue indicates invalid data. ............. 101
Figure 4.2: Guide layer immersed in bed of corn syrup to suppress back surface reflection. ................... 102
Figure 4.3: Top: Deflectometer data from guide layer front surface. Bottom: magnified region as marked
in top graphic with surface figure subtracted out. A scratch and tool marks become visible. Vertical
and horizontal slice charts shown, all units are mm. ......................................................................... 103
Figure 4.4: Portion of guide front surface from the raw deflectometer data. Scratch and tool marks are
visible. ................................................................................................................................................ 104
Figure 4.5: Zygo laser interferometer data of the injection prism back surface. ....................................... 107
Figure 4.6: Representation of prism front surface slope in the (top) horizontal and (bottom) vertical
directions. .......................................................................................................................................... 108
xvi
Figure 4.7: White light interferometer data of prism top tool marks. Top graph shows registered data sets
and position of slice, bottom shows surface height values along the slice (blue line) and the
smoothed data (red line). .................................................................................................................. 109
Figure 4.8: Deflectometer data of prism top near corner showing tool marks. All dimensions are in mm.
........................................................................................................................................................... 110
Figure 4.9: Looking through the prism at the back surface mirror. ............................................................ 110
Figure 4.10: Schematic of prism mirror reflectance measurement. “Fresnel Reflection” and “Output” rays
measured with power meters. .......................................................................................................... 111
Figure 4.11: Reflectance data from the prism mirror as a function of position in the extrusion direction.
The blue line is the calculated reflectance with grey error bars and the orange is the stepped
function used in the prototype model. .............................................................................................. 112
Figure 4.12: Geometry of the modeled reflectivity zones for the prism mirror. Blue regions are uncoated,
and the remaining regions have uniform reflectances as indicated. ................................................. 113
Figure 4.13: Reflector surface shape measured via CMM (top) before Mylar film is applied and via the
deflectometer (middle) with the Mylar film in place. Error values are mm of departure from the
designed shape. The bottom image shows difference of the two data sets. ................................... 114
Figure 4.14: Principal curvature analysis of reflector surface as measured by the deflectometer. ........... 116
Figure 4.15: Stock Mylar film showing wavy topology. .............................................................................. 116
Figure 4.16: Magnified reflector surface data with the principal curvature, k2, on the left and a set of raw
vertical fringe data on the right. ........................................................................................................ 117
Figure 4.17: White light interferogram of the reflector's Mylar surface. A 2nd order 2D polynomial is
removed to reveal surface roughness features. ................................................................................ 117
Figure 4.18: Schematic of PV cell slit scan experiment. ............................................................................. 118
Figure 4.19: PV chip geometry data and results. Photograph of back of PV cell over ruled background
(top), photograph of front of cell (middle), and generated binary apodization mask (bottom). ...... 118
xvii
Figure 4.20: Measured and modeled efficiency profiles for prototype photovoltaic cells. ....................... 119
Figure 4.21: Dark I-V curves of prototype PV cells before and after assembly. ......................................... 120
Figure 4.22: Light I-V curve of each PV cell before assembly. .................................................................... 121
Figure 4.23: Performance measurement schematic of the prototype system. Shows the three positional
variables in the system. The Vertical Angle axis of rotation remains constant with respect to the
prototype structure. .......................................................................................................................... 122
Figure 4.24: Slit scan simulation data for ideal model (red), added prism dimensions flaw (green), then
added reflector shape flaw (blue). Simulation is performed with wide source to average out
translational variations in the measured reflector shape. Vertical axis is in relative units and are
equivalent for all three plots. ............................................................................................................ 125
Figure 4.25: Raytraces of the "Reflector Shape" model at three different vertical angles as indicated.
There are peaks in the top cell output at 24° and 34° with a valley in between. .............................. 126
Figure 4.26: Results of Field of View (FoV) simulation for ideal prototype model. .................................... 127
Figure 4.27: Results of slit scan simulations for a 4.88 mm wide slit fixed at the translational origin. The
reflector shape data set includes the prism dimensions flaw. The remaining data sets are for and
added back prism fillet then front fillet. ............................................................................................ 128
Figure 4.28: Effect of front fillet on bottom cell output near 30° vertical angle and 9 mm translational
position. ............................................................................................................................................. 129
Figure 4.29: Slit Scan simulation results for final three modeled manufacturing flaws. Scales are constant
with each row to show attenuation effects of each flaw. ................................................................. 130
Figure 4.30: Field of View (FoV) simulation results for final three modeled manufacturing flaws. Scales are
constant across each row to show attenuation effects of each flaw. ............................................... 132
Figure 4.31: Slit scan performance comparison. Measured results in the left column, simulated results in
the right column. Scale is consistent across each row. ..................................................................... 133
xviii
Figure 4.32: Field of view performance comparison. Measured results in the left column, simulated
results in the right column. Scale is consistent across each row. ..................................................... 134
Figure 4.33: Photo peering through back face of guide layer at the bottom of the reflector structure. Resin
from the bottom cell seeping into the gap between the reflector and guide appears as irregularly
shaped darker regions. ...................................................................................................................... 135
Figure 4.34: Simulation of final prototype model at a vertical angle of 47° showing many rays interacting
with the area containing the unwanted resin. .................................................................................. 136
Figure B.1: Shows vertical and horizontal wrapped phase data and asks user to outline part leaving a
buffer of background pixels. .............................................................................................................. 167
Figure B.2: PUMA algorithm unwraps data within region of interest. ....................................................... 168
Figure B.3: Results of noise amplitude analysis. ......................................................................................... 169
Figure B.4: Histogram of noise amplitudes. Red line shows cutoff amplitude for what is considered noise.
........................................................................................................................................................... 169
Figure B.5: Left column: noisy data deleted. Right column: noise mask edges smoothed and rouge data
pixels mended. ................................................................................................................................... 170
Figure B.6: Calculated X and Y positions on the monitor. Shading relates loosely to surface slope in each
direction. ............................................................................................................................................ 171
Figure B.7: Sample points from ideal surface shape are overlayed over data from the deflectometer
camera. The green and cyan dots on the edge denote the surface points used as fiducial lines
pertaining to the part edges. If a caliper tip fiducial is used, the user must pick the location of the
caliper tips in the image instead. ....................................................................................................... 173
Figure B.8: Optimization iterations to find calculated XYZ points of the part surface. The value is the
average distance from the camera origin. In this case, the initial guess is rather accurate. ............ 174
Figure B.9: Initial guess vs. optimization solution. ..................................................................................... 175
Figure B.10: XYZ data for calculated surface. ............................................................................................. 175
xix
Figure B.11: Principal curvature maps of calculated data. Principal curvature k1 (left), principal curvature
k2 (center), Gaussian curvature (right). ............................................................................................. 176
Figure B.12: Registered data showing error from ideal surface. ................................................................ 177
1
Chapter 1: Background
1.1 Solar Power
The recent push for alternative energy solutions stems from the multifaceted problem
caused by the overuse of fossil fuels in the U.S. and worldwide. The current U.S. federal
government administration supports the move towards alternative energy production and
energy efficiency as a way of “building a new, clean energy economy, ending our dependence on
foreign oil, and limiting the dangerous pollutants that threaten our health and the health of our
planet.” [1] One focus of alternative energy electricity production is solar energy.
By far, the most common method of converting solar radiation into electricity is through
the use of large areas of silicon photovoltaic (PV) cells, whose prices have been falling rapidly
since 2009. While utility companies have been harvesting more solar energy in the past several
years, the majority of the explosive growth in
U.S. solar energy production has come from
the residential and commercial sectors [2],
both of which primarily utilize silicon PV cells.
The next most common form of solar
energy harvesting is via solar thermal
systems [2]. For residential applications,
these are usually water heating systems
which avoid converting the energy into
electricity. At a utility scale, electricity is
produced by focusing sunlight using
thousands of movable mirrors to heat a fluid,
Figure 1.1: Residential silicon flat panel PV solar installation (top) and the Solucar PS10 solar thermal power plant near Seville, Spain (bottom, [55], originally posted to Flickr by afloresm at http://flickr.com/photos/74424373@N00/1448540890).
2
often molten salt, and using it to run steam turbines and create electricity. These systems come
in the form of “solar power towers” or parabolic trough concentrators and are only effective on
a large scale, thus not suitable for residential and commercial applications. Finally, a still
emerging technology uses PV cells for conversion to electricity, but unlike traditional silicon
panels, optical components are used to concentrate the sunlight onto a small area of PV cells.
This concept is known as concentrating photovoltaics (CPV).
1.2 Concentrating Photovoltaics (CPV)
The purpose of CPV systems is to
optically relay an area of solar flux to a
photovoltaic cell of smaller area. This
effectively replaces photovoltaic cell area with
relatively inexpensive optical materials,
potentially lowering the levelized cost of
electricity (LCOE) produced by the system,
especially when utilizing highly efficient PV cells that carry a high monetary cost per unit area.
Additionally, CPV modules often have much higher conversion efficiencies than even the best
silicon flat panel PV technologies. A more recent area of interest in CPV is for building
integrated photovoltaics (BIPV, or BICPV) where PV modules exist as part of the architecture of
buildings. CPV offers great flexibility in terms of the aesthetics of such systems.
1.2.1 Concentration Ratio
CPV systems are classified by their concentration which is the ratio of the area of the
entrance aperture of a system to the area of its target surface, i.e. the photovoltaic chip. More
Figure 1.2: Fresnel lens based CPV array on a large tracking mechanism. "Amonix7700" by Mbudzi - Own work - https://commons.wikimedia.org/wiki/File:Amonix7700.jpg#/media/File:Amonix7700.jpg.
3
specifically, this is called the geometric concentration ratio given the spatial nature of its
definition. Classifications of CPV systems vary widely and have yet to be standardized. High
concentration (HCPV) systems have been defined as those with geometric concentration ratios
that range from 300X up to 1000X or higher. Low concentration (LCPV) system concentration
classifications vary greatly: anywhere from 3X and lower [3] to 100X and lower [4]. Some even
define a medium concentration class (MCPV) that exists between LCPV and HCPV, between
100X and 300X. Even given the variation of the definitions, HCPV systems almost exclusively
employ high-efficiency, high-cost, multi-junction PV cells and two-axis tracking systems to follow
the sun as it moves across the sky. Systems meant to maximize cost effectiveness often fall into
the HCPV category in order to minimize the area of expensive photovoltaic material and
increase efficiency of energy production, making this class of CPV a favorite of utility companies
for centralized solar plants.
LCPV system designs vary widely due to the numerous and highly diverse applications.
Some LCPV is meant to replace flat plate silicon while decreasing cell area while others are more
concerned with aesthetics, like in BIPV applications. Some LCPV requires two-axis tracking much
like HCPV, while others need only on-axis tracking or none at all. The PV material for LCPV is
most often inexpensive silicon in one of its several forms (single crystal, polycrystalline, etc.)
There is no dominant technology in the LCPV space at this time given the wide array of
applications and the fact that the market is still in a very early stage.
1.2.2 Tracking
The “field of view” (FoV) or “acceptance angle” of a CPV system refers to the angular
region (relative to the optical axis) from which the system accepts incident light. Due to
4
fundamental limits on concentration ratio, high concentration systems have smaller fields of
view than lower concentration systems. A small field of view of, say, a ±1° cone requires the
module to be pointed fairly precisely at the sun in order to function properly. Since the sun
moves approximately 1° across the sky every four minutes, a mechanical tracking system is
required.
Including a tracker in a CPV system has the disadvantages of an increased cost and
increased complexity with moving parts. One advantage of the tracker besides enabling the
functioning of high concentration systems is that it can keep the projected area of the CPV
system at a maximum throughout the day, most notably in the evening during the peak
residential electricity usage. For stationary solar panels, the projected area can become very
small, especially in the mornings and evenings, so very little sunlight strikes the cells during
those times. Another concern for solar trackers is their accuracy. Due to wind loading and
other pointing errors, even the most advanced trackers on the market have an accuracy of
around ±0.5° and the sun is approximately a ±0.25° source, so a practical high concentration CPV
design must have a field of view of at least ±0.75°.
Lower concentration systems can be designed to have an oblong field of view, accepting
light from large angles in one direction, but only a small range of angles in the orthogonal
direction. Such a system has the advantage of requiring tracking along a single axis, decreasing
the mechanism’s complexity and cost while maintaining a respectable concentration ratio.
1.2.3 Photovoltaics
Clearly, a key component of any CPV device is the photovoltaic cell, which converts the
concentrated light energy into electricity.
5
1.2.3.1 Photovoltaic Effect
As the name implies, photovoltaics function on the physical principal known as the
photovoltaic effect, which is related to the famous photoelectric effect. The photovoltaic effect
describes the process of photons being absorbed by a material and forming a mobile electron-
hole pair. If the electron-hole pair is separated and extracted from the material, the consequent
voltage potential can be used to perform work. On a molecular level, the absorbed photons are
exciting bound electrons to a higher discreet energy state, and the minimum energy required to
cause that excitation is referred to as the band gap of the material. In the case of a silicon PV
device, the band gap is 1.12 electron volts, which is equivalent to the energy contained in a
photon with a wavelength of approximately 1100 nm according to the following equation:
𝜆 =ℎ𝑐
𝐸 ,
where ℎ is Plank’s constant, 𝑐 is the speed of
light in vacuum, and 𝐸 is the photon energy.
Excluding effects such as two-photon
absorption and those of indirect bandgaps,
this means that photons of lower energy than
the band gap, or longer wavelength, cannot
be converted to electron hole pairs.
Another important fact is that, under
normal conditions, absorption of one photon results in one and only one electron-hole pair. In
the scope of a PV device, this means that a photon at the band gap energy and a photon with
twice that energy produce the same useable output current. Thus, the higher energy photons
Figure 1.3: Spectral response of a silicon solar cell. Efficiency on the vertical axis is in units of current (A) output per light power (W) input. The red curve is an ideal cell considering only the band gap/photon energy differential and the blue is a measured real-world cell. [5]
0
0.2
0.4
0.6
0.8
1
0 0.4 0.8 1.2
Spe
ctra
l Re
spo
nse
(A
/W)
Wavelength (µm)
Ideal Cell
Measured Cell
6
are not converted as efficiently as the photons just above the band gap energy. Figure 1.3
shows the ideal spectral response of a silicon PV cell as well as a measured device. The short
wavelength depression of efficiency in the measured data is due to absorption of a protective
glass cover layer, and the extension of the spectral response past the band gap wavelength is
due to effects associated with the indirect band gap nature of the device [5].
Knowledge of the spectral response of PV materials is important in CPV design. If the
concentration optics change the spectral distribution of the light incident on the cell, the
electrical output can be expected to change in a way that is not linear with the total power
striking the cell. Additionally, in order to convert sunlight with maximum efficiency, it is possible
to optically split the solar spectrum onto several different PV materials with various band gap
energies so that each one receives wavelengths of light that it can convert most efficiently. This
is a concept known as spectral splitting. Multi-junction cells can be thought of as PV devices
with integrated spectral splitting since different spectral bands are absorbed by each PV
material. The most efficient concentrating systems to date use these types of cells [6].
1.2.3.2 IV Curve
Typical inorganic PV devices consist of semiconductor p-n junctions and function as
diodes with the added photovoltaic effect as described previously. As such, PV devices follow a
similar law to diodes with a forward voltage bias:
𝐼 = 𝐼0 [𝑒𝑞𝑉
𝜂𝑘𝑇 − 1] − 𝐼𝐿 ,
where 𝐼 is the net current through the diode, 𝐼0 is the dark saturation current, 𝑉 is the applied
forward bias voltage, 𝑞 is the absolute value of electron charge, 𝑘 is Boltzmann’s constant, and
𝑇 is absolute temperature in Kelvin. 𝜂 is called the ideality factor which encompasses certain
7
effects that cause real diodes to function less efficiently than the theoretical models. Finally, 𝐼𝐿
is the light generated current, a term that does not exist in the diode law [5].
An IV curve of a PV device can
be directly measured by
simultaneously applying voltage and
reading the output current. Some of
the important metrics of PV cells are
the short circuit current (𝐼𝑆𝐶), open
circuit voltage (𝑉𝑂𝐶), the fill factor
(𝐹𝐹), and the peak power (𝑃𝑃). These
values are visualized in Figure 1.4. 𝐼𝑆𝐶
is the current produced by the cell under illumination with no voltage bias. This is the quantity
measured to assess performance of prototype systems in the lab since it increases linearly with
incident power assuming the spectrum of the incident light does not change. 𝑉𝑂𝐶 is the forward
bias voltage at which the net current is zero. For high quality cells, the open circuit voltage is
nearly constant with small changes in incident power, and devices of the same PV material will
have roughly the same open circuit voltages. The peak power is the largest absolute value of
the product of the applied voltage and output current along the IV curve and represents the
maximum power that can be extracted from the cell. Finally, the fill factor is a measure of how
square the IV curve is, and it is calculated by
𝐹𝐹 =𝑃𝑃
𝐼𝑆𝐶𝑉𝑂𝐶 .
-0.1
-0.08
-0.06
-0.04
-0.02
00 0.2 0.4 0.6
Net
Cu
rren
t (A
)
Voltage (V)
Figure 1.4: Example IV curves. The orange curve is measured data from a silicon PV cell, and the blue is derived from the diode law with I0 and IL adjusted to match the measured data. The areas above the dashed lines indicate the peak power output for each curve. The fill factors for the measured and ideal curves are 0.52 and 0.82, respectively.
VOC
ISC
8
A higher fill factor often indicates a cell of greater quality that is closer to functioning as an ideal
diode. As seen in Figure 1.4, the measured silicon cell is far from ideal. This is likely largely due
to parasitic resistances within the device [5].
In practice, measuring IV curves in both dark and illuminated conditions can give insights
into the quality of the cell. More importantly for the research presented here, comparing the
dark IV curves of a cell before and after it is adhered to an optical component can indicate if it
was damaged during assembly.
1.2.4 Viability of Solar Power
One of the major hurdles with all forms of solar power generation is its intermittency.
No solar technology can produce significant amounts of electrical power at night or under heavy
cloud cover. If solar is to satisfy a large portion of electricity demand, this issue must be
resolved. Perhaps the most direct solution is to use electrical energy storage systems which
exist in a variety of forms from chemical batteries to flywheels to pumped hydro-power [7],
though these would increase the total cost of the systems. There are two major benchmarks in
solar power storage: three and twenty hours. With three hours’ worth of energy storage
capacity, a non-tracking solar harvesting system could shift its output to match the peak
demand on the electrical grid, effectively producing electrical energy when it is needed most.
With twenty hours of storage, solar could effectively deliver electricity around the clock, making
it a viable primary energy source for utilities [8].
Even without extensive storage capabilities, solar has proven to be a valuable ancillary
energy source through what is called “peak shaving.” This concept refers to providing electricity
during times of peak demand on the electrical grid in order to reduce the maximum capacity
9
required of the primary energy generation methods. Peak demand for commercial
establishments tends to occur in the early afternoon (see Figure 1.5), which is also near the peak
production of most solar energy systems. Including solar as part of the energy infrastructure
(distributed or centralized) can help utility companies avoid having to build new fossil fuel
power plants that would only be needed for a few hours each day.
Peak demand for the residential sector, however, typically occurs in the early evening
(Figure 1.5) when the sun is lower in the sky. Non-tracking systems like most flat plate silicon
installations produce a fraction of their peak output at these times since the projected area of
the panels from the perspective of the sun is greatly reduced. This is one area where a tracking
system has an advantage, since the projected area is always kept at a maximum. Therefore,
solar installations with tracking capabilities, e.g. HCPV, can perform peak shaving for both major
demand peaks on the electrical grid, making them an attractive ancillary energy source, even
without large electrical storage capacity.
Figure 1.5: Electrical grid demand during a hot day in California [57].
10
1.2.5 Current Market
The principal metric used by utility companies is the aforementioned levelized cost of
electricity, or LCOE. This value has units of $/kWh and includes all the costs of building,
financing, and maintaining an energy production facility as well as how much electricity it is
predicted to generate over its lifetime. In the utility-scale energy production market, solar PV
must compete with traditional fossil fuels such as coal and natural gas on the LCOE metric which
intrinsically involves government policies such as renewable energy subsidies and greenhouse
gas emission penalties (e.g. “carbon tax” or “cap and trade”). Silicon-based PV is currently
competitive with coal and natural gas in some regions of the U.S. with an LCOE as low as $0.09
up to $0.18/kWh including the as-of-now permanent 10% investment tax credit provided by the
U.S. federal government. For comparison, the LCOE for a new coal power plant ranges from
$0.09 to $0.16/kWh depending on the geographical region and technology employed. Similarly,
natural gas ranges from $0.07 to $0.16/kWh [9]. As a subset of solar PV, CPV technologies are
often compared to flat plate silicon PV to evaluate their competitiveness in the energy market as
a whole.
A recent joint study by the Fraunhofer Institute for Solar Energy Systems (Fraunhofer
ISE; Freiburg, Germany) and the National Renewable Energy Laboratory (NREL; Golden, CO, USA)
reviewed the current state of the CPV market and technology [4]. While the market is still small
and young, it is growing quickly, mostly due to utility scale high concentration CPV (HCPV)
installations in the last few years. HCPV is becoming more attractive as commercially available
system efficiencies improve because it directly reduces area-related costs (e.g. land and number
of tracking mechanisms), lowering the LCOE. In fact, high efficiency is one of the key drivers to
make HCPV competitive with flat plate PV [4]. The record laboratory CPV module efficiencies
11
have now exceeded 36% and are projected to continue improving [10]. In comparison, the far
more mature silicon technologies have champion efficiencies around 22%. Despite these
impressive numbers, HCPV is not yet competitive with silicon on a LCOE basis due to higher
system costs and the relative difficulty of manufacturing and scalability [4].
1.2.6 Fresnel Lens CPV
The dominant technology in the CPV arena
consists of Fresnel lenses point-focusing direct sunlight
onto secondary concentration elements that are adhered
to PV chips, as in the Figure 1.6 schematic. These systems
typically have high geometric concentration ratios in the
500X to 1000X range, fitting squarely into the HCPV
classification. Due to their long focal lengths, on the order
of tens of centimeters, they have the disadvantage of
being bulky, requiring a large volume that needs to be
environmentally isolated. The main reason Fresnel lens
systems make up the majority of the CPV market is that they are relatively simple and
inexpensive to manufacture, and it is a time tested, proven technology.
Figure 1.6: Fresnel lens CPV system diagram with secondary concentrator. Image source: Light Prescriptions Innovators, [59].
12
1.2.7 Planar Light Guide CPV
Another class of CPV system that utilizes a planar light
guide has been extensively studied at the University of
Rochester [11, 12]. These systems eliminate the large air gap of
the Fresnel lens systems, allowing for a more manageable, flat
form factor while mitigating the requirements for environmental
isolation. Additionally, the solid layered construction decreases
risk for misalignment of the different components after assembly. The systems are in the shape
of flat rectangular plates, where direct sunlight enters through
one of the large faces and exits one of the edges (Figure 1.7).
The designs created at the University of Rochester vary from
about 50X to 500X concentration for the application of utility-
scale electricity production [11, 12].
The three key components of these designs are the
primary optic, injection feature, and the light guide. An
example of one planar light guide CPV design is shown in
Figure 1.8 with the components labeled. The role of the
primary optic is to decrease the spatial extent of the light so it
can interact with a small injection feature. In the figure, the
primary optics are an array of “lenslets.” The injection features
then redirect the light to travel parallel to the guide layer such
that it is trapped by total internal reflection (TIR). The purpose of the guide layer is to transport
light from the injection features to the output edge of the system.
Figure 1.7: Planar light guide CPV form factor. Sunlight enters the large face and is guided toward one edge (in red) where the PV chip is placed.
Figure 1.8: Refractive planar light guide CPV components.
13
The challenge with these designs is to keep light trapped in the guide layer long enough
for it to reach the output surface. The problem arises from the interactions of the injected light
with downstream injection features, which can cause some of the light to couple out of the
guide prematurely. Many of the designs try to reduce the severity of these interactions with
novel injection feature geometries [11, 12].
1.3 Concentrator Design Theory
The design of solar concentrator optical systems primarily uses concepts from the
broader field of non-imaging optics, which also encompasses illumination design (e.g.
automobile headlights, display illumination, street lighting, etc.). One of the core concepts of
non-imaging theory is a quantity called étendue, a French term that translates to “extent”.
1.3.1 Étendue and Maximum Concentration Ratio
Étendue relates to the angular and spatial extent of light captured and propagated
through an optical system and can be loosely defined as the product of the index of refraction,
an area, and the solid angle taken up by the light incident on that area. The differential étendue
is defined by
𝑑휀 = 𝑛2 ∙ (𝑑𝑥 ∙ 𝑑𝑦) ∙ (𝑑𝐿 ∙ 𝑑𝑀),
where 𝑛 is the index of refraction, 𝑑𝑥 ∙ 𝑑𝑦 is the differential area of the target surface, and 𝑑𝐿 ∙
𝑑𝑀 is the compensated differential solid angle taken up by the incident light, L and M being the
x and y direction cosines, respectively. This definition assumes that the surface lies in the XY
plane. Étendue is then defined by the following integral:
휀 = ∫ 𝑑휀 = 𝑛2 ∬ ∬ 𝑑𝑥𝑑𝑦𝑑𝐿𝑑𝑀,
or equivalently,
14
휀 = 𝑛2 ∭ cos 𝜃 𝑑𝑥𝑑𝑦𝑑Ω = 𝑛2 ∬ ∬ cos 𝜃 sin 𝜃 𝑑𝑥𝑑𝑦𝑑𝜃𝑑𝜑 [13]
in polar coordinates with 𝑑Ω being the differential solid angle, and with the assumption of a
spatially and directionally constant (non-birefringent) index of refraction. The integrand
contains a cosine term where 𝜃 is the angle between the surface normal and the direction of the
incident light, compensating for the solid angle in polar coordinates [13]. In a lossless system
limited to reflective and refractive interfaces and gradient index materials, étendue is conserved
and the invariant quantity is 𝑛2 𝑑𝑥 𝑑𝑦 𝑑𝐿 𝑑𝑀 [14], so we have
𝑛′2 𝑑𝑥′ 𝑑𝑦′ 𝑑𝐿′ 𝑑𝑀′ = 𝑛2 𝑑𝑥 𝑑𝑦 𝑑𝐿 𝑑𝑀.
This ignores effects such as diffraction and Fresnel reflection losses and does not account for
components such as scatterers. The consequence of étendue conservation is that within an
optical system, light can be incident on a small area from a large angular range or it can be
incident on a larger area from a smaller angular range.
In the extreme case, the conservation of étendue predicts that light from a perfectly
collimated source can be concentrated to an infinitesimally small point (again ignoring
diffractive effects). On the other hand, if the light entering a finite entrance aperture comes
from a non-zero solid angle, the light cannot possibly be concentrated to a single point given
that the maximum possible solid angle on the target is 4π if light is incident from every direction
in three dimensional space. The minimum area which the light can be concentrated onto is
finite. In this way, étendue defines an upper limit to the concentration ratio of a CPV system
given its acceptance angle.
If we assume a spatially invariant Lambertian angular distribution and make the
following simplifications of
15
∬ 𝑑𝑥𝑑𝑦 = 𝐴
and
∬ cos 𝜃 sin 𝜃 𝑑𝜃𝑑𝜑 = 𝜋 sin2(𝜃𝑜),
where A is the area of the surface in question and 𝜃𝑜 is the half angle of a cone with its axis of
symmetry along the surface normal, then the integrated étendue becomes
휀 = 𝑛2 ∙ 𝐴 ∙ 𝜋 sin2(𝜃𝑜).
For a lossless system (i.e. an optical efficiency of unity), the geometric concentration, C, is
𝐶 = 𝐴
𝐴′= (
𝑛′ ∙ sin(𝜃𝑜′ )
𝑛 ∙ sin(𝜃𝑜))
2
,
since étendue is conserved (ε = ε’). Assuming that the ambient index of refraction is unity and
𝜃𝑜′ is maximized to π/2 (for incident light from the 2π steradian hemisphere accessible to one
face of a flat target surface), we get a maximum possible concentration, Cmax, of
𝐶𝑚𝑎𝑥 = (𝑛′
sin(𝜃𝑜))
2 [14].
Notice that the maximum concentration can be increased n’2 fold by immersing the target solar
cell in a material with a refractive index of n’.
Now consider a CPV system that only captures direct sunlight, making the acceptance
angle range (or field of view) of the system equal to the angular size of the sun from Earth, a
±0.27 degree cone. Also assume that the PV cell is immersed in a material of index n’ = 1.5 and
can accept light from 2π steradians, then the maximum theoretical concentration of this system
is
𝐶𝑚𝑎𝑥 = (1.5
sin(0.27°))
2
≈ 101000
16
This concentration is impractically high as any system that could achieve this would have to be
made of extremely resilient materials since the PV cell would be receiving about as much
radiation as it would at the surface of the sun. CPV systems in production do not often have
concentrations higher than about 1000X, and these systems must employ advanced cooling
systems to avoid destroying the PV cells while keeping them at peak efficiency. Also note that
given a 1000X system with a target accepting light from a ±40° cone while immersed in an index
of 𝑛′=1.5 has a maximum acceptance cone of approximately ±1.75°. This is why HCPV systems
necessitate a two-axis tracking system to remain effective throughout the day.
All of the above discussion assumes that the system is comprised of only lossless,
smooth surfaces and non-diffuse materials. If the system includes a scattering component, for
example, the étendue increases when the beam interacts with it. To illustrate this, imagine a
perfectly collimated beam (étendue = 0) with a finite cross section hitting a diffuse surface.
Immediately after that interaction, the beam has the same finite cross section, but now has a
finite angular range in which it propagates, resulting in a positive, non-zero étendue.
It is also possible for étendue to decrease, and the most common way for this to happen
is through optical loss in a system. For example, if a small aperture is placed relatively far away
from a finite extended Lambertian source, the light that passes through the aperture looks more
and more collimated the further from the source it is. The large étendue of the initial extended
source becomes very small in the form of a nearly collimated beam, however, only a small
fraction of the light is successfully passing through the aperture, so the optical loss is high. This
decrease in étendue would also be evident in a CPV system which has a geometric
concentration ratio which is greater than the theoretical maximum concentration ratio: there is
guaranteed to be some optical loss. While there will always be some amount of loss in real
17
systems, the étendue-derived theoretical maximum concentration is still a useful concept in CPV
design, providing a fundamental limit to what is possible.
1.3.2 Optical Efficiency and Effective Concentration
Since the concentration ratio is a purely geometrical quantity, a CPV system could
technically obtain a higher concentration by simply shrinking the size of the PV cell, allowing
much of the light to miss its target. Of course, this would be a pointless exercise because much
of the light is wasted, which decreases the system’s efficiency. For this reason, another
important quantity for CPV systems is the optical efficiency, which is a metric describing the
fraction of light entering the system that eventually strikes the target PV cell. Note that this
quantity is independent of the PV cell efficiency.
In common vernacular, “module efficiency” describes the ratio of output power in the
form of DC electricity to the input power in the form of solar radiation, and “system efficiency”
is the same metric but for an array of modules instead of a single one. Both of these are usually
used in the context of real-world measurements, hence the differentiation of module and
system efficiencies. This document uses the module efficiency term as described here, but not
constrained to real-world data, and ignores this definition of the system efficiency entirely, using
the term more generally, e.g. as the efficiency of an optical system.
Additionally in this document, a new term, effective concentration, is defined as the
product of the optical efficiency and the geometric concentration. This quantity is especially
useful for systems with low optical efficiency, when the geometric concentration is less
meaningful in isolation. Effective concentration is meant to describe the ratio of the average
solar irradiance striking the cell to the solar irradiance entering the CPV system, or in other
words, how many sun’s worth of energy is striking the target PV cell.
18
1.4 Low Concentration Photovoltaics
The aptly named low concentration photovoltaic (LCPV) systems have low concentration
ratios of significantly less than 100X [4]. The low concentration ratio is often paired with a large
field of view, meaning that a tracker is not required, or a simpler system that tracks in only one
dimension may be sufficient. Lesser tracking requirements can make these systems attractive,
especially when high concentration is not necessary. Additionally, LCPV systems allow for some
interesting form factors and applications.
1.4.1 Concentration Limits on Stationary Concentrators
Having a stationary concentrator requires it to
have a large field of view in order to capture sunlight for
a significant amount of time throughout the year. The
necessary field of view can be calculated by following the
elegant description from Winston and Zhang [15]. First,
define a coordinate system for a given location on Earth’s
surface where the X axis is parallel to Earth’s rotational
axis and the Y axis points due west (Figure 1.9). Then,
the Z axis points towards the sun during solar noon on
equinox. The Z axis can be found by imagining a line pointing straight up, normal to the earth’s
surface, then tilting it by the latitude angle of the current position on Earth towards the equator
(due South in the northern hemisphere). This coordinate system is stationary with respect to
Earth, so it spins with Earth’s rotation and moves with Earth’s orbit around the sun. The XY
plane is defined as the polar plane.
Figure 1.9: Schematic of polar plane orientation with respect to the earth (blue) and the sun on the equinox at solar noon (yellow).
19
Recalling that the tilt of the Earth’s rotational axis is 23.45° with respect to its orbital
axis, the unit vector of the sun’s angular position can be written approximately as
𝑛𝑠 = (sin 𝛿 , cos 𝛿 sin 𝜔 , cos 𝛿 cos 𝜔),
where the solar declination, δ, is defined as
sin 𝛿 = − sin 23.45° cos (360°(𝑛 + 10)
365.25),
for the nth day of the year, and the hour angle, ω, is defined as
𝜔 =360°
24𝑡,
for the tth hour of the day starting from
solar noon (t<0 in the morning) [15]. If L
and M are the direction cosines for X and
Y, respectively, the sun’s position can be
visualized in convenient way as in Figure
1.10, with L = sinδ and M = cosδ∙sinω. The
black unit circle represents the positions in
the sky that lie on the polar plane as
defined above. Located on the equator,
this circle marks the horizon. If the sun’s
position is tracked from the bottom of this circle to the top on any given day, the time between
the two endpoints will be twelve hours (𝑡 ∈ [−6, +6]). Similarly, the blue ellipse marks the
boundaries for which it takes the sun eight hours to traverse. The various vertical lines trace the
sun’s position for single days throughout the year, with the green lines representing the days of
the solstices when the sun is at its highest and lowest points in the sky. On the equinoxes, the
-1 -0.5 0 0.5 1
-1
-0.5
0
0.5
1
L
M
Figure 1.10: Recreated from Figure 2 of ref [15]. The bold black circle is the unit circle, the green lines represent the sun’s position throughout the day of the winter (left) and summer (right) solstices, the solid vertical lines represent the sun’s path for the first day of each month from Jan 1 to June 1 from left to right, and the dashed lines do the same for July 1 to Dec 1 from right to left, and the blue ellipse represents the eight hours per day boundary.
20
sun’s path is represented by a vertical line at L=0. The region inside the closed loop formed by
the green lines and the solid sections of the blue ellipse would be the minimum field of view
required for a stationary concentrator to capture sunlight for eight hours per day, year round.
Likewise, the central region formed by the green lines and black circle would be the necessary
field of view for capturing sunlight twelve hours every day for the entire year, assuming the sun
is visible. Note that sunrise and sunset times throughout the year varies if not located on the
equator. At a latitude of 43° (Rochester, NY), the shortest day of the year is roughly nine hours
long, so if a concentrator were designed to capture exactly eight hours of sunlight every day, it
would never be attempting to capture sunlight before dawn or after dusk in Rochester. The
blue eight hour ellipse of Figure 1.10 is calculated by using the equation
sin2 𝛿 + cos2 𝛿 = sin2 𝛿 +cos2 𝛿 ∙ sin2 𝜔
sin2 𝜔= 𝐿2 +
𝑀2
sin2 𝜔= 1 ,
and holding the hour angle, ω, constant such that t = 4 (four hours before noon and four hours
after noon for a total of eight hours). This defines an ellipse with a major radius of 1 in the L
direction and a minor radius of sinω in the M direction.
Now that the sun’s position is calculated in direction cosine space, consider the
following definition of concentration, directly following the above section on étendue,
𝐶 =∫ 𝑑𝑥𝑑𝑦
∫ 𝑑𝑥′𝑑𝑦′=
𝑛′2 ∫ 𝑑𝐿′𝑑𝑀′
𝑛2 ∫ 𝑑𝐿𝑑𝑀 [15].
Assuming the light can hit the target surface from a full hemisphere, ∫ 𝑑𝐿′𝑑𝑀′ is equal to the
area of the unit circle, which is simply π. The area of the region for capturing eight hours of
sunlight per day can be calculated using the following equation:
∫ 𝑑𝐿𝑑𝑀 = sin(𝜔′) [2𝛿𝑠′ + sin(2𝛿𝑠
′)] ≈ 1.56 sin(𝜔′) [15] ,
21
where 𝛿𝑠′ is the solar declination on solstice plus the angular radius of the sun (0.27°), equaling
23.72° or 0.414 radians, and ω’ is the hour angle modified in a similar way according to the
equation,
𝜔′ =360°
24∙
𝐻
2+ 0.27° ,
where H is the number of hours per day captured. In this way, the maximum achievable
concentration for capturing eight hours of sunlight per day is calculated to be about 2.3X for n’ =
1. If the concentrator immerses the target surface in n’ = 1.5, the maximum concentration is
increased 1.52 = 2.25 times to around 5.2X.
1.4.2 Stationary Compound Parabolic Concentrator
The compound parabolic concentrator, or CPC, is a simple and well-known ideal form of
concentrator in nonimaging optics, which is a prime example of a design using the edge-ray
principle [14]. This principle essentially describes a nonimaging design method where the edge
of the source is mapped to the edge of the target, often in a point-to-point manner which is
reminiscent of imaging optical design. However, light incident from the source away from the
edges need not form a point on the target surface, but all rays will land somewhere within the
boundaries of the target surface. This principle is illustrated in the cross section of the CPC in
Figure 1.11. The blue rays come from the edge of the source, or equivalently the edge of the
concentrator’s field of view, and they converge on the edge of the target surface. However, the
red rays which form less of an angle with respect to the optical axis do not converge in any
discernable way.
The CPC is formed by two mirrored parabolic profiles. The axis of each parabola is tilted
at the maximum field of view angle of the system so that rays coming from that direction are
22
focused to a point. The focus of each parabola
is positioned at the bottom point of the
opposite reflector, which is where the edge of
the target surface will be. This is pictured by
the blue rays of Figure 1.11. Theoretically, this
concentrator is 100% efficient in getting light
within the designed field of view from the large
input aperture to the smaller target surface.
This assumes that the mirrors are 100%
reflective. Additionally, for some three dimensional manifestations of these concentrators such
as a rotationally symmetric version, rays that do not share a common plane with the optical axis,
called skew rays, can sometimes be ejected before reaching the target surface, slightly lowering
the concentrator’s efficiency.
As an example of what kind of CPC would be necessary to capture direct sunlight for
eight hours per day, year round, consider a hollow (n=1) extruded, or “trough,” CPC. The system
would be aligned so the input aperture exists in the polar plane, and the extruded dimension
runs in an east-west direction. The end caps of the extrusion are flat mirrors, perpendicular to
the input aperture. This CPC would capture 100% of all rays whose projected angle on the XZ
plane is within its designed acceptance angle, θ1. In equation form, this inequality is
𝐿2
sin2(𝜃1)+ 𝑀2 ≤ 1 [15].
If θ1 is adjusted so that it is just large enough to capture sunlight for eight hours per day, then θ1
≈ 41.5°. The field of view for such a system is shown in Figure 1.12 as a red ellipse. One can see
Figure 1.11: Compound parabolic concentrator profile illustrating the edge ray principle. The blue rays come from the edge of the source and focus to a point on the edge of the dark red target surface. The red rays come from inside the edges of the source.
23
that the corners of the shaded eight hours per day region intersect the field of view (FoV)
ellipse. Also notice that there is much angular
area in the FoV where the sun will never be
located. This is essentially wasted field of view
since the overly large angular range limits how
small the target surface can be and, therefore,
how high the system’s concentration is. For
this system, the area inside the ellipse is
∫ 𝑑𝐿𝑑𝑀 = 𝜋 ∙ sin 41.5° ,
making the concentration
𝐶 =𝜋
𝜋 ∙ sin 41.5°=
1
sin 41.5°≈ 1.5 .
This is about 65% of the theoretical maximum
concentration of 2.3X. This reduction is
entirely due to the extra regions in the field of view that the sun will never occupy.
To significantly increase the concentration, the same basic design can be filled with a
dielectric material of index greater than one, n = 1.5 for this example. Now, another factor to
consider is the refraction of rays at the input surface of the CPC. This is easy to implement with
the direction cosine form of Snell’s Law:
𝐿 = 𝑛𝐿𝑛, 𝑀 = 𝑛𝑀𝑛 [15],
where L and M are the direction cosines before the light enters the concentrator, and Ln and Mn
are the direction cosines just after the light enters the dielectric material of index n. For the
-1 -0.5 0 0.5 1-1.5
-1
-0.5
0
0.5
1
1.5
L
M
Figure 1.12: Direction cosine representation of the sun's position for eight hours per day, year round (grey shaded area) and the fields of view of trough CPCs with an index of 1 (red ellipse) and 1.5 (blue ellipse) that are just wide enough to capture sunlight for eight hours every day without tracking.
24
field of view plots, this essentially means the ellipse shape will be scaled by a factor of n = 1.5.
In equation form, the field of view of the dielectric-filled CPC is
𝐿2
sin2 𝜃1+
𝑀2
𝑛2 ≤ 1 [15],
where θ1 is the acceptance angle in air and n is the index of the dielectric. The equation shows
that the field of view ellipse is simply scaled by n in the M direction. This change of ellipse shape
allows the acceptance angle to be smaller (≈28.3°) and still capture direct sunlight eight hours
per day. The blue ellipse in Figure 1.12 represents the dielectric CPC field of view. The dashed
portions of the ellipse are not physical since they assume rays incident upon the input aperture
at greater than 90° from the surface normal, so only portions of the ellipse inside the unit circle
are physically realizable. That being said, the non-physical regions are still considered during the
calculation of concentration ratio. Compared to the hollow CPC from earlier, the dielectric CPC
has much less extraneous area in its field of view. As such, a higher concentration is expected.
In fact, the concentration is calculated to be
𝐶 =𝑛2 ∙ 𝜋
𝑛 ∙ 𝜋 ∙ sin 28.3°=
𝑛
sin 28.3°≈ 3.2 .
This is about 2.1 times higher than the concentration of the hollow CPC, a significant
improvement. Immersing a CPV system, especially one with a reflective concentrating
component, in a dielectric material can often have beneficial effects and is implemented in
some of the designs presented as part of this thesis.
1.5 Examples of Existing Low Concentration Systems
This section explores low concentration solar photovoltaic systems that exist today.
There are a wide variety of different design types, some that simply modify existing flat plate
solar arrays, and other designs that have interesting niche applications. With the exception of
25
the first device presented here, these designs fall into the building-integrated concentrating
photovoltaics (BICPV) sector which is the focus of this thesis.
1.5.1 RAIS™ PV from tenKsolar
A company called tenKsolar sells a
silicon PV system that has a concentration
ratio of roughly 1.5X which is pictured in
Figure 1.13 [16]. It is a simple but effective
design that is created by modifying a typical
flat plate solar array, placing dielectric
mirrors between the rows of tilted PV
panels. Much of the sunlight that would otherwise fall between the panel rows is reflected onto
the PV cells, boosting energy output. Additionally, the mirrors preferentially reflect photons
with energies greater than the band gap of silicon so light that the cells cannot convert is not
concentrated onto them, helping to temperature control the system.
Figure 1.13: tenKsolar's RAIS™ PV system. The deep blue colored rows are silicon solar panels and the translucent plates are cold mirrors that concentrate convertible sunlight onto the PV cells. [16]
26
1.5.2 Nagaoka University of Technology
The application on which this thesis focuses is
the integration of LCPV into architectural windows. One
such design has been developed, prototyped, and tested
by a research group at the Nagaoka University of
Technology [17]. The basic concept is similar to
tenKsolar’s PV module with alternating rows of PV
material and mirrors, but this system is mounted
vertically and the mirrors work solely on total internal
reflection so they are see-through from the observer’s
perspective. Figure 1.14 shows the operation principle
as well as a picture of the prototype. Notice that an
image of the building can be seen through the CPV
module, though it is significantly obstructed and shifted due to the prismatic nature of the
design. As tested, this module generates 1.15 times the electricity of a standard flat plate PV
module with just 37% of the cell area [17], or a geometric concentration of about 2.7X.
1.5.3 ClearPower PV Window Tile from Stellaris
Stellaris has introduced a “photovoltaic window
tile” that integrates optical components and silicon PV
cells into windows such that a feint image can still be
seen through the module [18]. A similar design
integrates the modules into roofing shingles [19]. This
Figure 1.14: See-through window CPV system schematic (top) and picture of prototype (bottom, [17]).
Figure 1.15: Reproduced rendering of Stellaris' window CPV module showing extruded CPC troughs [18].
27
technology appears to use a well-known shape in illumination design called a compound
parabolic concentrator, or CPC [14], introduced earlier in this chapter. In Stellaris’ design, the
CPC shape is employed in one dimension and linearly extruded in the other (Figure 1.15). It is
constructed of a solid dielectric that uses total internal reflection (TIR) to create a reflection off
of the CPC surfaces [20]. Since the surfaces are transparent, some light outside of the
acceptance angle of the CPC can still pass through the device, though heavily obstructed. While
this design is likely very efficient in terms of capturing solar energy, it loses much of its utility as
a window.
1.5.4 Luminescent Solar Concentrators
A class of concentrators on its own,
luminescent solar concentrators (LSC) utilize
luminescent particles, e.g. quantum dots or
organic dyes, to absorb and re-emit light towards
the PV cells [21]. These systems are shaped like
flat plates that act as light guides with the
luminescent particles throughout, accepting
sunlight from any angle on the large faces and sending light towards the relatively small target
edges. A significant fraction of the light is able to pass through the plate, thus causing the
devices to appear transparent. Re-emission from the luminescent particles sends photons in
random directions, so much of light is prematurely ejected from the system through one of the
large faces. The rest of the light is trapped in the plate by virtue of TIR and travels towards the
edges of the device (Figure 1.16). A major challenge in these systems is avoiding the re-
Figure 1.16: Reproduction from [21]. A schematic for a LSC showing the incoming sunlight, a luminescent particle (orange circle), and re-emitted light that is lost (1) and trapped in the light guide (2).
28
absorption of light that has been successfully trapped in the light guide. Many tricks have been
played such as wavelength conversion to decrease absorption after re-emission, and multiple
layers that specialize in either absorption or efficient light transfer. However, these devices
continue to have low conversion efficiencies of well under 10%, even with highly efficient and
expensive gallium-based PV cells. The geometric concentration ratios can be rather high at 10X
or greater, but the optical efficiencies are often extremely poor. This can be independently
deduced by noticing that the system can accept light incident on the large faces from a full 2π
steradians and the light incident on the smaller target surfaces is incident only from angles that
satisfy TIR conditions in the light guide. Note that these systems also do not conserve étendue
since they are effectively comprised of a diffuse material.
As these devices are highly inefficient at
converting sunlight, applications are often artistic.
Since the luminescent particles re-emit light in a
narrow band of wavelengths, the output light is
colored and the systems can be used, for example, to
accentuate a product display in a big box store. The
light from the overhead illumination is captured and
sent towards the edges of the guide making them glow somewhat brightly as seen in Figure
1.17.
Figure 1.17: Luminescent concentrator plates. Image courtesy Fraunhofer ISE.
29
1.6 Examples of Non-Concentrating BIPV
The building-integrated photovoltaic (BIPV) examples shown in this section do not
explicitly use concentrating optics, but are included since they are integrated into buildings on
vertical surfaces and allow a partially unobstructed view through the modules.
1.6.1 Prism Solar Technologies
Prism Solar leverages bi-facial PV cells and the
natural reflectance of surrounding surfaces in the
environment to create a product that will “outperform any
traditional module in a vertical application” [22]. Bi-facial
PV cells use a transparent conductor on the rear face of
the cell, allowing light to be absorbed in the PV material
from virtually any direction. Prism Solar advertises its
modules as being used in a vertical orientation, which will
severely impact how much sunlight is incident on the cells
due to the effects of projected area. However, some light energy is regained through diffuse
reflections from the ground or from surfaces behind the modules. The modules are designed
for integration into fencing, railings, balconies, and building facades, but would not perform well
as windows due to the high degree of obscuration.
1.6.2 Solaria’s BIPV Laminates
A similar system is available through Solaria, but these modules are meant for
integration into windows [23]. The individual PV cells are very narrow, and hundreds of them
are strung together leaving gaps in between adjacent cells. The individual cells are about 156
Figure 1.18: Prism solar BIPV modules integrated into balcony railings [22].
30
mm by 3 mm with about 6 mm between centers of adjacent cells, resulting in about 50%
transparency. The overall effect of the module looks similar to a tinted window.
1.7 Window Integrated LCPV Planar Light Guide Solar Concentrators
This thesis introduces novel low concentration planar light guide CPV designs for
integration into windows. The architecture of the University of Rochester planar light guide
systems [11, 12] are modified to greatly expand the field of view for use without a tracking
system. The resulting systems and target application are discussed in detail in Chapter 2. The
above examples of commercial BIPV systems show that there exists interest in such a
technology.
31
Chapter 2: Design
The LCPV systems presented in this thesis are designed to meet the criteria of a specific
application. They are integrated into South-facing architectural windows and the electricity
produced is used to offset the thermal energy lost through the windows during colder times of
the year. The application drives the specifications and figures of merit during optimization.
2.1 Application
The application imposes the constraints of being stationary, planar in shape, and
translucent. The stationary requirement implies that the module’s field of view must be very
wide in order to capture sunlight during a significant portion of the day since traditional tracking
is undesirable. However, moving parts are not prohibited, so there can be tracking via moving
components within the stationary module. The design spaces of completely static concentrators
and those with moving parts for one dimensional tracking are considered.
The planar constraint exists to keep the system in a shape that is expected of a window,
and it rules out systems with large air gaps such as Fresnel lens-based designs. The UR planar
light guide design [11, 12] is a good starting point since it has an appropriate form factor and
consists of only refractive surfaces.
Finally, in order to remain a window, a translucency constraint is imposed. Here,
“translucent” means that some outdoor light must have a path through the module so it can
illuminate the indoor area. If the specific application calls for integration into a picture window,
the image of the outdoor environment cannot be heavily distorted nor obstructed, thus
changing the constraint to “transparency.” In the application of a privacy window, the image
32
coming through the module is required to be heavily distorted, thus translucent but not
transparent. Both of these spaces are investigated.
2.1.1 Design Goals
This application does not focus on maximizing power generation. The specific use of the
electricity influences the optical design. The presented designs have the purpose of heating the
indoor air during the winter time in order to effectively improve the insulation properties of the
window. This use is chosen based on the poor insulation properties of architectural windows,
especially during winter when the temperature difference between the indoor and outdoor air
is greatest. Much energy in the form of heat is lost through windows as compared to typical
building outer walls. Thus, windows with the built-in capacity to offset that lost energy,
effectively having an increased R-value, could be a useful and marketable concept.
This use for the produced electricity affects the optical design mainly in the field of view
requirements. Heat should be produced only during the times of year when the outside air is
colder than a comfortable room temperature of 20°C. Thus, the field of view of the system must
only capture direct sunlight when the sun is lower in the sky during winter. The location where
the system is operating has a large effect on when electricity should be produced and where the
sun is located during those times.
2.1.2 Field of View
The sun’s position is often given in terms of an elevation angle (degrees above the
horizon) and an azimuthal angle (for the purposes of this paper, degrees to the west of due
south). From the perspective of the concentrator, the field of view (a.k.a. acceptance angle) is
33
more conveniently considered in the
horizontal and vertical angle coordinate
system defined in Figure 2.1. If the
window exists in the YZ plane and the
positive Y axis points straight up
relative to flat ground, then the
direction vector is parameterized into a vertical angle and horizontal angle. The vertical angle is
the angle between the Z axis and the projection of the direction vector onto the YZ plane, while
the horizontal angle is the angle between the Z axis and the projection of the direction vector on
the XZ plane.
All designs have geometry that is extruded in the horizontal direction. This means that
the optical performance of the design is constant with respect to horizontal angle if certain
effects (e.g. Fresnel losses) are ignored. Thus, the optimization’s figure of merit is weighted as a
function of vertical angle only. This weighting function is location specific, derived from the
sun’s position and the
typical high and low
ambient temperatures
throughout the year.
First consider
the sun’s position
throughout the year.
Figure 2.2 shows the
sun’s position in
vertical angle
horizontal angle
Figure 2.1: LCPV field of view coordinate system definition.
Figure 2.2: Map of sun's position in azimuth and elevation for Rochester, NY (latitude = 43.12°). Yellow dots indicate sun position at various times. The black dashed lines indicate constant vertical angle.
20°
40°
60°
80°
34
Rochester, NY every ten days and every 20 minutes during those select days. Lines of constant
vertical angle are shown as dashed black curves. Based on sun position alone, some vertical
angles are weighted lower since the sun rarely appears at those coordinates. For example, the
80° vertical angle line only coincides with the sun’s position in the sky for absolute azimuthal
angles of about 75° to 90°, near dawn and dusk, and only in the summertime.
The projected area of the window from the sun’s point of view must be considered since
it affects the solar irradiance on the window’s surface. This value is indicated in Figure 2.2 by
the size of the yellow dots. The closer to an azimuth and elevation of 0°, the greater the
projected area, and the greater the weighting in those regions.
Finally, the temperature differential between the inside and outside air must be
included in the vertical angle weighting function. There are two days of the year during which
the sun passes through each point within its range: one in the spring semester and another in
the fall. The outside temperature is estimated from average temperature in the specified
location as a function of calendar day. Further, the estimated temperatures for the two days
corresponding to each position of the sun are averaged. This value is then subtracted from
room temperature (20°C) and factored
into the weighting function. If the
average temperature is greater than
room temperature, its weighting is
negative.
The sun’s position, window’s
projected area, and temperature
differential are all integrated along each Figure 2.3: Weighting functions for three cities in the U.S.
35
line of constant vertical angle. The resulting values describe the final weighting function with
respect to vertical angle. The weighting functions for El Paso, TX, Rochester, NY, and Fairbanks
AK are shown in Figure 2.3. El Paso is relatively warm and at a lower latitude of 32°N. Rochester
is temperate with a latitude of 43°N. Lastly, Fairbanks is cold and at a high latitude of 65°N.
Each weighting function has a sharp peak that corresponds with the vertical angle of the
sun at solar noon on the winter solstice. This is the smallest vertical angle that exists completely
within the region occupied by the sun at some point during the year. Additionally, lower vertical
angles also correspond to a larger projected area of the window and a larger temperature
differential. The peak location can be calculated simply by subtracting the tilt of the earth’s
rotational axis and the latitude from 90°. For example, Fairbanks, located just south of the arctic
circle, has a peak in its weighting function at a vertical angle of nearly zero:
90° − 23.45° − 𝐿𝑎𝑡𝑖𝑡𝑢𝑑𝑒 = 90° − 23.45° − 64.82° = 1.73°
Another feature of note is the negative weighting function values for El Paso at vertical
angles above 60°. This occurs because the integrated average temperature is above 20°C for
those vertical angles.
2.2 The Louver Concept
For most CPV designs, the field of view is centered about the optical axis which is
normal to the input aperture plane. For example, a typical HCPV FoV is a ±1° cone centered on
the optical axis. In the window LCPV application, the ideal field of view is not only extremely
large, but it is far off center and oddly shaped. To accommodate this field of view, a novel
optical design is created.
36
Just like the planar light guide CPV introduced in
Chapter 1, there are three optical components to the
designs presented in this thesis: primary focusing optics,
injection features, and a guide layer. The novel primary
optics come in the form of curved reflective louvers that
direct sunlight into the guide layer via injection features.
The louvers are curved blades reminiscent of metal
window blinds. This design space takes advantage of the
high, non-normal incidence angles of the incoming
sunlight.
Each louver casts a shadow on the louver directly below, and the amount that the
adjacent louver is shadowed depends on the vertical position of the sun (Figure 2.4). This allows
part of the louver surface to be optimized for a range of vertical angles at which that section is
not shadowed. The horizontal extrusion geometry of this design creates no concentration in the
horizontal direction, thus keeping the theoretical horizontal field of view at ±90°.
The application calls for a large area of CPV. However, the further light travels through
the guide layer, the greater the chance it is coupled out of the guide prematurely, resulting in
optical efficiency loss. Splitting the window area into a number of CPV modules mitigates this
inefficiency. The louver designs send light towards both the top and bottom guide edges, so PV
cells must be located on each. If the modules are stacked top to bottom as illustrated in Figure
2.5, adjacent modules can share a single, bi-facial PV cell. The extruded architecture allows the
CPV to be extended to any length without impacting its optical efficiency.
Figure 2.4: Shadowing advantage of the louver design space, where part of the louver (a) is designed for greater vertical angles and other parts (b) are optimized for lesser ones.
37
Sending light towards both the
top and bottom edges of the guide
provides the opportunity to intrinsically
decrease guiding losses by reducing the
footprint of the injection features on the
guide surface. This is done by
shortening the injection feature
subsystem by essentially adding a fold
mirror. This approach is used in all
louver designs and appears in the form
of small mirrored surface located on the
upper extreme of the injection feature, perpendicular to the window plane.
For a single module, sending light towards two target edges instead of one decreases
the system’s concentration ratio by a factor of two. However, if the modules are stacked and
bifacial PV cells are used to accept light from two adjacent modules, it can be argued that the
concentration ratio is unaffected.
Four distinct designs
based on the louver concept
are presented here. The
“suspended louver” (SL) has
louvers suspended in air with
extruded dielectric prisms as
injection features. The
Thre
e st
acke
d L
CP
V m
od
ule
s
Bif
acia
l PV
cel
ls b
etw
een
mo
du
les
Figure 2.5: Illustration of a full window LCPV system consisting of several modules stacked top to bottom.
Figure 2.6: Cross-section view of a suspended louver design. The horizontal grey lines on the injection features indicate a reflective surface.
38
extruded injection features use a flat refractive surface to bend the light to angles where it is
subject to TIR in the guide layer. The top side of the injection features are mirrored to reduce
the footprint of the features on the guide surface while sending the light towards two edges of
the guide as opposed to a single edge as in the UR light guide module of Chapter 1. An example
of this design is shown in Figure 2.6 between the glass of a double-paned window. Hashed lines
indicate reflective surfaces which include the louver and the topmost injection feature edge.
The “immersed louver”
(IL) immerses the louvers in a
dielectric material. This has the
unique advantage of narrowing
the angular range of the light
that strikes the louver surface,
allowing them to be smaller and
flatter. In addition, if the
immersion material contacts the outer window pane, number of air-dielectric interfaces in the
system decreases. This means fewer Fresnel losses and greater optical efficiency. The injection
features in this design are areas of optical contact between the immersion material and the
guide layer which act as “holes” that allow light to pass through. The cross-section of an IL
design can be seen in Figure 2.7. Notice the fold mirror associated with each injection feature is
present.
The “extruded segment lens” (ESL) deviates from the original concept by having a flat
reflective surface and using a curved refractive interface to add focusing power. This design
loses much of the shadowing advantage around which the louver concept is based. The cross-
Figure 2.7: Cross-section of an immersed louver design.
Injection Feature
Fold Mirror
39
section of one such design is
displayed in Figure 2.8. Since the
window area is filled with curved
refractive surfaces, this design
heavily distorts the image of the
landscape on the opposite side of
the window. Thus the ESL is not
applicable to picture windows,
but has promise in the form of a privacy window.
Finally, the “tracking louver” once again suspends louvers in air, but allows them to
move and track the sun in a vertical direction. The cross-section looks qualitatively similar to the
suspended louver in Figure 2.6, but the louver’s position and orientation vary as a function of
the vertical angle of incoming sunlight. The injection features and guide layer remain static, but
the injection feature utilizes a cylindrical refractive surface. Though the moving parts increase
the complexity of the system, they allow greater optical efficiency and a broader vertical angle
field of view.
2.3 Optimization and Results
Initially, the primary optics of the static designs were optimized in segments, in a
sequential manner. The surface was constrained to being continuous, but not necessarily
smooth. In this scheme, each segment is described by a quadratic function with three degrees
of freedom. Other degrees of freedom include the starting position of the first segment relative
to the injection feature, the injection feature size, and the weighting function. Unlike those
Figure 2.8: Cross-section of an extruded segment lens design. Grey lines indicate mirrored surfaces.
40
presented in Section 2.1.2, the weighting function for each segment is dynamically calculated
according to the fraction of light from each vertical angle (within a predefined range) captured
by that segment.
While this optimization method has a large number of variables and its sequential
architecture is slow and cumbersome, it provides insight by explicitly incorporating the
shadowing effect central to the louver concept. After numerous results for each static design, it
was clear that the best performing designs exhibited relatively smooth surfaces that did not
appear segmented. The optimization routines were then rewritten to describe the louver (and
refractive lens) surface shape as a single higher order polynomial while implementing the
vertical angle weighting functions of Section 2.1.2. The new optimization method greatly
reduces the number of system variables and eliminates the need for a sequential process.
Though the performance values for each optimization method are comparable, the single
segment method does produce slightly better results since it can evaluate a greater number of
variable values in a shorter amount of time.
For comparison purposes, all designs are optimized for a guide layer length of 300 mm
and thickness of 13 mm. All dielectrics are simulated as PMMA with a refractive index of about
1.49 and do not include internal absorption. The reflectance of all reflective surfaces is a
constant 95% and the spacing between adjacent louvers is 2 mm. The size of the louvers is
proportional to their spacing (larger size adds to the thickness of the window as a whole), so 2
mm is chosen in order to not add too much thickness to the system since the guide already adds
13 mm. It is advantageous to the designs to have a thick guide layer rather than large primary
optics. Of course, the dimensions may be adjusted to improve manufacturability.
41
2.3.1 Suspended and Immersed Louver
The optimization parameters for the
suspended and immersed louver designs are similar.
The variables consist of the height of the injection
feature, the distance from the guide to the extreme
endpoint of the louver, and the coefficients of a
seventh order polynomial describing the shape of the
louver reflector (Figure 2.9). During optimization,
solutions in which the reflectors collide with adjacent
injection features are invalidated.
For the suspended louver (SL), the injection prism shape is calculated so the refractive
surface of the prism is oriented in a way that allows rays from any point on the reflector to be
refracted at an angle compatible with TIR in the guide layer. The size of the injection feature
fold mirrors is calculated for both SL and immersed louver (IL) so that all rays from the extreme
endpoint of the louver that strike said mirror will subsequently pass through the injection
feature/guide layer interface.
Figure 2.10 shows the final SL solutions for each location. The geometry of each
solution is shown across the top with the same scale for each. The bold lines in the geometry
plots represent one iteration of the arrayed optics, and the thin curve is the adjacent louver that
provides the shadowing effect. The optical efficiency as a function of vertical angle is presented
in the bottom graph. Notice that the efficiency peaks for the three cities appear in the same
order as the peaks in their respective weighting functions seen in Figure 2.3.
x0
h
Figure 2.9: Optimization variables for suspended (and immersed) louver designs indicated in red.
42
The efficiency values represent the optical efficiency of the concentrator, so the effect
of projected area for off-axis incidence angles is not included. This value may be broken down
into two components:
the “injection
efficiency” and “guiding
efficiency”. Injection
efficiency refers to
fraction of light energy
entering the system’s
front aperture that is
successfully injected
into the guide layer
within its TIR limits. The
guiding efficiency is the
fraction of successfully
injected light that
travels in the guide until
it strikes a PV cell surface. For these designs, the injection efficiency is the same for every louver
in the CPV module. The guiding efficiency, however, varies depending on distance that light
must travel in the guide layer before reaching the output edges. This is explored in greater
detail in Section 2.4.1.
As indicated by the geometry plots, the Rochester and Fairbanks design have injection
prisms that occupy about half of the adjacent guide surface. This means that the guiding losses
Figure 2.10: Solutions from the suspended louver optimization for the three chosen locations. Geometry of the reflectors and injection features are displayed across the top, and the efficiency as a function of vertical angle is shown below.
43
are large since there is a high chance that a ray traveling along the guide couples out via a
downstream injection feature. The efficiency plots take this into account since they simulate
the full 300 mm tall system.
Similar
efficiency trends are
found in the immersed
louver solutions as
shown in Figure 2.11.
The geometry of the
injection features are
displayed as a thick
horizontal line
representing the fold
mirrors and a narrow
vertical line indicating
the extent of the
injection feature.
Recall that the IL
injection features are
areas of optical
contact between the immersion material and the guide layer. The IL solutions typically have
better performance than their SL counterparts. Part of the reason for this is the reduced size of
the injection features, allowing for a greater guiding efficiency.
Figure 2.11: Solutions from the immersed louver optimization for the three chosen locations. Geometry of the reflectors and injection features are displayed across the top, and the efficiency as a function of vertical angle is shown below.
44
There exists a tradeoff between the width of the efficiency peaks and their height. For
example, comparing the Fairbanks solutions from the SL to the IL architecture reveals that the
efficiency peak has become narrower and taller. This tradeoff is also evident in the multiple
solutions found for a constant location and architecture. The peaks tend to be fairly narrow and
tall since the weighting functions have relatively narrow peaks.
2.3.2 Extruded Segment Lens
The extruded segment lens
(ESL) design was originally named for
its segmented curved surface and its
horizontally extruded geometry,
though the surface presented here is
defined by a single polynomial function.
ESL designs have analogous
optimization variables to the SL and IL
architectures (Figure 2.12). Instead of a
polynomial describing the louver shape,
there is a polynomial describing the
refractive surface shape. The width of
the refractive surface and size of the
injection feature are also variable as were the louver widths and injection features in the
previous designs. The calculated quantities include the injection feature fold mirror (horizontal
h y0
Figure 2.12: Optimization variables for extruded segment lens design indicated in red lettering. Traced rays show the additional angled fold mirror in the ESL design (ray colors indicate angle after injection into the guide layer).
Fold Mirror
← G
uid
e →
45
lines in Figure 2.12) height, and the angle of an additional fold mirror that makes up the bottom-
most face of the extruded lens structure. This added fold mirror essentially serves the same
purpose as the refractive face of the injection prism feature in the suspended louver
architecture.
Figure 2.12 also shows rays traced for a given incidence angle, displaying three ways
light can enter the guide layer. With the louver designs, all light reflects off of the louver and
possibly the fold mirror before successful injection into the guide layer. Those two paths remain
true for the ESL design, replacing the louver with the angled fold mirror. There is an additional
optical path that interacts with neither mirror, injecting into the guide immediately after passing
through the refractive lens surface.
Another note for this design
is the effect of the dielectric
material that fills the shape drawn
in Figure 2.12. It is modeled as a
dispersive material (PMMA) and
rays of several wavelengths are
traced during optimization. This is
done because the chromatic effects
are more significant than in the
reflective designs due to the highly
curved refractive surface as the first
interface in the ESL system. Figure 2.13: Solutions from the extruded segment lens optimization for the three chosen locations. Geometry of the reflectors and injection features are displayed across the top, and the efficiency as a function of vertical angle is shown below.
46
However, for the presented designs, the performance does not depend strongly on wavelength.
Optimization results for the three locations are shown in Figure 2.13. These refractive
designs have a uniquely shaped field of view compared to the two static reflective designs, but
the same trends are observed among the different locations. The El Paso optimization yields a
taller, narrower field of view than the Rochester and Fairbanks locations. The peaks still follow
the same order as the two louver designs since the weighting functions are independent of
system architecture.
While the ESL performance is roughly as good as the IL, it does have significant
disadvantage in this application. Since the curved refractive surface fills the majority of the
window’s aperture, the image of the outside world is heavily distorted.
2.3.3 Tracking Louver
The final design space explored is the “tracking louver” (TL). As the name implies, it
utilizes a reflective louver primary optic that moves to track the sun. The louver is allowed to
translate in the cross-sectional plane and rotate about an axis parallel to the extrusion direction.
The louver shape is defined as a section of a parabola to achieve a tight line focus. The injection
feature changes shape as well: the refractive surface is cylindrical instead of flat. The focus of
the reflector is shifted to a part of the injection feature such that the light rays refract into an
angle supported by TIR in the guide layer.
Since the reflector’s focus spot size is infinitesimally small for incident rays parallel to
the parabola axis, an extended source with the angular size of the sun is considered during
optimization to prevent an unrealistically small injection feature.
47
Optimization variables consist of the radius of the
injection feature refractive surface, the size of the injection
feature’s footprint on the guide surface, the focal length of
the reflector’s parabola, and the extent of the reflector
(Figure 2.14). For each vertical angle (at sub-1° intervals),
the reflector is moved to a position such that its axis is
aligned with the sun and its focus is positioned on the face
of the injection feature. Then the alignment and lateral
position is refined through an optimization routine for each
vertical angle. Thus the tracking motion is determined.
Occasionally, the reflector collides with the guide
layer after initial alignment. This is a physically disallowed
state and its occurrence depends primarily on the
reflector’s length and shape. In this case, the optimization
procedure brings the bottom of the reflector in contact with
the guide surface and rotates it out of alignment. The new
alignment causes the sharp focus to be lost, but a relatively
concentrated caustic is formed and aimed at the injection feature. This reflector-guide collision
occurs in the lower range of vertical angles as in the 0° position of Figure 2.15 (guide surface at x
= 0 mm). The lower the vertical angle, the more misalignment is required to prevent collision,
and the less well defined the caustic becomes. This reduces the optical efficiency at the vertical
angles in question.
Injection Feature
Guide
Figure 2.14: Tracking louver optimization variables shown in red.
Fold Mirror
48
Another concern
regarding the mobile
louvers is light blocked by
an adjacent louver after
reflection but before
striking the injection
feature. This essentially
constrains the maximum
reflector focal distance to
be approximately the
same as the louver
periodicity. This way, the
adjacent louver does not
interfere with the light
headed towards the
injection feature.
The optimization
solutions in Figure 2.15 show that the performance of the tracking louver design changes little
among the three cities investigated. Note, the weighting function for El Paso is modified to
ignore the negative values for this optimization procedure. Further investigation shows that the
optimized louver shapes are similar for all three locations as well. This means that a single
tracking louver may be used effectively at all three locations without modification.
Figure 2.15: Solutions from the tracking louver optimization for the three chosen locations. Geometry of the reflector and injection features for the Rochester design are displayed at the top for several vertical angles, and the efficiency as a function of vertical angle is shown below for all three cities.
Injection Feature
49
The magnitude of the efficiency for the TL designs is far greater than that of the static
designs, and the field of view is much broader. This vastly improved performance comes at the
cost of increased system complexity due to moving parts. The small size of the optimized
injection features mean that the reflector has a high positional tolerance making manufacture
difficult. Looser tolerances require a larger injection feature, therefore reducing guiding
efficiency.
2.4 Analysis
Insights regarding the loss mechanisms in the presented systems are achieved through a
more detailed analysis of the ray trace data recorded during optimization. Additionally, the data
are analyzed within the scope of the application: in terms of effective R-value gains.
2.4.1 Efficiency
Recall that the efficiency for the CPV systems can be broken into components of
injection efficiency (front aperture through injection feature) and guiding efficiency (injection
feature to PV cell). The suspended louver Rochester design is used as an example of this
analysis in Figure 2.16. The full
system field of view is the
same as that found in Figure
2.10, and the thin red line
shows the injection efficiency
as a function of vertical angle.
The guiding efficiency
(averaged over the system Figure 2.16: Suspended louver Rochester design performance showing injection efficiency and weighting function.
50
aperture) is the ratio of FoV to injection efficiency at each vertical angle. The guiding efficiency
is low for the SL designs, on the order of 40%.
The full length for the optimized
systems is 300 mm from the top edge of
the module to the bottom, where the two
PV cells are located. Given the louver
periodicity of 2 mm, each module contains
about 150 louvers and injection features,
giving ample opportunity for light to couple
out of the guide prematurely. To illustrate
the guiding efficiency in another way, the
performance data is averaged over vertical
angle and presented as a function of
aperture position instead. Additionally, the
output is broken into the top and bottom PV cells to show the effect of the low guiding
efficiency. A guide position of 0 mm in Figure 2.17 represents the location of the bottom PV cell,
and 300 mm is the location of the top cell.
Each cell has high efficiency in positions near their respective locations. In fact, the first
several millimeters near each guide edge reveal the injection efficiencies for rays travelling
towards the top and bottom cells. Guiding losses do not occur for approximately the first 26
mm of travel along the guide since the injected light does not contact the lossy guide surface
immediately. At a ray angle matching the critical angle of the guide material, about 45°, it
travels a distance roughly equal to twice the guide thickness (13 mm) before interacting with the
Figure 2.17: Rochester suspended louver design normalized efficiency components as a function of position on the system's front aperture. The total is the sum of the top and bottom cells, while the average is the mean of the total over all positions.
51
guide surface containing injection features. In contrast, very little light travels along the entire
length of the guide to strike the opposing PV cell since that requires multiple interactions with
the lossy guide surface. This is indicated by the low efficiencies of each cell at aperture positions
opposite their respective locations.
The sum of the top and bottom cells (“Total” in Figure 2.17) shows the relative efficiency
with which light is captured by either PV cell as a function of aperture position. The efficiency
for this design in the center of the aperture is about half of its maximum value found near the
edges. This efficiency depression is less pronounced in systems with greater guiding efficiencies,
e.g. tracking louver.
If the system remains as is except for the
total length of the guide, the efficiency is expected to
increase as the guide becomes shorter. A short
guide means less distance for light to travel before
encountering a cell and therefore greater guiding
efficiencies. Thinking graphically, the two curves of
Figure 2.17 for the top and bottom cells maintain the
same shape, but are shifted closer to each other if
the guide is shortened. The efficiency for the bottom
cell remains as is at the position of 0 mm and the
same is true for the top cell, but at the maximum
aperture position. The results of this analysis are
summarized in Figure 2.18. As expected, the
efficiency increases as the guide length decreases.
Figure 2.18: Rochester SL design average efficiency and effective concentration as a function of guide length, both normalized at the designed guide length of 300 mm.
52
However, the geometric concentration ratio is directly proportional to the guide length, so the
effective concentration ratio (geometric concentration x optical efficiency) actually decreases
with shorter guide lengths. For example, if the guide is shortened from 300 to 100 mm, the
optical efficiency for the system doubles, but the geometric concentration ratio is only a third of
its initial value. Thus, the resulting effective concentration at a 100 mm guide length is 66% of
its value for a 300 mm long guide.
Recall that this design is optimized for a guide length of 300 mm and thickness of 13
mm. If the system were re-optimized for a shorter guide, the results would not coincide with
those in Figure 2.18. For example, at a 100 mm guide length it is advantageous to achieve
higher injection efficiency at the expense of guiding efficiency since the average distance light
must travel along the guide layer decreases. This changes the shape of the optical components,
i.e. larger injection features, and achieves a higher efficiency (and effective concentration) than
seen in Figure 2.18 which assumes the optical components remain as they are for a 300 mm
long guide.
2.4.2 R-Value
The final analysis attempts to predict the CPV system’s effect on the insulatory
properties of a window. The R-value is a measure of thermal insulation efficiency. The higher
the R-value, the better the insulator. A well-insulated window has an R-value of R-3.0 to R-5.0
while a typical outer wall of a house is about R-13. R-value is defined by the expression, Q =∆T
R,
where Q is the energy flux lost through a barrier, ΔT is the temperature differential from one
side of the barrier to the other, and R is the R-value of the barrier. The US units for R-value are
ft2∙°F∙hr/Btu and the SI units are m2∙°K/W [24]. The U-factor, or U-value, is simply the inverse of
53
the R-value. When the energy produced by the window LCPV modules is equivalent to the
energy lost through the window, the U-factor is zero while the R-value is infinite. For this
reason, the analysis results are presented in terms of U-factor.
The “effective U-factor” is hereby defined as the passive U-factor above with a modified
net energy flux, Q, incorporating the energy recovered by the integrated CPV. This quantity is
highly dependent on weather conditions since Q varies with the temperature differential across
the window and the CPV electricity production depends on the amount of solar irradiance
incident on the window. As such, two weather conditions are considered in the effective U-
factor analysis: a year that is sunny at all times with temperatures based on monthly averages,
and a “typical meteorological year,” or TMY, that includes solar irradiance and temperatures
from historical data. The TMY database is managed by the U.S. National Renewable Energy
Laboratory (NREL) and includes data for hundreds of cities and towns across the United States
[25]. TMY data include ambient temperatures, direct and indirect solar irradiance, and several
other atmospheric conditions during every day of a single (synthetic) year per location.
The effective U-factor is calculated year-round and the results for the SL Rochester
design are displayed in Figure 2.19. The bold blue lines are the data for the sunny year and the
thin green lines correspond to the TMY data. The passive heat flux is the energy lost in the form
of heat per window area from the inside of the window to the outside based on the passive R-
value. Rochester does not often have average ambient temperatures (average of daytime highs
and nighttime lows) that exceed room temperature (20°C). The temperature gradient changes
sign mostly during the months of July and August.
54
The passive R-value for
this data is assumed to be 5.0
equivalent to a U-factor of 0.2.
This corresponds to a very well-
insulated, triple pane window
filled with a noble gas such as
krypton [26]. The passive R-value
is affected by the inclusion of the
CPV structure. The R-value is
inversely proportional to the
thermal conductivity of a bulk
material at a constant thickness,
the latter being an intrinsic
material property. Therefore, the
lower the thermal conductivity,
the more effective a material is for
use as insulation. Krypton, for instance, is sometimes used
between window panes since it has a low thermal conductivity
of 0.009 W/m∙K, less than half that of air. PMMA, a candidate
material for the CPV guide layer, has a relatively high
conductivity of 0.2 W/m∙K, but is still five times more effective
than glass (Table 2-1). If the construction of a CPV integrated
Material
Thermal
Conductivity
( W/m∙K )
Air 0.024
Argon 0.016
Krypton 0.009
PMMA 0.200
Glass 0.960
Copper 401
Table 2-1: Thermal conductivities for various materials [26].
Figure 2.19: Effective U-factor calculations for the SL Rochester design. The bold blue line represents a sunny year and the thin green line is from “typical meteorological year” data. The red line of the U-factor plot represents the passive U-factor of the window.
Passive Heat Flux (Indoors to Outdoors) W
h/m
2 /day
W
h/m
2 /day
55
window requires PMMA to replace part of the gas volume between the glass panes, the passive
R-value will decrease. If the window is allowed to become thicker to accommodate the
additional CPV structure, however, the R-value can be recovered. One can imagine the CPV
guide layer replacing the central pane of a triple paned window.
Referring once again to Figure 2.19, the CPV electricity production is the energy
converted to electricity per window area assuming a PV cell efficiency of 18%, typical of silicon.
The calculations account for both direct and indirect solar irradiance. When this value equals
that of the passive heat flux, the CPV is generating as much energy as is lost through the
window. One effect that is not included here is the heating of the cells which accounts for the
majority of the energy striking the cell that is not converted to electricity (100 – 18 = 82%). This
heats the inside of the window and is mostly lost to the outside, but would bolster the system’s
performance overall.
Finally, the effective U-
factor is plotted for both simulated
weather conditions along with the
passive U-factor of 0.2. The sunny
weather conditions yield a
significant decrease in the effective
U-factor in the winter. In February,
the U-factor is as little as half the
passive value alone. This equates to
an R-value of about 10, almost as
well insulated as the surrounding
Figure 2.20: Effective U-factor calculations for the SL Rochester design. Battery storage is included and its charge level is shown in the bottom plot.
56
outer walls of the building. Most of the month of October has an even more impressive U-factor
of around 0. This means there is no net loss of energy through the window, an effective R-value
of infinity. The TMY weather conditions, however, show significantly less optimistic
performance. Unfortunately, Rochester is extraordinarily cloudy during the winter months so
the solar irradiance is much reduced. This effect is seen clearly in the CPV electricity production
plot.
The U-factor data becomes negative and greater than the passive value at some times
during the year. A negative effective U-factor corresponds to the electricity production being
greater than the passive heat loss while the ambient temperature is below room temperature.
The U-factor wraps around through infinity when the ambient temperature becomes greater
than room temperature. These positive values greater than the passive U-factor indicate that
electricity is being produced when the indoor air is being cooled during warmer times of the
year.
To mitigate this unwanted effect, especially for TMY conditions, some battery storage
could be included with the window in order to save and use the electricity when it is needed
most. The U-factor is recalculated assuming an electrical storage capacity of 100 Wh (equivalent
to a large laptop battery) per square meter of window area. The battery is modeled as having
some current leakage that heats the indoor air when discharging. The U-factor in TMY
conditions is considerably improved during the summer and early fall months. This is because
any excess energy can be stored and used on a cooler or cloudier day.
57
Even with a large storage
capacity, the SL Rochester design
cannot provide a significant
benefit. The other static designs
fall similarly short for the
Rochester location due to the
cloudy winters. For the static
designs, the best case scenario for
effective U-factor is not
surprisingly a warm, sunny location
with a more efficient CPV
architecture. As such, the
immersed louver design is
analyzed for the El Paso location.
The results are presented in Figure
2.21. Indeed, the U-factor is
improved considerably and it is
often the case that the windows
have a net negative energy loss, as
is the case in February, October,
and November. Figure 2.21: Effective U-factor calculations for the immersed louver (IL) El Paso design including battery storage.
Wh
/m2 /d
ay
Wh
/m2 /d
ay
58
The final analysis is for
Fairbanks, a cold location with
little solar radiation in the
winters. The only truly effective
CPV for Fairbanks is the tracking
louver with its high conversion
efficiencies during the summer
and winter months. The results
are shown in Figure 2.22. The
highly efficient tracking louver
design shows promise even in the
demanding conditions of
Fairbanks. The advantages of the
CPV are especially noticeable
during the summer months,
which have average daily
temperatures below 20°C and a
fair amount of solar radiation.
The U-factor from April through
September is well below zero, so
the window has a net positive
effect for about half of the year.
Figure 2.22: Effective U-factor calculations for the tracking louver Fairbanks design including battery storage.
Wh
/m2/d
ay
Wh
/m2 /d
ay
59
2.4.3 Cooling Effect
One final effect that can be engineered into the reflective louver designs is a way to
reject direct sunlight at higher vertical angles associated with warmer months. If sunlight passes
into a building and strikes indoor surfaces, it will warm the indoor air. This is undesirable during
the summer when outdoor temperatures are high. At vertical angles above the range of the FoV
for the static reflective louver designs, direct sunlight tends to strike the back of the adjacent
louver before making its way indoors. If the back of the louvers are textured to be
retroreflective, the light could be redirected back outside where it will not have negative effects.
An immersed louver design is depicted in Figure 2.23. The left image illustrates solar
rays incident from a large vertical angle outside the FoV of the system. The smooth back of the
louver redirects the rays that miss the injection feature towards the indoor space. This is
undesirable when trying to keep the indoor air cool. The image on the right side of Figure 2.23
Figure 2.23: Effect of backside retroreflective texture on static louver designs: rejecting direct sunlight during summer. Left image shows high vertical angle rays striking back of louver and continuing through the window. Right image shows rays being turned back by a retroreflective texture on the adjacent louver rear surface.
60
shows the same system under the same illumination with the only difference being a
retroreflective texture on the back side of the louvers. Instead of sunlight being redirected
indoors, it is reflected back toward the primary louver and subsequently outdoors.
This system generally works for both the suspended and immersed louvers, but is not
obviously applicable to the refractive design space. The tracking louver can reject sunlight
without a retroreflective texture by simply moving the louvers into a positon that directs
sunlight back outside after a single reflection.
2.4.4 Aesthetics
For the application as specified, the aesthetics of the CPV are important. For picture
windows, an observer must be able to see a partially unobstructed view of the scene on the
opposite side of the glass. On the other hand, a privacy window application requires severe
distortion of the scene while still allowing light through to illuminate the room.
Three photorealistic renderings are shown in Figure 2.24. All ESL designs nearly fill the
system aperture with curved surfaces extruded in the horizontal direction. This blurs the scene
on the opposite side of the window in a vertical direction so no details can be distinguished,
thus its potential as a privacy window. This blurring is especially evident when comparing the
background of the bottom and middle images in Figure 2.24. The suspended louvers exhibit a
high degree of obstruction due to the louver shape and some obscuration from the large
prismatic injection features.
The IL designs offer the least amount of obstruction of any static design given their
relatively flat louver shapes and injection feature architecture. The only obstructive portion of
the injection features are the fold mirrors. If the injection feature is located close to the
61
adjacent louver (e.g. the Fairbanks design, Figure
2.11), the scene can be minimally obstructed
when peering through the window at certain
angles. The middle image in Figure 2.24
simulates such an IL design at the optimal
viewing angle for low obstruction ratio, about
25% of the total aperture is obstructed.
The tracking designs have even flatter
louver shapes and very small injection features,
resulting in obstruction ratios as low as 10%. Of
course, windows containing any of the louver
designs can have high obstruction ratios if
viewed from certain directions, for example, a
steep upward angle. Traditional window blinds
have the same, familiar effect.
IL No CPV
No CPV ESL
No CPV SL
Figure 2.24: Photorealistic renderings of views through the three static designs: SL (top), IL (middle), and ESL (bottom).
62
2.4.5 Passive Solar Heating
Passive solar heating is a
technology that has a nearly identical
application to the presented LCPV window
designs. Instead of using photovoltaic
materials, however, this approach relies on
indoor surfaces absorbing sunlight energy
passing through windows, converting the
energy directly to heat. Thoughtfully placed thermal masses embedded into a building’s
structure can offer storage of that thermal energy with the ability to continue heating the
indoor space when sunlight is not available, albeit in an uncontrolled manner. A passive control
mechanism may be included in the form of an eve to shade the windows during the summer, a
similar concept to that presented in Section 2.4.3 [27].
Effective passive solar heating design requires a disproportionate number of south-
facing windows (in the Northern Hemisphere) compared windows of other orientations. In a
typical home, about one quarter of the window glass is south-facing, amounting to about 3% of
the building’s floor area. A house with basic passive solar heating (without additional thermal
masses) increases this to between 5% and 7% the total floor area. Once the area of south-facing
window glass exceeds about 12% of the floor area (depending on climate), gains from solar
heating begin to wane since it is difficult to include enough thermal mass into the structure.
Additionally, problems such as glare from the large glass area and fading of indoor fabrics
become significant [27]. A major advantage of passive solar heating is that it is essentially free if
incorporated prior to construction.
Figure 2.25: Schematic of building with passive solar heating. Shows absorbing indoor surfaces, thermal mass storage, and shading control eve.
63
For some climates, passive solar heating can surpass the performance of the presented
LCPV designs for this application. For example, aggressive passive solar design can reduce the
amount of energy needed for heating by as much as 75% in favorable climates [27]. It is
important to note, however, that the electricity produced by photovoltaic systems is highly
versatile in its end use and the ability to transport and store the energy. Additionally, an effect
that is not included in the earlier analysis is the heating of the PV cells. During operation, the
cells convert roughly 18% of the energy that strikes them. Much of the remaining energy heats
the PV material, some of which will ultimately heat the indoor air, constituting a passive heating
effect.
2.5 Conclusion
A summary of the optical efficiency with respect to vertical angle is presented in Table
2-2. One notable trend is the highest peak efficiency in the El Paso designs compared to the
other two locations for each static design. This occurs because the El Paso weighting function
Table 2-2: Vertical angle field of view summary. The left data column indicates the vertical angle field of view range for each design, the center column shows the average optical efficiency over that range, and the right column gives the peak optical efficiency.
64
has the narrowest peak. The tradeoff between vertical angle range and average efficiency is
evident as well. For each static design, it is nearly always the case that a smaller FoV range
corresponds to a higher average optical efficiency.
In order to achieve large fields of view, efficiency must be sacrificed. In fact, several of
the presented designs have peak optical efficiencies of less than 40%. The ideal balance
between efficiency and field of view depends largely on the application, and integration into a
window demands light collection from a wide range of angles. All designs improve the effective
insulation properties of the windows to varying degrees. The immersed louver design in
Rochester has a small impact and is not a viable solution. Conversely, the immersed louver in El
Paso offers a net energy loss of zero or better during much of the year, which may be a viable
product in today’s energy conscious market.
65
Chapter 3: Prototype and Metrology
3.1 Prototype
The primary goal of the prototype is to serve as a proof of concept. If the performance
measurements taken on the prototype unit match the performance of a computer model of the
prototype, the modelling techniques are validated. Further study of the model can give insights
into the loss mechanisms present in the as-built prototype.
3.1.1 Prototype Design Choice
For ease of fabrication and alignment, the prototype unit contains a single primary
optical component and injection feature at roughly a 10X scale. A baffle is also included to
incorporate the shadowing effect of the adjacent primary reflector.
The choice for which of the aforementioned designs to attempt to prototype was made
through a process of elimination based on the availability and difficulty of the required
fabrication methods. The tracking louver, for the purposes of this thesis, is prohibitively
complex to build and align due to its moving parts. The refractive design requires the very
difficult manufacture of optically clear extruded freeform surfaces. The immersed louver design
is a strong candidate since it has the best non-tracking performance and provides the least
obstructed view. However, immersing a large scale prototype unit in a dielectric material while
maintaining a small air gap adjacent to the front surface of the guide layer is a difficult task given
the available fabrication techniques. The only remaining option is the suspended louver design,
and though it does not have the best performance nor the least obstructed view, it serves as an
acceptable proof of concept and is able to lend credence to the optical modeling techniques.
66
The chosen location for the model is Rochester since it has a wider field of view than the
El Paso design and the efficiency as a function of vertical angle is less disjointed than the
Fairbanks design. Due to these features, the Rochester version is thought to be the best design
for diagnosing fabrication errors in the prototype based on performance measurements, but
likely any location choice is suited to achieving the goals of the prototype. The specific choice of
which Rochester design is based on similar merits.
An additional benefit to the chosen design is that the dimension of the prism back
surface can be extended to help make fabrication easier without interfering with the adjacent
reflector, or baffle in the case of the prototype (Figure 3.1).
3.1.2 Guide Layer Dimensions
In the full suspended louver design, the thickness of the guide layer is many times larger
than any dimension on the reflector or the injection prism, but this is impractical and
unnecessary for the large scale prototype. For the prototype, the guide need only be thick
enough so that light entering through the prism will not TIR off the back surface of the guide and
reenter the prism. With a critical angle of about 45° for the guide layer material, this means a
Back
Bo
tto
m
Top
Bottom Fr
on
t
Bac
k
Gu
ide
Prism
Baffle
Reflector
Figure 3.1: Dimensioned cross section of prototype design (lengths in mm). Shows nomenclature for faces of prism and guide. The dashed red line shows that the prism has minimal interference with light that moves past the baffle and is headed for reflector. The blue dotted lines show that the prism back can be extended without obscuring the intended optical path through the device.
PV Cell
PV Cell
67
minimum guide layer thickness of half the width of the prism bottom. Additionally, the guide
needs to be long enough so that light entering the guide via the prism at angles that do not TIR
off the guide surfaces cannot strike the PV cell surfaces before interacting with at least one
guide surface. The PV cells are located on the top and bottom faces of the guide compontent.
3.1.3 Extruded Dimension
The dimension of the prototype in the extruded direction is a balance between the
measurable azimuthal field of view and the difficulty of fabrication. A longer extrusion
dimension means that light entering the system from further off-axis in azimuthal angle can
traverse through the system without interacting with the side walls of the guide or prism.
However, manufacturing a longer prism and reflector becomes difficult to do accurately. The
extrusion dimension for the prototype is 100 mm, largely due to limitations of the fabrication
method chosen for the reflector.
3.1.4 Injection Prism Tolerancing
The prototype consists of three separate optical components: the guide layer, the
injection prism, and the reflector. The guide layer is the simplest to manufacture since it is a flat
slab of dielectric material, and it is constrained primarily by the minimum dimensions described
above. The prism and reflector present more difficulties, but the fabrication method of the
reflector is extremely difficult to control and adjust. For these reasons, tolerance analysis is
focused on the prism since there is more freedom in the choice of fabrication methods for an
optical component comprised entirely of flat surfaces.
Note that during the tolerance analysis, some simulated errors increase the expected
efficiency, however, this does not imply that the performance of the full system is improved if
68
the same error is introduced. The prototype and the full design must be thought of as disparate
systems with the prototype functioning as a proof of concept of the reflector-prism geometry
only.
In cross-section, the injection prism is a four-sided polygon with two sides, the “bottom”
and the “back”, perpendicular to each other (see Figure 3.1). The tolerance analysis performed
perturbs the two adjacent vertices that form the “top” edge of the prism. The perturbations are
parameterized into the angle between the front (α) and back (β) edges relative to the bottom
edge as well as the length of the front and back edges. The values of the dimensions as
designed can be found in Figure 3.1. Each of α and β are perturbed by ±1 degree and the
lengths of both front and
back edges are each
perturbed by ±1 millimeter
(Figure 3.2). Each parameter
is varied individually then all
four are varied
simultaneously to find the
maximum compound error in the performance of the prototype model.
The figure of merit in this study is the deviation of total irradiance on the top and
bottom guide faces as compared to the ideal geometry. This is equivalent to the relative total
power incident on the PV cells. The results show that both edge length perturbations had a
negligible effect on the prototype performance, and so they were specified to be within the
maximum range of the study, ±1 mm. The back edge is allowed to be extended further in order
to make it easier to manufacture, i.e. to create a right angle with the top edge. The angle
0
5
10
15
20
25
-40 -30 -20 -10 0
Ideal Shape
Front Vertex Variation
Back Vertex Variation
Envelopeα
β
back
Figure 3.2: Tolerance study on prototype prism dimensions. Solid blue line shows designed shape, dashed black lines show envelope of the tolerance study which is achieved by varying α, β, and the lengths of the front and back edges.
69
perturbations had a more profound effect. To limit the change in performance, the maximum
error specifications for angle α are ±0.75°. The angle β is more sensitive still and has a specified
maximum error of ±0.25°, though it only affects the performance of the bottom PV cell. The
effect of the compound errors given the above specifications are shown in Figure 3.3.
3.2 Fabrication Methods
Given the varied specifications and applications, the fabrication and metrology methods
for each component have different requirements. This section discusses fabrication methods
for the components as well as assembly of the prototype.
3.2.1 Injection Prism and Guide Layer
A primary restriction on the injection prism and the guide layer is the material. Since
both components are used in transmission, absolute refractive index and its uniformity are
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
5 10 15 20 25 30 35 40 45 50 55
Rel
ativ
e To
tal P
ow
er O
utp
ut
Vertical Angle ( ° )
Compound Error Tolerance Study
As Designed Minimum Error Maximum Error
Figure 3.3: Error envelope of tolerance study. The blue line shows the performance of the as-designed prototype, the orange line shows the minimum performance from the compound geometry errors, while the grey line shows the maximum.
70
major concerns. Anticipating the need to fabricate the system, the material used in the
computer model is poly(methyl methacrylate), and is indeed the choice for the real world
prototype. Poly(methyl methacrylate), or PMMA, is more commonly known as acrylic or by one
of its trade names, e.g. Plexiglas [28]. PMMA is easily and inexpensively sourced in bulk, and is
machined and polished with relative ease. Like many of the physical properties, the refractive
index can vary depending on the plastic’s specific formulation, but it is typically around 1.49 in
the visible spectrum. This has been verified for the fabricated prism and guide layer using a
refractometer (see Section 3.3.1.3) which measured an index of about 1.489 at a wavelength of
632.8 nm, matching published data [29]. Amongst typical optical glasses, PMMA would be
considered a crown, i.e. a low index and low dispersion material.
The fabrication method used for both the prism and guide is a milling procedure,
common for creating structures out of metals and plastics. The faces are then buffed to remove
surface roughness caused by the milling bit. This is not a common fabrication method for
optical components due to the relatively imprecise reproduction of the surface geometry and
high surface roughness. However, due to the fact that all surfaces were designed to be flat, the
loose tolerances on the component dimensions, and the non-imaging nature of the prototype
device, this fabrication method proved to be adequate.
Stock PMMA material is often in the form of flat plates, and the factory-produced faces
are usually optically smooth and fairly flat. In order to increase the chances of a successful
prototype, all of the faces of the prototype components that are used in reflection (back of the
prism, and front and back of the guide) are chosen to be factory faces of the original bulk
material. The reason for this is that surfaces used in reflection are more sensitive to slope errors
71
than refractive surfaces, and subjugating them to the milling process would have created a
much rougher finish.
To further ease the fabrication process for the prism, its “top”
face is rotated to be perpendicular to the “back” face (Figure 3.4). This
adds material that is not part of the optical path of the device, but does
not interfere with intended path of the light. The three perpendicular
faces are more conducive to the milling process with only one face at a
non-right angle to the others.
In order to create a mirrored surface on the prism, aluminum is used in a physical vapor
deposition (PVD) process. The PVD process used does not have precise control over the layer
thickness or uniformity, so some variation in thickness across the surface is expected.
3.2.2 Reflector
The reflector requires unorthodox fabrication methods to remain cost effective due to
its unusual shape. Precision methods such as diamond turning, injection molding, and slump
molding are cost prohibitive. Though not yet widely used in the field of optics, an additive
manufacturing method was chosen to create the shape of the reflector. Specifically, a Form1+
desktop 3D printer from FormLabs [30] is used to create the freeform surface along with its
supportive structure. This printer is based on selective laser sintering technology where each
layer of the part to be printed is created out of a liquid polymer resin that is selectively cured
using a UV laser and two galvanometer mirrors. It is capable of reproducing geometrical
features as small as 300 µm, with layer thicknesses down to 25 µm. While these specifications
are top of the line in desktop 3D printing, they are far from good enough to recreate an optical
Figure 3.4: Cross-section of prism shape modified for the milling fabrication process. The red dashed line indicates the unmodified shape.
72
surface for use with visible light. The printed surfaces are
very rough on the microscopic level and not suitable as a
reflector without post-processing.
In order to create a smooth, reflective surface,
several methods were considered. The chosen method
adheres a reflective Mylar film to the printed surface
(Figure 3.5, bottom). Mylar is a thin polyester film that is
metallized with aluminum using a vapor deposition
process [31]. The process of drawing the polyester into a
sheet creates surfaces that are smooth enough to be used
in optical applications. The reflectivity of the aluminum
layer depends on its thickness, but is often similar to bulk
aluminum, around 90%, since the skin depth for visible
wavelengths is less than 5 nm [32].
The thickness of the plastic film is another important factor for this research. If too thin,
the film picks up the higher spatial frequency roughness of the printed surface to which it is
adhered. If too thick, it is more difficult to flatten the film onto a surface that may be curved in
two directions, e.g. if the printed part is not perfectly flat in the extrusion direction. Mapping a
flat surface to a curved one is a well-known problem in the fields of projective geometry and
cartography [33]. If a surface is curved in a single direction, it can be mapped to a flat surface
without distortion. However, if the surface is curved in both directions, distortion is a necessary
byproduct of mapping that surface to a flat plane. This is the same problem encountered when
attempting to draw a world map on a flat surface as opposed to a globe. A thicker piece of
Figure 3.5: Modeled (top) and 3D printed (bottom) reflector with reflective Mylar film adhered to surface. Printed part is a first full scale manufacturing attempt with visible flaws in the surface.
73
Mylar is more resistant to stretching and conforming to the 3D printed reflector surface if is not
completely flat in the extrusion direction.
The Mylar film sourced for this prototype has a thickness of about 40 µm and is coated
with aluminum on a single side. It is used as a first surface mirror with the aluminum coating
opposite the reflector structure since the film appears slightly more diffuse when used as a
second surface mirror.
The final component of the reflector is
the adhesive used to join the 3D printed
structure and Mylar film. Several different
adhesives were investigated, and it was quickly
found that adhesives that hardened and shrank
as they set are not plausible options. These
adhesives cause the Mylar surface to become
rough and diffuse as it shrinks and stretches with
the adhesive as it did for the “SC” and “LT”
adhesives in Figure 3.6. Adhesives that remain
flexible are more appropriate for this application as the surface distortion is much reduced.
Rubber cement (“RC”) fairs well, but after a long dry time it creates dimples in the Mylar
surface. The best option found is a silicon-based adhesive, as the Mylar remains visibly
undistorted even after long dry times. “GE” of Figure 3.6 is a silicone sealant meant for
construction applications. The adhesive used in the prototype is a silicon elastomer from NuSil
meant for encapsulating electronic components [34].
Figure 3.6: Mylar adhesive trial. "SC" and "LT" represent glues that harden as they set, and cause the Mylar to become diffuse as a result. "RC" (rubber cement) and "GE" (silicone sealant) both stay somewhat flexible as they set, allowing the Mylar surfaces to remain smooth.
74
The process of adhering the Mylar film is done
manually using a roller to create a thin, relatively even layer
of adhesive. First, the bare reflector surface is wetted with
the uncured silicone elastomer. Care is taken to remove as
many air bubbles as possible from the adhesive before
proceeding. An oversized piece of Mylar film is wrapped
around a roller, in this case a large opto-mechanical post,
with a piece of paper in between to protect the reflective
surface during assembly. The roller is placed at one edge of
the curved surface and rolled towards the opposite edge
while laying down the Mylar and squeezing out excess
adhesive. The roller is then moved back and forth over the
part several times to ensure good lamination of the
component layers. After the silicone is set, the excess Mylar film is trimmed back to the edge of
the reflector structure using a razor blade.
The assembly becomes problematic when the extrusion direction is curved since the
straight roller cannot press evenly over the entire surface. This often results in pockets of
silicone or air in the low areas, creating large bubble-like features in the laminated surface. This
is the case for the reflector shown in Figure 3.5, where the part is slightly concave along the
extrusion direction and the Mylar has visibly deformed, especially in the center portion of the
part.
Figure 3.7: 3D printed reflector structure secured to an optical bench (top), and a roller with Mylar sheet and protective paper layer (bottom).
75
The printed reflector structures tend to warp and become concave in the extrusion
direction as they dry. To combat this effect, the final prototype reflector was printed as a
slightly convex surface in the extrusion direction so it would flatten as it dried.
3.2.3 Photovoltaic Cells
The PV material best suited to this design is silicon due to the low concentration ratio.
For the prototype, mono-crystalline silicon wafers are diced to an appropriate size to cover the
edge of the guide layer component while leaving some extra area for solder joints on the active
face of the cells. The conductor on the front face of the cells is a sliver-based screen printed grid
of lines as seen in Figure 3.8. The
thicker horizontal gridlines create low
resistance pathways for electrical
current extraction, but also inhibit
incident light from reaching the silicon
PV material. The numerous, thin,
vertical gridlines create a more
uniform functioning of the cell, but
individually have higher electrical
resistance.
The ideal dicing geometry
avoids the thick gridlines on the area
of the cell that attaches to the guide edge, but has a thick gridline running parallel to the length
of the cell adjacent to the active area (pictured as a red outline in Figure 3.8). Unfortunately,
Figure 3.8: A silicon wafer with conductive gridlines. Red box indicates ideal dicing lines and the green, the necessary dicing lines due to the crystal lattice orientation. Dashed lines indicate extra diced cell area that does not contact the guide layer edge in the prototype assembly, leaving room for solder connections.
76
the wafers sourced for this project have a crystal lattice orientation such that the material
preferentially breaks at a roughly 45° angle to the gridlines. As such, the best possible dicing
geometry leaves an area free of thick gridlines near the middle of the cell, pictured as a green
outline in Figure 3.8. In order to ensure the best possible extraction of electrical current, leads
are soldered to both thick gridlines on the face of the cell and in similar positions on the rear of
the cell.
3.2.4 Assembly
The prototype assembly is a three step process consisting of joining the prism and guide
layer, mounting that subassembly along with the reflector, and attaching the PV cells.
3.2.4.1 Joining Prism and Guide Layer
The primary consideration for joining of the two refractive components is how to
optically couple the adjacent surfaces. Since neither adjoining surface is completely flat, an
intermediate liquid is used to fill in the gaps. Ideally this medium is of the same refractive index
as the parts it is joining so that light passing through this interface does not experience any
change in refractive index. Finding an index matching fluid with precisely the correct properties
is often impossible, especially for multiple wavelengths. However, a fluid with a nearly matched
index is sufficient for this application. Additionally, the prism and guide layer are attached with
machine screws for mechanical stability, so the index matching fluid need not serve as a
structural adhesive.
The first attempt at joining the prism and guide used a UV curable resin formulated
specifically for matching PMMA once set. Before curing, this resin has an index of
approximately 1.46 in the visible wavelengths and has a low viscosity similar to cooking oil. The
77
curing process increases the index to 1.49, matching PMMA. Unfortunately, the curing process
is made difficult by the large thickness of the PMMA parts that absorb UV wavelengths before
they can reach the resin. Before the resin could set, the UV source heats the PMMA parts
enough to warp them and create air pockets in the resin layer. If left uncured, the resin escapes
the interface due to its low viscosity in addition to maintaining a low index of 1.46. The resin
was rejected as a possible solution.
During the cleaning process to remove the resin, crazing of the guide layer was revealed
where it had been in contact with the uncured resin for a prolonged period. Crazing is a
phenomenon in plastics where local stresses are able to overcome the forces bonding the
molecules in the material, creating narrow fissures [35]. Some light that interacts with these
features is scattered, making them visible under certain illumination conditions. It is sometimes
possible to remove the surface crazing from thermoplastics by heating the material with a
blowtorch to reduce the internal stresses that prevent the fissures from closing. However, this
was not attempted due to the risk of damage to the part.
Ideally, a silicone gel would be used in this interface for its known stability in under solar
illumination, but it is not available with an index near that of PMMA. The final choice of index
matching fluid is Karo corn syrup. While not a conventional material in optical systems, it
satisfies the requirements of this application well. The high viscosity helps prevent the material
from flowing out of the interface, and its refractive index closely matches that of PMMA. The
corn syrup is measured with an Abbe refractometer (Section 3.3.1.4) and determined to have a
refractive index of 1.4832 ± 0.0005 at the Helium “d” Fraunhofer line, 587.6 nm.
78
3.2.4.2 Reflector Mounting
The next assembly step mounts the
reflector and refractive subassembly together
while providing the hardware necessary to
mechanically mount the finished prototype to a
rotation stage. Two custom braces are designed
to fit on the end caps of the prototype on either
side of the extruded dimension (Figure 3.9d,
pictured in red). The braces have features that
position the guide and prism subassembly relative
to the reflector surface and a baffle that simulates
the shadowing of an adjacent reflector. Set screws hold all the components in place. The two
braces are connected with a threaded rod and essentially create a clamp to form a rigid
prototype structure.
A hole in the brace is positioned at the vertical center of the prototype’s entrance
aperture and provides a place to mount the prototype to a rotation stage on axis. This way, as
the rotation stage moves during the measurement process the entrance aperture center
position remains nearly constant. The mounting structure also provides mechanical clamps to
keep the PV cells positioned after they are placed during assembly and a wire management
structure to handle the eight wire leads attached to the PV cells.
(a)
(b)
(d)
(e)
(c)
(f)
Figure 3.9: Exploded view of prototype assembly with (a) prism and guide in green, (b) reflector in grey, (c) baffle in black, (d) structural braces in brown, (e) PV cell clamp components in yellow, (f) wire management hanger in black, and (g) and (h) indicating the top and bottom PV cell locations, respectively.
(g)
(h)
79
3.2.4.3 Attaching Photovoltaic Cells
There are two PV cells, one for each
output edge of the guide layer, and each cell
has four wire leads as previously described.
The cells are weak and brittle, and they tend
to warp after being diced. The solution for
mounting the cells is to include two clamps
that contact the back of the opposing cells to
sandwich the top cell and the bottom cell
with the guide layer in between. The UV
curing resin that was utilized in the first prism-guide assembly attempt is placed between the
cell and guide layer edge to achieve good optical contact. The prototype is placed under a UV
lamp in a final attempt to cure the resin and secure the cells, but most of the resin remains fluid.
The clamp structure is enough to keep the cells in the correct positions.
During assembly, good optical contact can be easily assessed with the unaided eye, as
bubbles in the liquid layer appear with great contrast since TIR selectively occurs in those areas
(Figure 3.10). The liquid layers allow light to couple out of the guide and interact with the cells
with maximum efficiency. If there were an air interface
between the cell and the guide, Fresnel losses would occur at
the guide-air surface as well as the air-cell interface. The
Fresnel losses would be severe given the high index of silicon,
around 4.0 in the visible [36]. For this reason, the sourced
Figure 3.10: PV cell optical contact trial (top) and in the prototype looking through the length of the guide layer (bottom). Top: the darker regions of the cell are area of good optical contact with the PMMA cover plate and the lighter areas have poor contact. Bottom: good optical contact in the prototype assembly.
Figure 3.11: Magnified view of PV cell surface showing a ridged texture running perpendicular to the small gridlines.
1 mm
80
silicon cells have a textured front surface that helps combat Fresnel losses as seen in Figure
3.11.
3.3 Metrology Tools
This section introduces the metrology instruments used to measure the prototype
components as well as the full assembly. Special attention is given to the fringe reflection
deflectometer since it is a one-of-a-kind apparatus, built specifically for this project.
3.3.1 Commercial Instruments
This section briefly describes the commercially available metrology instruments used
during for the prototype component measurements. Details about each instrument can be
obtained from the manufacturers, and is thus not presented here.
3.3.1.1 Zygo Verifire PE Interferometer
The Zygo Verifire PE is a versatile laser interferometer system capable of measuring flat
and spherical surfaces in reflection [37]. The source has a high spatial and temporal coherence,
so it is most useful for measuring large, smooth parts. It is used to measure the flatness of the
calibration mirror for the deflectometer apparatus discussed later. This interferometer could
not obtain good data from most of the prototype component surfaces since they are too rough,
or have too large a departure from flat.
3.3.1.2 Zygo NewView 600 White Light Interferometer
Unlike the laser interferometer, the Zygo NewView 600 [38] white light interferometer
uses a source that has a small temporal coherence and a precision scanning stage. Due to the
low coherence, fringes are only visible over a small range along the optical axis, and as the
81
scanning stage moves, the fringes are visible at different depths on the test surface. The end
result is a system with high depth resolution, even on rough surfaces. Unfortunately, the active
measurement area is several orders of magnitude smaller than the laser interferometer, on the
order of 0.1 mm2.
This instrument is most useful for gaining information about surface roughness as well
as small topical features. It is used to measure the surface quality of the PMMA components
and the Mylar.
3.3.1.3 Metricon Model 2010/M Refractometer
The Metricon Model 2010/M [39] is a refractometer that measures the critical angle of
an interface comprised of a high index prism and the sample material. The prism’s index is well
known and the critical angle is found by measuring the power in a reflected beam as a function
of incidence angle. Once the critical angle is found, the index of refraction of the unknown
sample is calculated. This instrument is used to verify the index of the PMMA prototype
components.
3.3.1.4 Abbe Refractometer
Abbe refractometers measure the index of refraction of an unknown material by
measuring the critical angle at an interface between a known high index prism and the unknown
material. This instrument is very similar to the aforementioned Metricon, but is more
appropriate for measuring fluid media.
3.3.1.5 Optical Gaging Products SmartScope Quest 300
The SmartScope Quest is a line of coordinate measurement machines (CMMs) that use
one of a variety of sensing methods to detect discreet points on a surface [40]. The method
82
used for this research employs optical interference to find the position of a surface without
physically contacting the part. High precision stages move the part in three dimensional space
and the point data is recorded. The SmartScope is used in the measurements of the reflector
surface shape prior to applying the Mylar film for comparison with the data from the fringe
reflection deflectometer discussed next.
3.3.2 Fringe Reflection Deflectometer
The primary reflector prototype component is a highly specular freeform surface that
has significant figure errors, no common focal point, and deforms when small pressure is
applied to certain areas. Traditional optical metrology is not capable of measuring such a
surface with a large departure from spherical and no focal point. A contact profilometer risks
deforming the surface if it passes over an air pocket under the Mylar film, and the stylus could
damage the first surface coating on the Mylar.
After a review of measurement techniques for freeform surfaces [41] a structured light
system was chosen as an appropriate technology for this application. Structured light systems
come in two major categories: projection and reflection. The former projects a patterned light
beam onto the part to be measured and a camera images the light scattered from the part. The
images are analyzed to reveal the shape of the part’s surface in three dimensions.
Unfortunately, this system is not compatible with specular surfaces, but the other category of
structured light system uses reflections from a surface instead of scattered light. While this is a
less direct system for measuring points on a surface, it is far more sensitive to surface slopes.
One study shows that such systems are capable of measuring feature depths to an accuracy of 1
nm [42]!
83
Current applications of this technology include qualitative fabrication flaw detection for
parts such as automobile body panels [43]. Applications that involve quantitative reconstruction
are less common and are very much still in the research stage. For example, the Software
Configurable Optical Test System (SCOTS) from the University of Arizona focuses on the accurate
reconstruction of optical surfaces, often ones with large apertures [44].
3.3.2.1 Hardware
The hardware needed for a basic reflective structured light system is widely and
inexpensively available: a camera, a flat digital display (e.g. LCD computer monitor), and a
computer for control, data acquisition, and analysis. Additionally, a mirrored calibration flat
with at least five fiducial points is needed to build the system presented here.
The display is a Dell UltraSharp 2009W with a resolution of 1680 by 1050 pixels, a pixel
periodicity of 0.258 mm in both the horizontal and vertical directions, and has a 20 inch diagonal
[45]. This display is large enough to capture all reflections off of the prototype reflector from
the point of view of the camera. For maximum accuracy, it is necessary to have a linear
relationship between the output of the monitor and the pixel brightness as perceived by the
camera. However, the chosen display has a nonlinear response which changes depending on
the angle from which each pixel is viewed. The steps taken to mitigate the nonlinearity are
outlined in section 3.3.2.3.
The deflectometer uses an Allied Vision Marlin F-201B monochrome machine vision
camera with a sensor resolution of 1628 by 1236 pixels and a pixel pitch of 4.4 µm. The lens is
an off-the-shelf TV lens with a nominal focal length of 25 mm for which the aperture stop is set
to the minimum diameter so as to increase the depth of focus during operation. Ideally, the
84
lens would be telecentric so that the image does not shift depending on object’s distance from
the focal plane in object space. The lens used is not telecentric, which introduces error into the
final data since the entire part surface does not exist in a single focal plane.
The computer includes MathWorks® MATLAB computational software for which the
deflectometer code is written. It controls the monitor display and
the camera for data acquisition and analyzes the resulting data.
Finally, the calibration flat is a first surface mirror with nine
disk-shaped fiducial marks arranged in a 3 by 3 grid (Figure 3.12).
The relative positions of the fiducials are obtained via a measuring
microscope. The fiducials were created by ablating the surface with a CO2 laser writing system.
In order to avoid rigid mounting of the calibration flat and the part to be measured, the
monitor is suspended above the
tabletop facing down, and the camera
is looking down at a portion of the
tabletop that is underneath the
monitor, as pictured in Figure 3.13.
This way, the calibration flat and
measured parts may be set on the table
surface and held in place by gravity.
The monitor mount is vertically
adjustable so the distance from the
part to the display is variable.
Camera
Monitor
Part to measure
Monitor stand
Figure 3.13: Fringe Reflection deflectometer schematic showing relative positions of the monitor display, camera, and reflective part.
Figure 3.12: Deflectometer reference flat mirror.
85
3.3.2.2 Operation Summary
The operation of the fringe reflection deflectometer consists of three stages: calibration,
data acquisition, and data processing. The details for each stage can be found in the following
sections.
The primary goal of calibration is to find the relative position and orientation of the
camera and monitor in three dimensional space. This is done using the camera to image a
minimum of five coplanar fiducial points on the calibration flat. Given the relative fiducial
positions, the best fit rotational and translational transformations are found describing the
relative position of the camera and fiducial plane [46]. Additionally, the focal length and the
radial distortion of the camera lens are calculated. This process is used once to locate the
calibration flat and again to locate the reflection of the monitor off of the calibration flat’s
mirrored surface. The real position of the monitor is then calculated.
The data acquisition stage replaces the calibration flat with the part to be measured.
The fundamental goal is to map each pixel of the camera that is viewing the part surface to a
position on the monitor. This is done by displaying a short series of patterns on the monitor and
recording images of the part surface illuminated by each pattern.
The data analysis stage begins by calculating the coordinates on the monitor seen by
each camera pixel using knowledge of the patterns displayed during data acquisition. Then the
shape of the part surface is found using geometrical arguments and some justified assumptions
about the surface.
86
3.3.2.3 Monitor Nonlinearity Mitigation
To illustrate the magnitude of the nonlinear response of the monitor, the
deflectometer’s camera is pointed directly at the monitor from five different viewing angles:
normal to the screen, and from an angle of about 45 degrees looking down from above, up from
below, and horizontally from the left and right. Data are taken at each position while increasing
the input to the monitor and recording the brightness as perceived by the camera. These data
describe the response function between the camera and the value output by the computer.
Both the monitor and the camera run in 8-bit mode so the displayed and recorded values are
discretized to whole numbers between 0 and 255.
The data from this study
are seen in Figure 3.14. Notice
that the data at normal incidence
as well as that from the left and
right perspectives have similar
shapes, but all are nonlinear.
Much of this nonlinearity is an
intentional effect implemented
by the computer’s display driver.
Given the logarithmic response of the human eye, displays often implement what is called
gamma encoding to the display signal so that the output intensity appears more linear to human
viewers. Gamma is simply an exponent on the value to be displayed (𝐼𝑜𝑢𝑡 = 𝐼𝑖𝑛𝛾), and is often
chosen to be around 2.2 for input values between 0 and 1 [47].
Figure 3.14: Camera response to monitor input values for several viewing angles using default display settings.
Mea
sure
d In
ten
sity
Input Value
87
More problematically, the data from the above and below viewpoints are significantly
different from each other and from the other three perspectives. Further still, the slope of the
data from below actually changes sign around an input value of 100, making it impossible to
create a one to one mapping between input and output. In other words, looking from below,
the pixels actually appear to become dimmer as the input value is increased over a portion of
the full range. This is an effect that is also detectable by the unaided eye. The source of this
error is unknown and not intuitive, but may have to do with the color balance among display’s
red, green, and blue subpixels while a white pixel is being displayed and its value is increased.
Several measures are taken to create a more linear response between the camera and
monitor at different viewing angles. First, the display driver gamma values are readjusted so the
camera perceives a nearly linear increase in brightness from normal incidence. Second, two
films, the vertical brightness enhancement film and a textured light recycler film, were removed
from the LCD display stack which modified the angular output of the device. Third, the monitor
is operated with an increased minimum and reduced maximum pixel value in order to utilize
only the most linear region of the response curves. Finally, the monitor, camera, and part to be
tested are oriented in such a way that the monitor is rarely seen “from below” in order to avoid
the most egregiously nonlinear viewing angles.
The results of all the above adjustments are shown in Figure 3.15. The greyed out
ranges in the top graph indicate unused pixel value regions. Notice the normal, left, and right
viewing angles are very nearly linear within the chosen range. The phase error in the bottom
graph of Figure 3.15 is calculated for a system that uses a four step phase shifting algorithm as
does this deflectometer. The phase error is related to a lateral position error on the monitor
and is discussed further in a later section. Notice that the phase error has a period that is one
88
quarter that of the actual phase, an
effect that is observable in the data
generated by this apparatus.
The color-coded shaded
regions on the bottom graph
indicate an estimated range of the
phase error based on the noise in
the measured data. The viewing
angle from the right is omitted since
it is very similar to that from the
left. The data from below are of
much greater amplitude and
somewhat nonsensical due to the
highly nonlinear and inverse nature
of the response curve, and are also
omitted since that viewing angle is
avoided during operation of the
deflectometer.
Recall that the non-normal viewing angles are at a fairly severe 45 degrees. For most
measurements, the apparatus can be configured to have lower incidence angles during data
acquisition, further reducing the severity of the phase error.
Figure 3.15: Camera and monitor response curves with modifications (top), and the calculated phase error based on the nonlinear response (bottom). The phase error is based on a four step phase shifting algorithm and the shaded region estimate the error based on the noise in the measured data.
89
3.3.2.4 Calibration
The calibration procedure follows a 1987 publication by R. Y. Tsai for the case of
coplanar fiducial marks and a single captured frame [46]. This method finds a three dimensional
rotation matrix and a three element translation vector to map the coordinate system of the
fiducials to the camera’s coordinate system. This mapping is defined as
[𝑥𝑦𝑧
] = 𝑅 [
𝑥𝑤
𝑦𝑤
𝑧𝑤
] + 𝑇 ,
where (xw, yw, zw) is a point in the fiducial coordinate system, (x, y, z) is a point in the camera
coordinate system, R is a 3 by 3 rotation matrix, and T is a three element translation vector. The
camera is simplified to a pinhole geometry with the addition of a single radial distortion term
(r2). The focal length of the lens, f (i.e. the distance from the pin hole to the image plane), and
the distortion coefficient, κ1, are calculated along with R and T.
First, the camera records an image with the fiducials visible, and the fiducials are
identified in the software with the help of user input. This defines the pixel positions of each
fiducial from which a physical position on the sensor is calculated given the sensor array
geometry and dimensions. The lens distortion is assumed to be zero until the final step of the
process.
From this data, the entire orthonormal rotation matrix is calculated along with the first
two components of the translation vector which control position perpendicular to the camera’s
optical axis. This calculation requires there be at least five fiducial marks, and uses a least
squares solution for greater than five fiducials.
90
Next, a linear relationship between the lens focal length and the third component of the
translation vector (Tz , distance along the camera’s optical axis) is leveraged to find an initial
guess for these two quantities. The lens distortion is still assumed to be zero at this step.
Finally, f, Tz ,and κ1 are varied in an optimization scheme with a merit function that
compares the actual pixel positions of the imaged fiducials to the calculated positions using R, T
(including Tz), f, and κ1.
This method is first applied to the reference flat pictured in Figure 3.12 to find its
position and orientation relative to the camera along with the lens focal length and distortion
coefficient. The monitor displays a solid white image to obtain the highest contrast of the
optically absorbing fiducials.
Then, the monitor displays
solid black and the user is asked to
draw white dots on the display so
that they can be seen in the reflective
surface of the reference flat (Figure
3.16). These white dots act as
fiducials on the monitor and their
position is calculated through the
known pixel positions and pixel pitch
of the monitor. The above method is
applied to the new set of fiducials to
find the position of the monitor’s reflection relative to the camera. The lens focal length and
distortion are taken from the previous step and are not recalculated.
Figure 3.16: Deflectometer calibration during monitor reflection positioning step. Shows (a) drawn fiducials on monitor, (b) reflection of drawn white fiducials and black mirror fiducials on calibration flat, and (c) camera.
(a)
(b)
(c)
91
Now that the position of the reference mirror and the monitor’s reflection are known,
the real position of the monitor is calculated. To maintain a calibrated state, the positions of the
camera and monitor must remain fixed and the focus position of the lens must not be adjusted,
but the calibration flat may be removed.
3.3.2.5 Data Acquisition
The calibration flat is replaced with the part to be measured. In order to find the
position on the monitor that each camera pixel sees reflected off the part surface, a four step
algorithm is borrowed from phase shifting interferometry [48]. For this method, sinusoidal
fringes are displayed on the monitor and four images are recorded, shifting the fringes by a
phase of π/2 between frames. Example data of the prototype reflector is shown in Figure 3.17.
If I1, I2, I3, and I4 are the values of a single pixel for the images with a fringe phase shift of 0, π/2,
π, and 3π/2, respectively, the modulo 2π phase, φ, of that pixel is calculated as follows:
𝜙 = 𝑡𝑎𝑛−1 [𝐼4 − 𝐼2
𝐼1 − 𝐼3] .
Figure 3.17: Reflection of horizontal fringes from prototype reflector as recorded by camera. From phase shift of the fringes from left to right is 0, π/2, π, and 3π/2.
92
This calculation is done independently for each camera pixel, meaning the fringe apexes do not
need to be located to obtain the phase. Additionally, a constant background signal and constant
scaling do not affect the calculated phase, so if the reflections from one area are not as bright as
they are from of another area, the calculation is still valid [48].
During the data acquisition procedure, the best lateral resolution is gained by focusing
on the part surface, so the pattern on the monitor is out of focus [43]. However, given the
theoretically singular spatial frequency composition of sinusoidal fringes, an out of focus image
of this pattern is still sinusoidal with the same frequency and phase [49, 43]. The main concern
then becomes the signal to noise ratio, which will decrease with more defocus. The defocus is
advantageous by effectively eliminating the possibility of resolving individual pixels on the
display, producing a smooth, continuous sine pattern.
The period of the fringes is chosen to be as short as possible while retaining fringe
contrast, so a given error in the detected phase (e.g. Section 3.3.2.3) is less significant when
converted to spatial coordinates on the monitor. Once again, loss of signal to noise ratio limits
how short the period may be.
The phase calculated by the four step
algorithm in this case relates to a position on the
monitor’s screen. To gain knowledge of the two
dimensional position on the monitor, two sets of
fringes must be recorded: one for the horizontal
position (vertically oriented fringes), and one for
the vertical position (horizontally oriented
fringes). Since the calculation only gives the
Figure 3.18: Pixel line data for the calculation of absolute position. Horizontal (left) and vertical (right) lines are shown. These images are superimposed with another photo of the part so the part outline is visible.
93
relative phase of each camera pixel, two more images are acquired that reveal the absolute
position on the monitor. This is done by displaying a single line of pixels at a known position
with a vertical line orientation in one image, and a horizontal orientation in the other (Figure
3.18).
Finally, an optional frame is captured where calipers are set on the part’s surface and
the distance reading is recorded. This may serve as a reference distance during data analysis.
Thus, a total of eleven frames are captured during this stage.
3.3.2.6 Data Analysis
The wrapped phase (modulo
2π) on the part surface found via the
aforementioned four step algorithm
[48] is unwrapped using publicly
available “PUMA Algorithm”
software [50, 51]. Figure 3.19
shows the wrapped and unwrapped
phase for the prototype reflector. This phase is translated into absolute position on the monitor
using the information from the frames that captured the single horizontal and vertical lines
displayed on the monitor.
At this point, an inverse propagating ray can be traced for each camera pixel from the
camera origin towards the part, and the ray position on the monitor after reflecting off of the
part surface is now known. To calculate the part’s surface geometry, the distance the ray travels
between the camera and the surface must be calculated. Unfortunately, this is a
Figure 3.19: Results of PUMA phase unwrapping algorithm performed on the horizontal fringe data for prototype reflector. Wrapped phase [-π, π] (left) and unwrapped phase (right).
94
mathematically ill-posed problem with infinite
solutions for each pixel (Figure 3.20), and is an active
research topic in machine vision [42]. The ambiguity
comes from the fact that the ray directions at the
monitor surface are unknown.
To remove the relative ambiguity amongst all
the data points on the surface, it is assumed to be
continuous and smooth over the distance separating
adjacent data points. These assumptions are
integrated using a slope equalization technique
borrowed from the field of wave-front sensing [52].
First, an initial guess is made for the distance (σ) between the surface and the camera origin for
each camera pixel. This guess is based on the designed geometry of the surface and the position
of the reference mirror during the calibration stage. The slope of the surface is calculated at
each data point given the knowledge of where the ray strikes the monitor. The slope is broken
into components in the vertical and horizontal directions with respect to the camera pixel array
dimensions. Slopes of horizontally and vertically adjacent data points are averaged to calculate
the slope between them. The slope between horizontally and vertically adjacent data points is
separately calculated based on their σ values and the distance between them. The solution
matches these two slope quantities as closely as possible over the entire surface by adjusting
the σ values of each data point. A simplified illustration of the slope equalization calculation is
shown in Figure 3.21. This solution finds the relative σ of all data points, and additional
information is needed to determine absolute position.
Figure 3.20: Illustration of multiple solutions to surface position problem. The solid red line is the known ray coming from the camera, the green patches are possible surface positions with the black arrows indicating the surface normals.
95
Note that there exist two distinct coordinate
systems: 3D Cartesian coordinates and a spherical
coordinate system defined by σ and the pixel position
on the camera sensor. A surface with constant σ is a
spherical shell centered at the camera origin, and the
two dimensional pixel position determines the
position on that shell. Care must be taken to
transform all slopes into a single coordinate system
before solving the least squares problem. The
camera’s coordinate system is chosen for this apparatus since it provides a more direct solution
using the mathematical methods in [52].
To find an absolute distance from the camera, a constant is added to all data point
distances so that a physical measurement of the part (e.g. from the picture of the calipers) is
maintained in the reconstructed data. In the wave-front reconstruction analogy, this would be
equivalent to adding a piston term, which does not affect the wave-front shape.
The solution depends highly on the initial guess of the σ values, so the process is
iterated using the previous iteration’s calculated values as the new initial guess. In practice, the
solution converges very quickly, within 3 to 5 iterations.
Finally, once the surface shape is reconstructed, it is registered to a position that is
consistent with the part as it was originally modeled and the departure from the ideal surface
shape is calculated.
S1
S2
S12
σ1
σ2
Figure 3.21: Illustration of two different slope calculations. S1 and S2 are the slopes calculated from the monitor position reflected in the part, and S12 is the slope calculated from the positions of the data points. In this example, to get the average of S1 and S2 to equal S12, σ2 will need to increase relative to σ1.
96
3.3.2.7 Sources of Error
The primary sources of error in the fringe reflection deflectometer are calibration error,
variable nonlinearity of the display, and noise in the captured image data. As previously
discussed in section 3.3.2.3, the monitor nonlinearity varies depending on the viewing angle
causing an error in the measured phase. The phase is also adversely affected by noise in the
captured images. The signal to noise ratio is maximized by adjusting the exposure time of the
camera and the fringe period on the display for high contrast. Additional noise is inherent in the
discreet, 8-bit nature of the monitor pixel brightness and the camera’s digital sensor.
Calibration error refers to an inaccurate knowledge of the position and orientation of
the display surface relative to the camera. This will affect the geometrical calculations in the
data analysis stage. This error is very difficult to quantify, partially due to the virtual nature of
the camera origin. The calibration error also includes uncertainty in the calculated focal length
and distortion coefficient of the camera lens, which directly impact the ray directions associated
with each camera pixel. Calibration error can stem from a variety of sources including
inaccurate measurement of the calibration flat fiducials, a curved calibration flat, a curved
display surface or camera sensor, tilt or decenter of the camera sensor relative to the lens, or
inconsistent spacing of pixels on the display or camera sensor. The flatness of the calibration
mirror is simple to measure using the Zygo laser interferometer introduced earlier. The results
are seen in Figure 3.22, and they reveal a cylindrical bend in the mirror, but the amplitude is a
mere 1 µm over a distance of 100 mm. The effects of such a defect pale in comparison with the
nonlinear response of the monitor, for example.
97
The cumulative error in this system is
noticeable in the final measurements, but the
result is accurate enough to yield a robust
computer model of the large scale prototype. The
subsequent chapter presents data from the
deflectometer and compares it with similar
measurements performed via established, highly
accurate methods.
3.3.3 Solar Simulator
Given the varying properties of sunlight
and the difficulty of accurately tracking the sun as
it moves across the sky, the assembled prototype is tested in the laboratory under controlled
illumination meant to simulate sunlight. The apparatus is referred to as a solar simulator which
ideally mimics the sun in angular extent, spectral power distribution, and absolute irradiance.
However, it is difficult to simultaneously meet all three of these requirements with currently
available light sources. The solar simulator employed for this research satisfies the angular
extent and spectrum specifications fairly well, but has an irradiance that is approximately 20%
that of the sun on a clear day. This is a suitable device for relative power measurements.
The solar simulator uses a xenon short arc lamp with an integrated parabolic mirror.
This is a well-suited source since it is bright and the spectrum closely matches that of the sun
Figure 3.22: Calibration flat measured in a Zygo laser interferometer. A cylindrical bend can be seen over the aperture of the part with a peak to valley departure of about 1 µm. The bottom graph shows the slice chart indicated by the line in the top graph.
98
with the exception of excess power in
the near infrared (Figure 3.23), a defect
which can be filtered out. The
integrated parabolic reflector creates a
roughly collimated output from the
bulb. This beam is focused by a singlet
lens into a straight integrating rod with
a hexagonal cross section. The
integrating rod mixes the beam to
create a spatially and angularly uniform output. The output face of the integrating rod is placed
at the focus of a large off-axis parabolic mirror which collimates the light with a finite angular
extent. Angular extent of the final beam is determined by the focal length of the mirror and the
size and shape of the rod’s output face. The size of the mirror determines the size of the output
beam, and the F-number of the aforementioned focusing lens is chosen so that the mirror’s
aperture is not significantly over- or under-filled.
0
1
2
3
4
5
6
7
8
9
10
0 500 1000 1500 2000 2500
Re
lati
ve S
pec
tral
Po
wer
Dis
trib
uti
on
Wavelength (nm)
Xenon Lamp Sunlight on Earth's Surface
Figure 3.23: Comparison of the spectral power distribution of sunlight after passing through Earth's atmosphere and a xenon arc lamp.
Focusing Lens
Integrating Rod
Off-Axis Parabolic
Mirror
Test Area
Figure 3.24: Schematic of solar simulator with labeled components. Path of light though system shown in yellow.
99
A schematic of the solar simulator is shown in Figure 3.24, where “Test Area” signifies
position of the prototype during testing. The solar simulator is combined with computer
controlled translation and rotation stages and electronic source-meters to create a versatile test
bed for solar PV devices. Automated measurements utilizing this apparatus include I-V curves
for PV cells and 2D fields of view and sub-aperture mask scans for CPV prototypes.
100
Chapter 4: Measurements and Computer Model
This chapter presents metrology data from the assembled prototype as well as the
individual components. Measurement results are used to create an accurate, as-built computer
model of the prototype. The performance of the simulated system is compared to that of the
real-world prototype, and insights about the measured performance data are derived from the
validated model.
4.1 Component Measurements
Measurements taken on the individual components allow an accurate computer model
to be created using a bottom-up approach. The geometry of each component is found along
with the topology and optical properties of critical surfaces. The relative alignment of the
system’s components is also important for a high fidelity model.
4.1.1 Guide Layer
The guide layer has the simplest geometry of any component in the prototype. It is a
rectangular slab with designed dimensions of ≥11 x ≥60 x 100 mm. The dimensions of the
fabricated component are measured using calipers,
assuming the angles between all faces are close to 90
degrees. It was found to have dimensions of 11.7,
61.0, and 100.1 mm, with an accuracy of ± 0.05 mm.
There is no discernable wedge in the part based on caliper data, so the part is assumed to have
all perpendicular faces for the purposes of the computer model.
(mm) Designed Measured
Thickness ≥ 11 11.7 ± 0.05
Length ≥ 60 61.0 ± 0.05
Width 100 100.1 ± 0.05
Table 4-1: Guide layer designed vs. measured dimensions.
101
The topology of the guide surfaces is only of great importance on the large faces.
During performance testing, the prototype is oriented in such a way that the faces
perpendicular to the extrusion direction are not part of the system’s optical path. The faces
adjacent to the PV cells are immersed in a resin with an index of refraction near that of guide
material, so any refractive effects due to surface topology on those faces are reduced to the
point of insignificance. In fact, there are tool marks on all four of the narrow guide faces, but
they become invisible when immersed in the index matching resin.
The large faces of the guide layer, however, are critical to the system’s operation. If the
surface roughness is too great, they will not support total internal reflection, which is the
primary function of the guide. If these surfaces are smooth, but not perfectly flat, they would
have little impact on the prototype’s performance.
The guide front face is
measured with the Zygo laser
interferometer described in Chapter 3,
and the results are shown in Figure 4.1.
Only about half the surface area can be
resolved by the interferometer in a
single measurement, but it shows that
much of the surface is smooth enough to be measurable by the interferometer using a
wavelength of 632.8 nm. The missing data is either due to a high surface roughness that
produces a diffuse reflection or smooth surfaces with high local surface slopes that produce high
fringe densities that are unresolvable by the interferometer’s sensor. In this case, the primary
contribution to the invalid data is the latter. This is evident when the invalid regions of Figure
Figure 4.1: Laser interferometer data of the guide front face. Dark blue indicates invalid data.
102
4.1 become resolvable as the part is tilted. This is a strong indication that the surface is smooth
enough to support TIR, though not extremely flat. However, the peak to valley departure from
flat for the resolved data is a mere 3.5 µm over the extent of the 100 mm x 61 mm face. Even a
peak to valley surface figure error of 10 times this value does not produce detectable changes in
the prototype performance. For these reasons, the surface is adequately modeled as being flat
and smooth.
The guide layer surfaces are measured with the fringe reflection deflectometer as well.
Measuring data on refractive parts is more difficult in the deflectometer than opaque reflective
surfaces such as the prototype primary reflector. This is due to a reduced signal from the tested
surface relying solely upon Fresnel reflection and unwanted signals from the part’s other
surfaces.
The deflectometer is configured in such
a way that the surface reflections occur at a
more grazing incidence and the part is oriented
to reduce or eliminate signals from other
surfaces. In the case of the guide layer, the
reflection of the monitor from the opposing
guide surface is unavoidable through orientation
change alone. To attenuate the competing signal, the offending surface is immersed in index
matching fluid (corn syrup) and coupled to absorptive black fabric as shown in Figure 4.2. The
reflection from the back surface becomes imperceptible.
Results from the deflectometer are shown in Figure 4.3. There is a large discrepancy in
the data between the deflectometer and interferometer results of Figure 4.1. The departure
Figure 4.2: Guide layer immersed in bed of corn syrup to suppress back surface reflection.
103
from flat is more than a magnitude
greater in the deflectometer data over
the breadth of the surface, and the
shape does not correlate well. The
reconstructed surface shape from the
deflectometer data is a smooth saddle
shape that has a high positive error
magnitude in two opposing corners,
and a high negative error magnitude in
the other two corners. In contrast, the
valid interferometer data shows a finer
structure to the surface. The
discrepancy is primarily due to two
effects: the nonlinear response of the
monitor (especially considering the
deflectometer’s high incidence angle
configuration) and the cumulative error
of integrating the surface slopes during 3D reconstruction. For this measurement, there are
over 1 million data points scattered across the surface, so some error is expected when
reconstructing the data in three dimensions based on measured slope data. That being said, the
data has a peak to valley value of just 0.1 mm over a 60 x 100 mm part. While the surface figure
is not entirely accurate, the slopes of the surface are more trustworthy since they are measured
more directly.
Figure 4.3: Top: Deflectometer data from guide layer front surface. Bottom: magnified region as marked in top graphic with surface figure subtracted out. A scratch and tool marks become visible. Vertical and horizontal slice charts shown, all units are mm.
x 10 -4
104
The close-up data in Figure 4.3 shows a scratch
and some shallow vertical markings, probably from the
buffing process used to help remove the aged
protective tape that was covering the surface of the
bulk PMMA material. These features are visible in the
raw data of the same region as illuminated by a set of
vertical fringes, shown in Figure 4.4 (note the raw data
is from a perspective view which slightly changes the
directionality of the features).
The close-up data illustrates well the strengths and weaknesses of the deflectometer
apparatus. As mentioned previously, commercial applications of this technology use it to find
qualitative flaws in reflective surfaces, for example, the scratch and the tool marks in the
presented data. However, surface reconstruction is difficult due to cumulative errors in the
slope integration. This effect is clearly seen by looking at either side of the scratch in Figure 4.3.
There is a jump in the data values from one side of the scratch to the other. This is not a real
feature of the surface and is primarily a result of slope integration error. The scratch acts as a
region of invalid data that the path of integration must avoid. Essentially, the path of
integration is routed around the scratch, staying in the smoother regions. The longer that path,
the more error accumulates from one end to the other. Further down in the frame, the scratch
has gaps where the slope integration calculation has a much shorter path between the two
sides. The discrepancy in topology across the scratch disappears in this region.
The reconstructed surface is more trustworthy in smooth regions over short distances
since the slope integration error is less severe. For this reason, it is still worthwhile to analyze
Figure 4.4: Portion of guide front surface from the raw deflectometer data. Scratch and tool marks are visible.
105
the shape of the tool marks from the deflectometer data. According to the data, they have a
period of about 1 mm and a depth of about 0.1 µm in the selected region, which will have little
effect on the direction of reflected light.
Even with the numerous defects detected by the deflectometer and interferometer, the
guide front (and back) surface can be accurately modeled as smooth and flat in the scope of the
prototype system.
4.1.2 Injection Prism
4.1.2.1 Geometry
The injection prism geometry is measured in a similar manner to the guide using
calipers. The non-right angles in combination with the filleted edges make this a less precise
measurement than for the right-angled guide component. This is indicated by greater
uncertainties in the measured data (Table 4-2).
To corroborate the caliper measurements, the angles between adjoining faces are
measured using a precision rotation stage (±5 arcminutes) and the reflections of a laser off of
adjacent faces. The prism is placed on the stage such that the rotational axis is aligned with the
extrusion direction of the part and is located near the edge corresponding to the angle being
measured. A screen is placed at a distance and the center of the laser spot is marked. Finally,
the rotation stage is turned so the laser strikes the adjacent face and its reflection hits the
previously marked spot on the screen. The difference in the start and end positions read on the
rotation stage is the internal angle on the part. Note that this measurement is only indicative of
the internal angle between the two points on the surfaces that the laser interacts with, and it
may vary depending on position if the surfaces are not flat.
106
A comparison of the designed and
measured dimensions are listed in Table 4-2. To
further validate the data, the distance
measurements from the bottom, back, and top are
used to create the prism geometry assuming right
angles between those edges. The resulting
geometry has calculated values of 35.58 mm for
the front edge, 75.85° for α, and 104.15° for δ.
Recall that the tolerance specification for α is
0.75°. These data correspond fairly well with the
other measured values and are the measurements
used in the computer model.
The largest discrepancy found in Table 4-2 is the length of the top and bottom edges,
both of which are about 3.5 mm longer than specified. The manufactured prism is thicker front
to back than intended, which has the effect of widening the field of view of the prototype.
Though this may appear advantageous to the design, the same flaw introduced into the full
system design has the effect of increasing guiding losses, thus reducing the efficiency of the
system at all points in the field of view.
The thicker prism also creates a potential issue in the prototype system. Recall that the
guide thickness is chosen based on the length of the bottom of the prism so that light trapped in
the guide by TIR has no chance of reentering the prism. The larger bottom dimension of the
fabricated prism increases the specification of the guide thickness to ≥13.0 mm, but the
manufactured guide is 11.7 mm. A similar discrepancy is observed for the guide length
Table 4-2: Injection prism designed vs. measured dimensions.
α
β γ
δ
Back
Bo
tto
m
Top
Edges (mm) Designed Measured
Front 35.50 35.9 ±1
Bottom 20.00 23.6 +0.5/-0.05
Back 34.38 34.5 ±0.05
Top 11.17 14.9 ±0.5
Angles ( ° ) Designed Measured
α 75.60 75.67 ±0.08
β 90.00 90.00 ±0.08
γ 90.00 90.00 ±0.08
δ 104.40 104.42 ±0.08
107
specification which would need to increase by about 3.5 mm. The guide satisfies the original
specifications, but not those modified to accommodate the thicker prism, so a fraction of the
light that is injected into the guide within its TIR limits reenters the prism and does not
contribute to the output of either PV cell.
4.1.2.2 Surface Finish
The surfaces of the prism
that are milled (top, bottom, and
front) have areas of tools marks
visible with the unaided eye. This
is an indication of a fairly rough
surface even in the areas where the marks have been more completely buffed out. As a result,
the Zygo laser interferometer is unable to resolve any fringes on these surfaces. The back
surface, however, is a smooth factory-finished surface that is easily measured in the laser
interferometer. The data are shown in Figure 4.5. The solid dark blue regions of invalid data are
areas outside of the interferometer’s maximum aperture and do not indicate flaws in the prism
surface. Notice the surface is slightly curved across the extrusion dimension, with a peak to
valley of about 8 µm over a distance of 100 mm. This is not of great concern with respect to the
prototype performance since its primary effect is a slight deviation of the rays in the extrusion
direction. This surface is modeled as being smooth and flat.
Lacking interferometer data on the remaining prism surfaces, they are measured in the
deflectometer under similar configurations to that used in the guide measurement. The data
are recorded and analyzed with the deflectometer’s limitations in mind. The prism front surface
Figure 4.5: Zygo laser interferometer data of the injection prism back surface.
108
reveals buffing tool marks much like those found on the guide layer. The marks have a depth of
about 100 to 200 nm and run parallel to the extrusion direction. Additionally, towards the
edges of the surface, milling marks become apparent in the form of more dramatic curved lines
that run somewhat perpendicular to the buffing marks. The more severe milling marks have
depths of around 500 nm.
The various markings can be seen most clearly by viewing the component slopes of the
measured surface data as shown in Figure 4.6. It appears that the central region was buffed
most agressively given the diminished milling marks and appearance of the finer buffing marks
in that region. Note that these emphasized features are not primarily due to phase error
stemming from the monitor nonlinearity. This is evidenced by the fact that the marks do not
run parallel to the fringes in the deflectometer’s raw data images.
The bottom surface of the prism has a similar finish to the other two milled sides, but
the surface topology is less significant since it will be immersed in an index matching fluid. The
top surface is even less important since it is not in the optical path of the system. However, in
Figure 4.6: Representation of prism front surface slope in the (top) horizontal and (bottom) vertical directions.
109
order to test the deflectometer, some
outstanding tool marks on the top
surface were investigated further by
both the deflectometer and the Zygo
white light interferometer. The two
data sets are compared to show the
merit of the deflectometer apparatus.
Data from the white light
interferometer is limited to a lateral
range of 0.35 x 0.26 mm, and the
milling marks in question have a
period of roughly 0.4 mm, so several
data sets must be stitched together.
The results are shown in Figure 4.7.
On the slice chart, the large
amplitude, large period undulations are the mill marks. There are some smaller features as well
that appear to be finer scratches left by the milling bit. These are seen most easily in the top
graph of Figure 4.7. On the prism top face, regions near the surface corners are visibly hazy.
This is due to a high concentration of the smaller scratch marks. The buffing procedure
evidently removes the scratches very quickly compared to the deeper milling marks.
The average depth of the milling marks in the tested region is approximately 0.2 µm
with a period of roughly 400 µm. This region is near the edge of what is resolvable by the
deflectometer. The very corner of the surface becomes too diffuse for the deflectometer to
Figure 4.7: White light interferometer data of prism top tool marks. Top graph shows registered data sets and position of slice, bottom shows surface height values along the slice (blue line) and the smoothed data (red line).
110
detect a usable specular signal. A portion of
the deflectometer data that is as close as
possible to this region is shown in Figure 4.8.
The vertical slice chart shows a period
between 400 and 500 µm, and an amplitude
of between 0.15 and 0.2 µm. This is
consistent with the white light interferometer
data (period and amplitude of 400 and 0.2 µm,
respectively).
4.1.2.3 Back Surface Mirror
The final aspect of the injection prism
metrology is the reflectivity of the back
surface mirror coating. Upon visual
inspection, as in Figure 4.9, the coating is clearly far from ideal. The edges appear blackened
and the coating does not extend all the way to the edges of the surface. This fabrication error is
due to issues during the vapor deposition process where the aluminum material pellet
completely evaporated during the first run. The process was run a second time to create a
thicker layer of material. Fortunately,
the center portion has a relatively
uniform reflectance, though much of
the light is absorbed. The process
was not repeated since cleaning off
Figure 4.9: Looking through the prism at the back surface mirror.
x 10-4
Figure 4.8: Deflectometer data of prism top near corner showing tool marks. All dimensions are in mm.
-12 -
111
the coating risks damaging the prism component. Additionally, the center portion of the mirror
can be selectively used during performance measurements and it only affects one of the two
cells, making it far easier to isolate in the final performance measurements.
For a robust computer model, the prism mirror must have a spatially varying
reflectance, so the reflectance as a function of position along the extrusion dimension is
measured. This is done using a green (543 nm) helium-neon laser, aiming it through the front
prism face, reflecting off the back face, and returning through the front face. A schematic of the
measurement process is pictured in Figure 4.10.
The prism is oriented in such a way that
the beam interacts with the front surface at the
same angle on the way in as on the way out.
The beam strikes each interface at nearly
normal incidence and is positioned to hit the
mirrored surface near its vertical center. The
prism is mounted on a translation stage and
moved in the extrusion direction after each
measurement.
Each data point consists of the power in
the Fresnel Reflection (beam A) and the Output
beam (beam B), a la Figure 4.10. The unattenuated power of the laser output is measured
separately. Beam A is the Fresnel reflection off of a single uncoated prism surface, so the
Fresnel transmission is easily calculated by
Figure 4.10: Schematic of prism mirror reflectance measurement. “Fresnel Reflection” and “Output” rays measured with power meters.
Fresnel Loss
Fresnel Loss
Reflection from prism
mirror
112
𝐹𝑡 = 1 −𝐼𝐴
𝐼0 ,
where I0 is the laser output power, IA is the power in beam A, and Ft is the Fresnel transmission.
To find an estimate of the internal transmittance of the prism material, the prism is moved so
the beam strikes an uncoated portion of the prism back surface. The output beam is subjected
to two Fresnel transmissions, two internal transmittance legs, and a Fresnel reflection off of the
back surface which is assumed to be 1 - Ft . The internal transmittance, τ, value is thus
calculated by
𝜏 = √𝐼𝐵
𝐼0(1 − 𝐹𝑡)𝐹𝑡2 ,
where IB is the power in beam
B. After Ft and τ are known,
the reflection, R, from the
coated portion of the back
surface is calculated by
𝑅 =𝐼𝐵
𝐼0𝐹𝑡2𝜏2
.
Primarily due to
estimated scattering from the surfaces, the uncertainty in the measurments is significant. The
results are shown in Figure 4.11. As expected, there is great variation in the reflectance with
especially poor performance near the edges. Even the best region in the center has just 36%
reflectance. The mirror surface is modeled as a series of uniform regions. The values of the
reflectance in each region along with the region widths are indicated by the orange line in the
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0 20 40 60 80 100
Ref
lect
ance
of
Seco
nd
Su
rfac
e
Position (mm)
Reflectance
Figure 4.11: Reflectance data from the prism mirror as a function of position in the extrusion direction. The blue line is the calculated reflectance with grey error bars and the orange is the stepped function used in the prototype model.
113
presented data. Figure 4.12 shows the geometry of the
uniform regions based on the reflectivity data and
computer analysis of prism photographs, such as that in
Figure 4.9.
4.1.2.4 Prism Model
Given all the above data, the prism is modeled
as having the measured dimensions and the mirror reflectivity is modeled as presented in the
previous section. All surfaces, however, are modeled as being flat and smooth. One feature not
previously mentioned is the fillets between the faces of the prism. The fillets on both edges
associated with the bottom prism face are important to model in order to coordinate the
measured and simulated prototype performances. The fillet on the front bottom edge is
modeled with a radius of 0.9 mm, tapering to 0.4 mm near the ends. The back bottom edge is
modeled as a scattering surface that extends 0.55 mm up the back face. This narrow strip does
not apply the reflective properties of the prism mirror since the coating does not extend around
the filleted edge. The effect of both of these fillets is inseparable from the effect of the index
matching fluid between the prism and guide layer near these two edges. Details of the modeled
prototype are found in Section 4.2.2.
4.1.3 Reflector
Given the reflector’s fabrication method, the primary concern regarding its
characterization is the surface shape. The surface has significant flaws and is expected to be a
major source of error in the final performance results. As previously indicated, measuring a
23% 11%
Figure 4.12: Geometry of the modeled reflectivity zones for the prism mirror. Blue regions are uncoated, and the remaining regions have uniform reflectances as indicated.
2% 2%
36% 31%
9% 22%
114
highly flawed, afocal, freeform optical surface is a difficult task, and is the motivation behind the
fringe reflection deflectometer apparatus.
Before the reflective Mylar is applied, the bare part is measured in the coordinate
measurement machine (CMM) introduced in Chapter 3. The data is shown in Figure 4.13
alongside the deflectometer data
after the Mylar film is applied.
These two data sets are compared
even though the surfaces being
measured are fundamentally
different: one is the bare 3D
printed reflector structure, and
the other is the surface of the
Mylar film that is adhered to that
surface. The macroscopic shape of
the surface is not expected to
change appreciably after applying
the Mylar film, so the data are
compared to assess the accuracy
of the deflectometer apparatus. A
direct comparison of the surface
shape is difficult since the CMM
optical probe experiences
Figure 4.13: Reflector surface shape measured via CMM (top) before Mylar film is applied and via the deflectometer (middle) with the Mylar film in place. Error values are mm of departure from the designed shape. The bottom image shows difference of the two data sets.
115
difficulty with the highly specular surfaces, and the deflectometer is incapable of measuring the
diffuse 3D printed surface.
From measurements of other components, the deflectometer is known to impart a
systematic surface figure error to the measured data as seen in Figure 4.3. This is thought to be
the primary reason for the large difference in the data sets of Figure 4.13. Note, however, the
CMM data does not extend to the very edges of the surface where the deflectometer predicts
the largest departure from the designed shape. The black outline in the top graph of Figure 4.13
shows the extent of the ideal surface geometry. The values shown in the CMM data also
depend on how the data are registered to the ideal surface.
From a qualitative standpoint, both the CMM and deflectometer data predict the
manufactured reflector to be slightly more curved along the X direction than designed. The
CMM shows a low amplitude convex bump in the extrusion (Y) direction which is absent in the
deflectometer data. It is possible that this is due to actual surface figure differences between
the bare and Mylar surfaces, though the demonstrated surface figure error in the deflectometer
reconstructions makes it impossible to conclude definitively. The effect of this error on
prototype performance is insignificant compared to the more egregious errors detected by the
deflectometer discussed below.
The CMM data shows the topology from the layered construction of the 3D printing
process which appears as striations in the extrusion direction. These marks are nonexistent in
the deflectometer data. This indicates that the Mylar film does not pick up the higher spatial
frequency topology present in the printed surface: an intended and beneficial effect.
Analyzing the principal curvatures of the deflectometer data reveals additional features
in the Mylar surface. The principal curvatures, k1 and k2, are the maximum and minimum
116
curvatures at each data point, respectively. For the chosen surface normal direction, a positive
curvature is convex and a negative, concave. The Gaussian curvature is the product of k1 and k2,
meaning it is negative for a saddle point and zero if either one of the principal curvatures is zero
[53].
The principal curvature data for the reflector surface based on the deflectometer results
are shown in Figure 4.14. Two notable features are the horizontal banding and the bumps near
the left edge of the data. The banding is seen exclusively in the k1 data. This is a real effect and
is present in the Mylar film even before it is applied to the reflector surface as seen in Figure
4.15. Since the waviness is evident when little external force is applied (e.g. freely hanging), it is
concluded to be caused by internal stresses in the film. Possible
origins of the internal stress include the stretching of the film or
metal deposition process during manufacture. The bumps near the
left edge of the data are predicted to be related to the adhesive
layer containing air bubbles. This conclusion is evidenced by the
Figure 4.15: Stock Mylar film showing wavy topology.
Figure 4.14: Principal curvature analysis of reflector surface as measured by the deflectometer.
117
observation of air bubbles in that region just prior to the Mylar lamination process.
A fine fringe-like structure is
observed in the curvature data as
shown in Figure 4.16 alongside the raw
fringe data of the same region. The fine
structure has the same directionality as
the raw fringe data and has a period
one fourth that of the imaged fringes.
For this reason, the fine structure is an
artifact of the nonlinearity of the deflectometer’s display as discussed in Chapter 3. Recall that
phase errors for the four step algorithm occur with a period that is one quarter that of the
displayed fringes. This fine error structure does not significantly affect the small scale topology
of the reconstructed surface, but contributes to cumulative integration error. However, due to
the comparatively small scale of the phase error, no attempt is made to remove it from the
reconstructed data.
The final test on the reflector
evaluates the surface roughness via
white light interferometry. The results
are shown in Figure 4.17 with a second
order 2D polynomial removed to reveal
the fine structure. Apart from an
occasional dust particle or scratch, the
Mylar surface is quite smooth with a
Figure 4.16: Magnified reflector surface data with the principal curvature, k2, on the left and a set of raw vertical fringe data on the right.
Figure 4.17: White light interferogram of the reflector's Mylar surface. A 2nd order 2D polynomial is removed to reveal surface roughness features.
118
peak to valley roughness of about 40 nm and an RMS roughness of about 120 Å. For reference,
a typical finish on a glass optical component is 50 Å RMS [54].
Given all the above data, the reflector surface is modeled according to the shape
measured by the deflectometer that imparts a very narrow (nearly specular) scattering angle
distribution to reflected rays, on the order of 0.1°.
4.1.4 Photovoltaic Cells
The geometry of the
PV cells is measured through
the computer analysis of
photographs of the cells over
a ruled background. The cell’s
size, shape, and gridline
pattern are measured and
modeled. The gridlines are a
necessary inclusion since they prevent light from interacting with the underlying PV material.
The photographs are used to create a binary apodization mask that is applied to the chip faces in
the model. The mask and raw photographs of one of
the prototype cells is shown in Figure 4.19.
To verify the mask geometries, each PV cell is
placed in the solar simulator beam behind a 4.88 mm
wide slit aperture. The output current of the cell is
Figure 4.19: PV chip geometry data and results. Photograph of back of PV cell over ruled background (top), photograph of front of cell (middle), and generated binary apodization mask (bottom).
Figure 4.18: Schematic of PV cell slit scan experiment.
119
measured as it is translated
along its long dimension with
the slit aperture remaining
stationary (Figure 4.18). The
same experiment is simulated
using the generated
apodization mask while
recording the incident
irradiance on the PV material.
The measured and simulated
results are compared in Figure
4.20, and they show excellent
agreement. The only simulated
effect is the geometry of the
exposed PV material, and the
simulated data is modified by
adjusting only the Y scale and X
and Y offsets. This data demonstrates that the output current of the cells is proportional to the
incident irradiance in the computer model, a fact that is used to compare the full prototype
measured and modeled performances. Additionally, this close agreement shows that there is no
appreciable drop in performance of the cells near the center which is furthest away from the
wire leads used to extract electrical current.
0
0.001
0.002
0.003
0.004
0.005
0.006
0.007
-80 -60 -40 -20 0 20 40 60
Translation Stage Position
Cell 1 Efficiency Profile
Measured Simulated
0
0.001
0.002
0.003
0.004
0.005
0.006
0.007
-60 -40 -20 0 20 40 60 80
Translation Stage Position
Cell 2 Efficiency Profile
Measured Simulated
Figure 4.20: Measured and modeled efficiency profiles for prototype photovoltaic cells.
Cu
rren
t (A
) C
urr
ent
(A)
120
The cell efficiency profile data show dips in output near the both ends of each cell. This
is due entirely to the presence of the thick gridlines at those positions. A more subtle feature is
the slight slope of the output data from cell 1 as a function of translation stage position. This is
caused by the geometry of the cell which is slightly wider at one end than the other, a
characteristic captured in the apodization mask.
The cells are also characterized
by their I-V curves as introduced in
Chapter 1. For this research, the primary
goal of these measurements is to
determine if the cells are damaged
during assembly. All that is needed for
this purpose is the dark I-V curves before
and after assembly. Prior to assembly,
the light I-V curve of each cell
illuminated by the solar simulator is
recorded for completeness.
The dark I-V curves shown in
Figure 4.21 reveal an obvious
discrepancy in cell 2 before and after assembly. These results indicate that cell 2 may see a
lower peak power and open circuit voltage than it did prior to assembly. However, the cell still
performs acceptably well, so it is not replaced. Cell 1 shows very little difference in performance
before and after assembly.
Figure 4.21: Dark I-V curves of prototype PV cells before and after assembly.
-0.01
0.01
0.03
0.05
0.07
0 0.1 0.2 0.3 0.4 0.5 0.6
Ou
tpu
t C
urr
ent
(A)
Forward Bias Voltage (V)
Cell 1 Dark I-V Curves
Pre-Assembly Post-Assembly
-0.01
0.01
0.03
0.05
0.07
0 0.1 0.2 0.3 0.4 0.5 0.6
Ou
tpu
t C
urr
ent
(A)
Forward Bias Voltage (V)
Cell 2 Dark I-V Curves
Pre-Assembly Post-Assembly
121
The light I-V curve of each cell
prior to assembly is presented in Figure
4.22. The effect of parasitic resistances
can be seen in the data, manifesting in
the form of a significantly sloped IV
curve at lower bias voltages. The two
cells have similar performance
parameters as indicated in Table 4-3.
The ratio of short circuit currents
between cells 1 and 2 is 0.991 which
approximately matches the ratio in
exposed PV material area between the
cells: 0.986. The light I-V curves are not taken after the prototype is assembled since it is
difficult to illuminate the cells in a controlled fashion. This means that comparisons between
the pre- and post-assembly cells as well as comparisons between both post-assembly cells
would be inconclusive.
4.2 Performance
4.2.1 Measurement Methods
The performance measurements are chosen to assist with a full characterization of the
prototype system and verify the computer model. The first performance metric is called the
“slit scan,” in which a vertically oriented, 4.88 mm wide, stationary slit aperture is placed in the
beam before the prototype. The prototype is then translated horizontally so the beam samples
-0.1
-0.08
-0.06
-0.04
-0.02
0
0.02
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7
Ou
tpu
t C
urr
ent
(A)
Forward Bias Voltage (V)
Light I-V Curves
Cell 1 Cell 2
Figure 4.22: Light I-V curve of each PV cell before assembly.
Cell 1 Cell 2
Short Circuit Current 95.2 mA 96.1 mA
Open Circuit Voltage 0.574 V 0.576 V
Peak Power 28.5 mW 30.3 mW
Fill Factor 52% 55%
Table 4-3: Light I-V curve parameters for both PV cells.
122
different parts of the prototype aperture in the extrusion direction. At each translational
position, the prototype is swept through a range of elevation, or vertical, angles producing a 2D
data set. This measurement is especially useful for assessing the performance as a function of
variations in the extrusion dimension such as the reflector shape, prism mirror reflectivity, and
cell gridline geometry.
The second measurement, called the “field of view” (FoV) is a 2D data set sweeping
through vertical and azimuthal angles. The slit aperture remains as it is in the previous
measurement, and the translational position is linked to the azimuthal angle in an attempt to
prevent the beam from interacting heavily with the poor reflectance regions of the prism mirror
or the thick gridlines on the PV cells. The FoV measurement is less for the purpose of verifying
Slit
Ap
ertu
re
Vertical Angle
Azimuthal Angle
Figure 4.23: Performance measurement schematic of the prototype system. Shows the three positional variables in the system. The Vertical Angle axis of rotation remains constant with respect to the prototype structure.
Bottom cell location
123
the model and more for assessing the prototype performance relating to the illumination
conditions expected for a full system. It maps the relative efficiency of the system for different
positions of the sun in the sky. The prototype dimensions and mounting structure limit the FoV
to azimuth angles between about +5° and -30°.
Each data point consists of two measured values, one is the output of the “top PV cell”
located on the guide top surface, closest to the prism back, and the other is the output of the
“bottom cell” on the opposing guide face (see Figure 4.23). Note that the prism mirror reflects
light towards the bottom cell while the top cell output is nearly, if not completely, independent
of the prism mirror quality. The top and bottom cell outputs are simply added together to
obtain the total performance metric.
All the data from the simulations is shifted in translational position, vertical angle, and
azimuthal angle to account for the offsets present in the mounted prototype. The data values
are also offset (background signal) and scaled to fit the measured data. These adjustments are
applied uniformly to all simulated results over both the slit scan and FoV data sets. For example,
if the reflectance value of the prism mirror is lower than modeled, the simulated data will
appear too high since the top and bottom cell values are not scaled independently.
As mentioned previously, the measured value in the real-world prototype is the
electrical current output from each cell, while the simulation records only the incident
irradiance on the cells’ active areas. These two values are proportional given the highly linear
current response of silicon PV cells [5]. This is supported by the slit scan data in Section 4.1.4
with the close agreement of the measured current and simulated incident irradiance.
124
4.2.2 Simulated Performance
To illustrate the effects of each modeled manufacturing flaw, the system performance is
first simulated without any flaws. Then the flaws are added to the model one at a time and the
performance is reevaluated. All of the flaws have already been discussed in detail and are
summarized in Table 4-4.
The ideal model has no variation in the translation direction, and is thus measured as a
function of vertical angle only for the slit scan experiment. The FoV measurement retains both
data dimensions.
Name Ideal Modeled Flaw
Prism Dimensions
Prism dimensions as specified for
manufacter (right angle between top and
back faces), 75.6° between front and
bottom faces, and a 20 mm wide bottom
face
75.847° angle between front and bottom
faces, and a 23.6 mm wide bottom face
Reflector ShapeAs-designed reflector shape with no
variation in the extrusion direction
Reflector shape as measured by the
deflectometer
Back Prism FilletSharp edge between back and bottom
prism faces
0.55 mm tall strip at the bottom of the
prism mirror face is modeled as a diffuse
scatterer since the edge is filleted and
the mirror coating does not extend to the
very edge of the surface
Front Prism FilletSharp edge between front and bottom
prism faces
Edge is filleted with a radius of 0.9 mm,
tapering to 0.4 mm near the ends of the
prism
Cell Gridlines No cell gridlinesCell gridlines with thick lines near either
end of each cell
Prism Mirror Spatially invariant reflectance of 90%Spatially varying reflectance with a peak
reflectance of 36%
Table 4-4: Summary of simulated manufacturing flaws. The flaws are added to the model in the order shown.
125
The results of several slit scan simulations are presented in Figure 4.24. The ideal model
is shown with none of the listed manufacturing flaws. Then the measured prism dimensions are
added followed by the measured reflector shape. A wide source filling most of the prototype
aperture is used for the simulations in order to average out the translational variability of the
reflector for these data. Notice that the totaled output does not appear to match the data
presented in the tolerance analysis of Chapter 3. While there are slight differences in the
models, the main cause of the discrepancy is that the previous data does not take into account
the cosine falloff from the projected area of the prototype aperture.
Including Flaws in:
0
0.2
0.4
0.6
0 20 40 60
Top Cell
Figure 4.24: Slit scan simulation data for ideal model (red), added prism dimensions flaw (green), then added reflector shape flaw (blue). Simulation is performed with wide source to average out translational variations in the measured reflector shape. Vertical axis is in relative units and are equivalent for all three plots.
0
0.2
0.4
0.6
0 20 40 60
Bottom Cell
0
0.2
0.4
0.6
0 20 40 60
Vertical Angle ( ° )
Total
0
0.2
0.4
0.6
10
Ideal
Prism Dimensions
Reflector Shape
None (Ideal Model)
Prism Dimensions
Reflector Shape
126
When the measured prism dimensions are included in the model, the field of view is
widened as predicted. A much more profound difference is seen when the measured reflector
shape is incorporated. This is the single most significant source of error in the prototype, as
expected. The measured reflector shape causes two peaks to appear in the output of the top
cell around vertical angles of 24° and 34° with a valley in between at 29°. Figure 4.25 illustrates
the cause of this phenomenon by visualizing the traced rays. At the 24° peak, the ray bundle
just fills the extent of the prism-guide interface, but as the vertical angle increases, those rays
begin to strike the prism mirror and are sent towards the bottom cell instead. Increasing the
vertical angle further begins to utilize the leftmost portion of the reflector whose rays are sent
towards the top cell via TIR inside the guide layer.
The ideal reflector shape has a more definitive caustic and an overall flatter shape. For
that model, the top cell output peaks when the prism-guide interface is just filled, and sends
more rays toward the bottom cell as the vertical angle begins to increase. The difference comes
in the lack of a second peak since the leftmost portion of the reflector is at a different angle and
does not send rays toward the top cell with increasing vertical angle.
Figure 4.25: Raytraces of the "Reflector Shape" model at three different vertical angles as indicated. There are peaks in the top cell output at 24° and 34° with a valley in between.
127
The FoV results for the ideal model are displayed
in Figure 4.26. This simulation reverts to a narrow slit
aperture, so there is no cosine falloff effect in the
azimuthal direction. The performance is nearly constant
as a function of azimuth except for a slight depression in
the output at the more extreme azimuthal angles. This is
primarily due to increased Fresnel losses for the more
extreme incidence angles at all refractive interfaces.
The FoV data for the ideal model is symmetric
about the azimuthal origin given the lack of variation in
the extrusion direction. However, this is no longer true
once certain flaws are introduced. Note that the FoV
data at an azimuth of 0° is equivalent to the slit scan data
at the zero translational position.
The next flaws to be introduced are the front and
back fillets on the edges adjacent to the injection prism’s
bottom face. The effect of these flaws depends greatly
on the translational position, so the slit aperture is
reduced once again to 4.88 mm wide. The results with a
fixed translational position of 0 are shown in Figure 4.27.
The legend lists the most recently added flaw, but the
model also includes all previously added flaws in the
order listed in Table 4-4. For example, a data set labeled
Figure 4.26: Results of Field of View (FoV) simulation for ideal prototype model.
128
“Back Fillet” includes the back fillet flaw along with all previous flaws: prism dimensions and
reflector shape in this case.
As indicated by the data, the primary effect of the front fillet is a depression of the top
cell output for lower vertical angles. Likewise, the back fillet depresses the output of the
bottom cell for lower vertical angles. Note the small bump in the bottom cell output near the
30° vertical angle. For some translational positions, this bump is significantly suppressed by the
inclusion of the front fillet. This is because some rays are reflecting off the prism mirror and
passing very close the front edge of the prism before continuing into the guide layer. The
0
0.2
0.4
0 20 40 60
Top Cell
0
0.2
0.4
0 20 40 60
Bottom Cell
0
0.2
0.4
0.6
0 20 40 60
Vertical Angle ( ° )
Total
0
0.2
0.4
0
Reflector Shape
Back Fillet
Front Fillet
Figure 4.27: Results of slit scan simulations for a 4.88 mm wide slit fixed at the translational origin. The reflector shape data set includes the prism dimensions flaw. The remaining data sets are for and added back prism fillet then front fillet.
Including Flaws from:
129
inclusion of the fillet deviates those rays so they do not reach the bottom cell with the same
efficiency. Figure 4.28 demonstrates this phenomenon at a translational position of 9 mm for
the most affected range of vertical angles. Rays are traced over the entire aperture height, but
only a subset are drawn for illustration purposes.
0
0.02
0.04
0.06
0.08
0.1
0.12
23 25 27 29 31 33
Translational Position = 9 mm
Back Fillet Front Fillet
Figure 4.28: Effect of front fillet on bottom cell output near 30° vertical angle and 9 mm translational position.
Front fillet
location
130
Fig
ure
4.2
9: S
lit S
can
sim
ula
tio
n r
esu
lts
for
fin
al t
hre
e m
od
ele
d m
anu
fact
uri
ng
flaw
s. S
cale
s ar
e co
nst
ant
wit
h e
ach
ro
w t
o s
ho
w a
tten
uat
ion
ef
fect
s o
f ea
ch f
law
. Fro
nt
Fille
t C
ell
Gri
dlin
es
Pri
sm M
irro
r
131
For the remainder of the data, all simulations are extended into two dimensions to show
the full effect of the included manufacturing flaws. Figure 4.29 shows the slit scan simulations
for the added flaws of the front fillet, cell gridlines, and prism mirror, which is the final modeled
flaw. The addition of the cell gridlines decreases the output of both cells since it is preventing
some of the light from reaching the PV material. In particular, there is a large decrease in
output near both extremes of the translation position for both cells. This is due to the thick
gridlines which are located on the corresponding parts of the cells. The top and bottom cells see
the decreased output at slightly different translational positions since the large gridlines are not
located on precisely the same parts of both cells.
Including the measured prism mirror reflectance has a substantial effect on the
bottom cell output, but the top cell experiences no distinguishable change. This is expected
since the purpose of the prism mirror is to redirect light rays towards the bottom cell. The low
reflectance of the mirror decreases the total output of the bottom cell at all data points. There
is an especially large depression at translational positions of less than -20 mm and greater than
about 30 mm. This is due to the reflectance falloff of the mirror near the translational extremes.
Figure 4.30 shows the same manufacturing flaws for the field of view measurement.
The addition of the cell gridlines appears to simply uniformly decrease output of both top and
bottom cells, while the poor reflectance of the prism mirror uniformly effects the bottom cell
only. The lack of added structure is achieved with the linked translational and azimuthal axes
during the simulation. The relationship between these two parameters is chosen so the beam
strikes the relatively uniform center portion of the prism mirror while avoiding the thick
gridlines on both top and bottom cells. As such, the uniformly decreasing output is due to the
thin cell gridlines and the ~36% reflectance center portion of the prism mirror only.
132
Figure 4.30: Field of View (FoV) simulation results for final three modeled manufacturing flaws. Scales are constant across each row to show attenuation effects of each flaw.
133
4.2.3 Measured Performance Comparison
The validation of the above simulation results is achieved by comparing them to
measured results from the real-world prototype. Figure 4.31 shows a comparison of the slit
scan performance and Figure 4.32 presents the field of view data. The data are processed only
in its relative output scale and offset, and the relative zero positions of the vertical angle,
Slit Scan Performance Comparison
Figure 4.31: Slit scan performance comparison. Measured results in the left column, simulated results in the right column. Scale is consistent across each row.
134
azimuth angle, and translation
position. The same post-processing
values are used ubiquitously for all
data presented in this section.
Many features match very well
between the measured and simulated
results. For example, the relative
position of peaks between the top and
bottom cells and the general envelope
of non-zero output values. Even the
fine translationally variant output of
the top cell at the 23° vertical angle
matches extraordinarily well.
However, there are certain structures
that the computer model did not
capture.
For instance, the measured slit
scan top cell data drops to zero at the
translational extremes while the
simulation predicts output to increase.
This is easily explained by the
prototype’s support structures blocking absorbing the incident rays at either end of the
extrusion. The support structure was purposely ignored during the simulation since its effects
Field of View Performance Comparison
Figure 4.32: Field of view performance comparison. Measured results in the left column, simulated results in the right column. Scale is consistent across each row.
135
would be easily discernable in the measured data. The simulation predicts a rise in output in
these regions because the beam would have passed over the thick gridlines as the translational
position nears ±50 mm. The measured results show the interaction with the thick gridlines, but
the output continues to decrease as the beam begins to be attenuated by the support structure.
A more mysterious discrepancy occurs near the bottom cell peak in both the slit scan
and field of view experiments. The simulated data shows a single peak at a vertical angle of
about 47° while the measured data shows the peak shifted to about 51° in the case of the slit
scan, and two separate peaks at about 47° and 52° in the FoV data. The FoV data at an azimuth
of 0° are the same exact measurement as the slit scan data at a translation position of 0 mm.
This is definitely the case for the simulated data and the measured top cell data seems to exhibit
this property. The change in this data subset in the bottom cell implies that part of the
prototype changed between the two experiments in a way that only significantly effects the
bottom cell output. A fabrication error that is not included in the computer model is some resin
trapped between the guide and the reflector structure.
This error occurred during the attachment of the bottom cell to the guide layer. At that
stage, the reflector was already in place and there existed a small air gap between that structure
and the front face of the guide layer. Some excess liquid resin from the bottom cell filled in part
of that gap via capillary action, against the force of gravity. Due to the construction of the
Bottom Cell
Guide Bottom of Reflector
Unwanted Resin
Figure 4.33: Photo peering through back face of guide layer at the bottom of the reflector structure. Resin from the bottom cell seeping into the gap between the reflector and guide appears as irregularly shaped darker regions.
136
braces, the offending resin cannot be cleaned off without disassembling the prototype.
Unfortunately, this resin allows light to couple out of the guide layer just prior to reaching the
bottom cell. The resin shape also changes unpredictably depending on the stresses in the
prototype structure, making it temporally variant as the prototype is rotated and moved during
the experiments. A snapshot of the resin’s irregular shape is shown in Figure 4.33 by looking
through the back surface of the guide layer.
The effect this has on the performance is
highly dependent upon the shape of the resin layer.
Investigating the ray paths near the discrepant
region in the data sets, say a vertical angle of 47°,
many rays strike the region of front guide layer
adjacent to the reflector structure where the excess
resin is located. By changing the shape of the resin
layer and assuming it is partially absorptive, one can
selectively and significantly change the bottom cell
output between vertical angles of about 44° and 51°
according to the as-built model. In combination
with adjusting the reflectivity values of the prism
mirror, this degree of freedom could appear to shift the simulated peak’s vertical angle position
or even split it in two. In a similar way, it can also explain the decreased output in the bottom
cell near an azimuth of -7° and a vertical angle of 47°. Since the resin layer shape is temporally
inconsistent and cannot feasibly be measured in real time, its effect is omitted from the
Unwanted Resin Region
Figure 4.34: Simulation of final prototype model at a vertical angle of 47° showing many rays interacting with the area containing the unwanted resin.
137
computer model. However, it offers a credible explanation for some inconsistencies in the data
that fits all observations.
Another more subtle inconsistency is the decreased top cell output in the simulation
data near the 24° vertical angle peak. This peak is slightly lower in both the simulated slit scan
and field of view studies. While no definite explanation is offered here, one possible cause is
the crazing of the guide surface adjacent to the prism as described in Chapter 3. This crazing is
not included in the model since its effect is difficult to measure. Ideally, the bidirectional
scattering distribution function (BSDF) of the surface would be measured as it is implemented in
the prototype: immersed in corn syrup. The BSDF is a notoriously difficult and data-intensive
measurement and the equipment needed was not readily available. The crazing is suggested as
the source of the data inconsistency since its degree of scattering depends on incident angle and
the 24° vertical angle peak has a significant portion of rays traversing the prism-guide interface
at grazing incidence angles (refer back to Figure 4.25).
4.3 Conclusion
Apart from the mentioned discrepancies, the data coincides very well, especially given
the major performance changes incurred by adding manufacturing flaws presented throughout
Section 4.2.2. This is a strong indication that the model is accurate to a degree such that
features in the data can be investigated and explained by visualizing light rays traced in the
computer model.
138
Chapter 5: Conclusion
5.1 Summary
Current research in CPV is focused mainly on high concentration systems with high
conversion efficiency. Low concentration systems are not as well explored since they cannot
offer the efficiencies of HCPV, but niche applications can take advantage of their flexible form
factor. Interest in building-integrated photovoltaics has led to several commercialized
technologies that integrate solar photovoltaics into windows [17, 18, 22, 23].
Several novel window-integrated low concentration solar concentrator designs have
been presented with the goal of reducing the net energy lost through the windows in the
wintertime. They are based on previous planar light guide concentrators from the University of
Rochester [11, 12]. The systems are evaluated regarding their effective insulation properties
given the calculated net energy lost. Without moving parts, they optimize to have acceptance
angles of about 20° to 35° in the vertical direction and ±90° in the horizontal direction, but have
peak optical efficiencies of less than 50%. By including internally moving parts, the acceptance
angle is increased to nearly a full π steradians (the full sky from the point of view of the window)
and the average optical efficiency increases to over 50%. Systems in certain locations are not
viable due to low solar irradiance in the wintertime. Others, however, reduce net energy loss to
zero or better for much of the year.
The “suspended louver” design optimized for Rochester NY is prototyped as a proof of
concept. The prototype is at a 10X scale and includes one primary optical element and its
associated injection feature. Its performance is measured using a solar simulator and is
compared to the performance of the computer model. Measurements of the prototype system
139
and its individual components help create an accurate model of the as-built system. The
measured and simulated performance results are shown to coincide closely.
The well-matched performance results indicate an accurate computer model of the
prototype system. This validates the simulation methods used during the optimization of the
designs and shows that they have the potential to reach the predicted performance values if
manufactured accurately.
The static designs must be optimized for a specific location while a single tracking design
operates efficiently for a wide range of latitudes. Another location specific consideration is the
variability of available solar irradiance throughout the year. Rochester, NY is a challenging
location for this application due to its frequent cloud cover during the cold times of year when
the CPV system is optimized to operate at peak efficiency. Designs for other locations, however,
show great promise in recovering energy lost through the windows.
5.2 Future Work
The next logical step to validate this LCPV design space is to create a prototype with an
array of optics at a smaller scale than done in this thesis. This requires sophisticated fabrication
methods and introduces more error largely due to the difficult task of aligning an array of micro-
optics. However, a similar undertaking has been achieved with some success at the University
of Rochester for HCPV systems [11, 12]. Fabrication methods that could be used for mass
manufacture are of particular interest. For example, the suspended louvers could be strips of
reflective Mylar film that are glued to plates of glass at either endpoint. The angle of the film
surface at the endpoints could be fixed during the glue setting process and the curvature may be
140
controlled by varying the film’s thickness (Dr. James Zavislan, personal communication, January,
2014).
The window-integrated light guide LCPV design space has not been thoroughly explored.
The designs presented in this thesis offer novel solutions in this space, but there is still much to
be discovered. In particular, the tracking design presented in Chapter 2 is based off of the static
louver designs and essentially tracks with a horizontal rotational axis. However, the more
sensible tracking direction uses a vertical (possibly tilted) rotational axis given the wider
acceptance angle requirements in the horizontal direction. This results in a drastically different
design form than the louvers presented here.
Finally, the presented static designs would be more marketable if they operated
efficiently for a wide range of latitudes rather than being designed for a series of singular
locations. A more broadly applicable design form seems to be possible given the similar shapes
of individual components for designs presented in this thesis. It may be possible to fabricate the
same components for a variety of locations, but assemble them with a different alignment
depending on latitude and typical annual weather conditions.
141
References
[1] "Remarks by the President on Energy," 29 June 2009. [Online]. Available:
http://www.whitehouse.gov/the_press_office/Remarks-by-the-President-on-
Energy/. [Accessed 21 January 2013].
[2] Solar Energy Industries Association, "Solar Energy Facts: 2014 Year in Review," 17
December 2014. [Online]. Available: http://www.seia.org/research-
resources/solar-market-insight-report-2014-q4. [Accessed 27 July 2015].
[3] S. Kurtz, "Opportunities and Challenges for Development of a Mature Concentrating
Photovoltaic Power Industry," U.S. National Renewable Energy Laboratory,
November 2012. [Online]. Available: www.nrel.gov_docs_fy13osti_43208.pdf.
[Accessed 1 January 2013].
[4] D. S. P. Philipps, D. A. W. Bett, K. Horowitz and D. S. Kurtz, "Fraunhofer ISE," January
2015. [Online]. Available: http://www.ise.fraunhofer.de. [Accessed 28 July 2015].
[5] S. B. Christiana Honsberg, "PVEDUCATION.ORG," 11 Sept. 2015. [Online]. Available:
http://www.pveducation.org/. [Accessed 14 Sept. 2015].
[6] Narional Renewable Energy Laboratory, "Best Research-Cell Efficiencies," 2015. [Online].
Available: http://www.nrel.gov/ncpv/images/efficiency_chart.jpg. [Accessed 3
Nov 2015].
[7] "Energy Storage Technologies," Energy Storage Association, 2015. [Online]. Available:
http://energystorage.org/energy-storage/energy-storage-technologies.
[Accessed August 2015].
142
[8] S. H. Tan, "Solar Intermittency: How Big is the Problem?," 1 November 2011. [Online].
Available: http://www.renewableenergyworld.com/articles/2011/11/solar-
intermittency-how-big-is-the-problem.html. [Accessed August 2015].
[9] U.S. Energy Information Administration, "Annual Energy Outlook 2015," 3 June 2015.
[Online]. Available:
http://www.eia.gov/forecasts/aeo/electricity_generation.cfm. [Accessed 29 July
2015].
[10] M. A. Green, K. Emery, Y. Hishiwaka, W. Warta and E. D. Dunlop, "Solar cell efficiency
tables (Version 45)," Progress in Photovoltaics: Research and Applications, vol.
23, no. 1, pp. 1-9, 2015.
[11] B. Unger, "Dimpled Planar Lightguide Solar Concentrators," PhD Dissertation, University
of Rochester, 2010.
[12] M. Brown, "Advanced Planar Light Guide Solar Concentrators," PhD Dissertation,
University of Rochester, 2013.
[13] W. Cassarly, "Taming Light," Optical Engineering, vol. 41, no. 12, pp. 16-18, December
2002.
[14] R. Winston, Nonimaging Optics, Burlington, MA: Elsevier Inc., 2005.
[15] R. Winston and W. Zhang, "Pushing concentration of stationary solar concentrators to
the limit," Optics Express, vol. 18, no. S1, 2010.
[16] tenKsolar, "Product," [Online]. Available: http://tenksolar.com/product. [Accessed 23
July 2013].
[17] N. Yamada, K. Kanno, K. Hayashi and T. Tokimitsu, "Performance of see-through prism
CPV module for window integrated photovoltaics," Optics Express, vol. 19, no.
S4, 2011.
143
[18] Stellaris, "Stellaris ClearPower Photovoltaic Window Tile," 2008. [Online]. Available:
http://www.stellarissolar.com/clearpower/clearpowertile.php. [Accessed 2 Sept
2015].
[19] J. B. Paull, "Concentrating solar roofing shingle". US Patent 20050081909 A1, 21 Apr
2005.
[20] J. B. Paull, "Apparatus and method for forming a photovoltaic device". US Patent
7875792 B2, 25 Jan 2011.
[21] L. H. Slooff, E. E. Bende, A. R. Burgers, T. Budel, M. Pravettoni, R. P. Kenny, E. D. Dunlop
and A. Büchtemann, "A luminescent solar concentrator with 7.1% power
conversion efficiency," Physica Status Solidi Rapid Research Letters, vol. 2, no. 6,
pp. 257-259, 2008.
[22] Prism Solar, "Vertical Mounting," 2014. [Online]. Available:
http://www.prismsolar.com/ev-stations.php. [Accessed 2 Sept 2015].
[23] Solaria, "Building-Integrated Photovoltaics (BIPV)," 2015. [Online]. Available:
https://www.solaria.com/solutions/Building.html. [Accessed 2 Sept 2015].
[24] Wikipedia, "R-value (insulation)," Wikimedia Foundation, Inc., 22 Aug 2015. [Online].
Available: https://en.wikipedia.org/wiki/R-value_(insulation). [Accessed 26 Oct
2015].
[25] NREL, "National Solar Radiation Data Base," 2015. [Online]. Available:
http://rredc.nrel.gov/solar/old_data/nsrdb/1991-2005/tmy3/. [Accessed 28 Oct
2015].
[26] Engineering ToolBox, "Thermal Conductivity of Materials and Gases," [Online]. Available:
http://www.engineeringtoolbox.com/thermal-conductivity-d_429.html.
[Accessed 28 Oct 2015].
144
[27] J. Fosdick, "Passive Solar Heating," Whole Building Design Guide, 24 Aug. 2012. [Online].
Available: http://www.wbdg.org/resources/psheating.php. [Accessed 3 Jan.
2016].
[28] "Poly(methyl methacrylate)," 3 Sept. 2015. [Online]. Available:
https://en.wikipedia.org/wiki/Poly(methyl_methacrylate). [Accessed 11 Sept.
2015].
[29] M. Polyanskiy, "Optical constants of (C5O2H8)n (Poly(methyl methacrylate), PMMA),"
2015. [Online]. Available:
http://refractiveindex.info/?shelf=organic&book=poly%28methyl_methacrylate
%29&page=Szczurowski. [Accessed 11 Sept. 2015].
[30] FormLabs, "Form 1+ High-Resolution 3D Printer," FormLabs, 2015. [Online]. Available:
http://formlabs.com/products/3d-printers/form-1-plus/. [Accessed 6 Oct. 2015].
[31] P. Anne Marie Helmenstine, "What is Mylar?," About.com, 2015. [Online]. Available:
http://chemistry.about.com/od/polymers/f/What-Is-Mylar.htm. [Accessed 16
Sept. 2015].
[32] "Skin Depth Calculator," RF Cafe, [Online]. Available:
http://www.rfcafe.com/references/calculators/skin-depth-calculator.htm.
[Accessed 16 Sept. 2015].
[33] "Projective geometry," Wikipedia, 30 June 2015. [Online]. Available:
https://en.wikipedia.org/wiki/Projective_geometry. [Accessed 16 Sept. 2015].
[34] NuSil, "R-2615," NuSil, 2014. [Online]. Available: http://nusil.com/product/r-
2615_optically-clear-potting-and-encapsulating-silicone-elastomer. [Accessed 29
Sept. 2015].
[35] "Crazing," Wikipedia, 28 Aug. 2015. [Online]. Available:
https://en.wikipedia.org/wiki/Crazing. [Accessed 28 Sept. 2015].
145
[36] G. Vuye, S. Fisson, V. N. Van, Y. Wang, J. Rivory and F. Abelès, "Temperature dependence
of the dielectric function of silicon using in situ spectroscopic ellipsometry," Thin
Solid Films, vol. 233, no. 1-2, pp. 166-170, 1993.
[37] Zygo, "Verifire Series," Zygo, [Online]. Available:
http://www.zygo.com/?/met/interferometers/verifire/. [Accessed 29 Sept.
2015].
[38] Zygo, "NewView 7100," Zygo, [Online]. Available:
http://www.zygo.com/?/met/profilers/newview7100/. [Accessed 29 Sept. 2015].
[39] Metricon Corporation, "Model 2010/M Overview," Metricon Corporation, 2015. [Online].
Available: http://www.metricon.com/model-2010-m-overview/. [Accessed 29
Sept. 2015].
[40] Optical Gaging Products, "SmartScope Quest 300," Optical Gaging Products, 2015.
[Online]. Available: http://www.ogpnet.com/ogpVidQuest300.jsp. [Accessed 29
Sept. 2015].
[41] E. Savio, L. D. Chiffre and R. Schmitt, "Metrology of freeform shaped parts," Annals of the
CIRP, vol. 56, no. 2, pp. 810-835, 2007.
[42] T. Bothe, W. Li, C. v. Kopylow and W. Jüptner, "High-resolution 3D shape measurement
on specular surfaces by fring reflection," Proc. of SPIE, vol. 5457, pp. 411-422,
2004.
[43] J. Balzer and S. Werling, "Principles of Shape from Specular Reflection," Measurement,
vol. 43, no. 10, pp. 1305-1317, 2010.
[44] P. Su, R. Parks, R. Angel, L. Wang and J. Burge, "A new test for optical surfaces," 20 Jan.
2011. [Online]. Available: http://spie.org/x44262.xml?ArticleID=x44262.
[Accessed 30 Sept. 2015].
146
[45] CNET, "Dell UltraSharp 2009W," CBS Interactive Inc., [Online]. Available:
http://www.cnet.com/products/dell-ultrasharp-2009w/specs/. [Accessed 29
Sept. 2015].
[46] R. Y. Tsai, "A Versatile Camera Calibration Technique for High-Accuracy 3D Machine
Vision Metrology Using Off-the-Shelf TV Cameras and Lenses," IEEE Journal of
Robotics and Automation, Vols. RA-3, no. 4, pp. 323-344, 1987.
[47] Wikipedia, "Gamma correction," Wikipedia, 25 Sept. 2015. [Online]. Available:
https://en.wikipedia.org/wiki/Gamma_correction. [Accessed 30 Sept. 2015].
[48] D. Malacara, Optical Shop Testing, Hoboken, New Jersey: John Wiley & Sons, Inc., 2007.
[49] J. W. Goodman, Introduction to Fourier Optics, Greenwood Village, CO: Roberts &
Company Publishers, 2005.
[50] J. M. Bioucas-Dias, "CODE," [Online]. Available: http://www.lx.it.pt/~bioucas/code.htm.
[Accessed 2 Oct. 2015].
[51] J. Bioucas-Dias and G. Valadão, "Phase Unwrapping via Graph Cuts," IEEE Transaction on
Image Processing, vol. 16, no. 3, pp. 698-709, 2007.
[52] W. H. Southwell, "Wave-front estimation from wave-front slope measurements," Journal
of the Optical Society of America, vol. 70, no. 8, pp. 998-1006, 1980.
[53] Wikipedia, "Gaussian Curvature," Wikimedia Foundation, Inc., 14 Oct 2015. [Online].
Available: https://en.wikipedia.org/wiki/Gaussian_curvature. [Accessed 16 Nov
2015].
[54] Edmund Optics Inc., "Understanding Optical Specifications," Edmund Optics Inc., 2014.
[Online]. Available: http://www.edmundoptics.com/technical-resources-
center/optics/understanding-optical-specifications/. [Accessed 13 Oct. 2015].
147
[55] "Solar Power Tower," Wikipedia, 5 August 2015. [Online]. Available:
https://en.wikipedia.org/wiki/Solar_power_tower. [Accessed August 2015].
[56] CED Greentech, "Residental Solar Financing," 2015. [Online]. Available:
https://www.cedgreentecheast.com/residential-solar. [Accessed August 2015].
[57] "Electricity Demand," Electropaedia, 2005. [Online]. Available:
http://www.mpoweruk.com/electricity_demand.htm. [Accessed August 2015].
[58] Lang Exterior, Inc., "Argon and Krypton Gas-Filled Insulated Glass," 2015. [Online].
Available: http://langexterior.com/argon-gas-filled-glass.html. [Accessed 28 Oct
2015].
[59] Light Prescription Innovators, [Online]. Available: http://www.lpi-
llc.com/Papers/Images/FresnelConcentrator.jpg. [Accessed 21 January 2013].
148
Appendix A. Design Specifications
Suspended Louver
149
Immersed Louver
150
Extruded Segment Lens
Curve
151
Static Designs: Departures from Best Fit Circles of Primary Optic
152
Tracking Louver
153
154
155
156
Appendix B. Deflectometer MATLAB Code
DeflectometerWizard.m
This code is the high level function for data acquisition from the deflectometer. The
dependency functions written for this research are included after the high level code. All other
functions are included in MATLAB 2012a or are publically available on the MATLAB Central File
Exchange website.
function [cutup,cutdn,v1234lin,h1234lin,linmm,permm,CalibrationData] =
DeflectometerWizard(varargin)
p = inputParser;
p.StructExpand = true;
addParamValue(p,'exposure',0,@isnumeric);
addParamValue(p,'f',1,@(x) (isnumeric(x) && numel(x)==1));
addParamValue(p,'k1',0,@(x) (isnumeric(x) && numel(x)==1));
addParamValue(p,'R',zeros(3),@(x) (isnumeric(x) && all(size(x)==[3,3])));
addParamValue(p,'T',zeros(3),@(x) (isnumeric(x) && all(size(x)==[3,1])));
addParamValue(p,'Rmir',zeros(3),@(x) (isnumeric(x) && all(size(x)==[3,3])));
addParamValue(p,'Tmir',zeros(3),@(x) (isnumeric(x) && all(size(x)==[3,1])));
addParamValue(p,'cxcy',[0 0],@(x) (isnumeric(x) && numel(x)==2));
addParamValue(p,'dxy',[0 0],@(x) (isnumeric(x) && numel(x)==2));
parse(p,varargin{:});
close all;
global vid src fs;
cutup = 200; % upper 8-bit cutoff for fringe display
cutdn = 30; % lower 8-bit cutoff for fringe display
monpp = [0.258,0.258]; % monitor pixel pitch [x,y]
% dummy values in case of early termination
v1234lin=0; h1234lin=0; linmm=0; permm=0;
if any(cellfun(@(str)
any(strcmp(str,p.UsingDefaults)),{'f','k1','R','T','Rmir','Tmir','cxcy','dxy'}))
CalibrationData=0;
else
f = p.Results.f;
k1 = p.Results.k1;
R = p.Results.R;
T = p.Results.T;
Rmir = p.Results.Rmir;
157
Tmir = p.Results.Tmir;
cxcy = p.Results.cxcy;
dxy = p.Results.dxy;
CalibrationData =
struct('f',f,'k1',k1,'R',R,'T',T,'Rmir',Rmir,'Tmir',Tmir,'cxcy',cxcy,'dxy',dxy);
end
%% create persistent objects and figures
vid = videoinput('AVTMatlabAdaptor_R2009b', 1, 'F7M0_Mono8_1628x1236'); % create
VideoInput object
% vid = videoinput('winvideo');
set(vid,'Timeout',70);
src = getselectedsource(vid);
[fsfig,fsax,fsimg,fssiz] = FullscreenFig(2); % open full screen figure on monitor 2
caxis(fsax,[0,255]);
caxis('manual');
set(fsimg,'cdata',255.*ones(fssiz));
fs = struct('FigureHandle', fsfig, 'AxisHandle', fsax, 'ImageHandle', fsimg, 'Size',
fssiz);
% wizard control and instruction figure
figwiz = pptfig('Deflectometer Wizard',1);
ss = get(0,'screensize');
fwsiz = [500,250];
set(figwiz,'outerposition',[1+2, ss(4)-fwsiz(2)+2,
fwsiz],'resize','off','CloseRequestFcn',@cancel);
numbut = 4;
but = zeros(numbut,1);
spac = 0.1/numbut;
for ij = 1:numbut
but(ij) = uicontrol('style','pushbutton','units','normal','position',[(ij-1)*(1-
spac)/numbut+spac, spac*fwsiz(1)/fwsiz(2), (1-spac*(numbut+1))/numbut, 0.2]);
end
txwiz = uicontrol(figwiz,'style','text','units','normal','position',[0.05,
spac*fwsiz(1)/fwsiz(2)*2+0.2, 0.4, 1-(spac*fwsiz(1)/fwsiz(2)*2+0.2)-
0.1],'backgroundcolor','w','HorizontalAlignment','left','fontsize',12);
axwiz = axes('parent',figwiz,'units','normal','position',[0.5,
spac*fwsiz(1)/fwsiz(2)*2+0.2, 0.5, 1-(spac*fwsiz(1)/fwsiz(2)*2+0.2)],
'visible','off','ylim',[-0.2 1.8]);
awpos = getpixelposition(axwiz);
set(axwiz,'xlim',awpos(3)./awpos(4).*[-1,1]);
% graphics objects
opengl software;
ang = 30; % graphical camera angle from vertical
raydir = [tand(ang),1];
raydirc = raydir.*[1 -1];
camsca = 0.3;
camverts = -1.6.*raydirc; % camera origin
camverts = [camverts;camverts+camsca.*raydirc+camsca./4.*raydirc([2,1]).*[-1
1];camverts+camsca.*raydirc-camsca./4.*raydirc([2,1]).*[-1 1]];
158
gcam = patch('vertices',camverts,'faces',1:3,'edgecolor',[0 .7
0],'linewidth',1.5,'facecolor','g','facealpha',0.5,'parent',axwiz,'linesmoothing','on');
trapx0 = bsxfun(@plus,repmat(-1:1,3,1),0.5.*(-1:1).');
trapy0 = repmat(-0.5.*(-1:1).',1,3);
mirsca = 0.38;
gmir(1) = patch('vertices',mirsca.*[trapx0(:),trapy0(:)],'faces',[1 3 9
7],'edgecolor','k','facecolor','none','linewidth',1.5,'parent',axwiz,'linesmoothing','on'
);
gmir(2) =
line('xdata',0.5.*mirsca.*trapx0(:),'ydata',0.7.*mirsca.*trapy0(:),'color','k','marker','
.','linestyle','none','parent',axwiz);
monsca = 0.7;
gmon =
patch('vertices',[monsca.*trapx0(:)+raydir(1),monsca.*trapy0(:)+raydir(2)],'faces',[1 3 9
7],'edgecolor','b','facecolor','b','facealpha',0.5,'linewidth',1.5,'parent',axwiz,'linesm
oothing','on');
parsca = 0.15;
traparx = parsca.*(bsxfun(@plus,trapx0,[0.3;0;0]));
trapary = parsca.*(bsxfun(@plus,trapy0,[0.5;0;0]));
gpar = patch('vertices',[traparx(:),trapary(:)],'faces',[1 2 3 6 9 8 7
4],'edgecolor','r','facecolor','r','facealpha',0.5,'linewidth',1.5,'parent',axwiz,'linesm
oothing','on');
grai =
line('xdata',[camverts(1,1);0;raydir(1)],'ydata',[camverts(1,2);0;raydir(2)],'linestyle',
'--','color','k','linesmoothing','on');
% preview window with slice chart
figprev = pptfig('Camera Preview',10);
vidres = get(vid,'VideoResolution');
set(figprev,'position',[4, ss(4)-fwsiz(2)-round(vidres(2)/2)-100,
round(vidres./2)],'CloseRequestFcn',@hideprev);
axprev =
axes('parent',figprev,'units','normal','position',[0,0,1,1],'visible','off','xlimmode','m
anual','xlim',[0.5,vidres(1)+0.5],'ylimmode','manual','ylim',[0.5,vidres(2)+0.5]);
imgprev = imshow(zeros(vidres([2,1])),[0,255],'parent',axprev);
preview(vid,imgprev);
linroi = imline(axprev,[100,100;300,100]);
setColor(linroi,'b');
boxfcn = makeConstrainToRectFcn('imline',[1 vidres(1)],[1 vidres(2)]); % confine line ROI
to image boundaries
setPositionConstraintFcn(linroi,boxfcn);
slicax(1) = line('xdata',[100;100],'ydata',100+[-10,10],'color','b','HitTest','off');
slicax(2) = line('xdata',[300;300],'ydata',100+[-10,10],'color','b','HitTest','off');
slicplot = line('xdata',[100;300],'ydata',100+[-10,10],'color','r','HitTest','off');
hideprev();
setappdata(imgprev,'UpdatePreviewWindowFcn',@slicechart);
%% Focus and Exposure adjustments
set(txwiz,'string','Adjust Focus and/or Exposure?');
buttonset({'Exit','Focus','Exposure','Next'},{@cancel,@focadj,@expadj,@OK},{'off','on','o
n','off'});
159
set([gcam,gmir,gmon,gpar,grai],'visible','off');
exitflag = false;
figure(figwiz);
uiwait(figwiz);
if exitflag
return;
end
%% Deflectometer Calibration
buttonset({'Exit','','',''},{@cancel,0,0,0});
set(txwiz,'string','Checking for existing calibration data...');
set([gcam,gmir,gmon,gpar,grai],'visible','off');
if any(cellfun(@(str)
any(strcmp(str,p.UsingDefaults)),{'f','k1','R','T','Rmir','Tmir','cxcy','dxy'}))
set(txwiz,'string','Position MIRROR in camera''s field of view for calibration.');
set([gcam,gmir,gmon,grai],'visible','on');
buttonset({'Cancel','','','Continue'},{{@cancel,figwiz},0,0,@(~,~)
uiresume(figwiz)});
set(fsimg,'cdata',255.*ones(fssiz));
drawnow expose;
% pfig = prevlink(@(~,~) uiresume(figwiz));
preview(vid,imgprev);
uiwait(figwiz);
% if ishandle(pfig)
% delete(pfig);
% end
hideprev();
if exitflag
exitflag = false;
return;
end
buttonset({'Exit','','',''},{@cancel,0,0,0});
set(txwiz,'string','Deflectometer Calibration');
[f,k1,R,T,Rmir,Tmir,cxcy,dxy,exitflag] = DW_DeflectometerCalibration(txwiz,but(1));
if exitflag
return;
end
else
f = p.Results.f;
k1 = p.Results.k1;
R = p.Results.R;
T = p.Results.T;
Rmir = p.Results.Rmir;
Tmir = p.Results.Tmir;
cxcy = p.Results.cxcy;
dxy = p.Results.dxy;
end
CalibrationData =
struct('f',f,'k1',k1,'R',R,'T',T,'Rmir',Rmir,'Tmir',Tmir,'cxcy',cxcy,'dxy',dxy);
assignin('base','CalibrationData',CalibrationData);
160
%% Focus and Exposure adjustment for part only
wizFE();
exitflag = false;
figure(figwiz);
uiwait(figwiz);
if exitflag
return;
end
%% Capture Phase Shift Data
set(txwiz,'string','Position PART in camera''s field of view.');
set([gcam,gpar,gmon,grai],'visible','on');
buttonset({'Exit','','','Continue'},{@cancel,0,0,@(~,~) uiresume(figwiz)});
set(fsimg,'cdata',255.*ones(fssiz));
drawnow expose;
% pfig = prevlink(@(~,~) uiresume(figwiz));
preview(vid,imgprev);
uiwait(figwiz);
permm = 100.*monpp;
set(txwiz,'string','Adjust VERTICAL fringe period. Aim for low value while maintaining
contrast.');
set([gcam,gmir,gmon,gpar,grai],'visible','off');
slid = uicontrol('style','slider','units','normal','position',[0.05,
spac*fwsiz(1)/fwsiz(2)+0.25, 0.9,
0.2],'value',round(permm(1)/monpp(1)),'callback',{@peradj,1},'min',20,'max',500);
peradj(slid,0,1);
uiwait(figwiz);
permm(1) = get(slid,'value').*monpp(1);
set(txwiz,'string','Adjust HORIZONTAL fringe period. Aim for low value while maintaining
contrast.');
set(slid,'value',round(permm(2)/monpp(2)),'callback',{@peradj,2},'min',20,'max',500);
peradj(slid,0,2);
uiwait(figwiz);
permm(2) = get(slid,'value').*monpp(2);
hideprev();
delete(slid);
if exitflag
exitflag = false;
return;
end
buttonset({'Exit','','',''},{@cancel,0,0,0});
set(txwiz,'string','');
[v1234lin,h1234lin,linmm,permm,exitflag] =
DW_PhaseShiftCapture(txwiz,cutdn,cutup,monpp,permm,but(1));
%% Fiducial picture
set(txwiz,'string','Place caliper on surface for fiducial definition.');
set([gcam,gpar,gmon,grai],'visible','on');
buttonset({'Exit','','','Take Pic'},{@cancel,0,0,@(~,~) uiresume(figwiz)});
set(fsimg,'cdata',cutup.*ones(fssiz));
161
drawnow expose;
preview(vid,imgprev);
uiwait(figwiz);
fidpic = capic(cutup.*ones(fssiz));
fidfig = pptfig('Fiducial Picture',8);
fidimg = imagesc(fidpic);
buttonset({'Exit','','Re-take','Continue'},{@cancel,0,@retake,@(~,~) uiresume(figwiz)});
uiwait(figwiz);
fidist0 = inputdlg('Enter caliper distance in inches:','Fiducial spacing');
if isempty(fidist0)
fidist0 = {0};
end
fidist = str2double(fidist0{1})*25.4; % fiducial spacing in mm
if isnan(fidist)
fidist = 0;
end
%% Prepare output data
[curpath,~,~] = fileparts(mfilename('fullpath'));
pn = [curpath '\Data\Part.mat'];
set(txwiz,'string','Save data.');
set([gcam,gpar,gmon,grai,gmir],'visible','off');
buttonset({'Exit','','','Save Data'},{@cancel,0,0,{@savdat,pn}});
savdat(0,0,pn);
if ~exitflag
uiwait(figwiz);
end
%% Cleanup
cancel(0,0);
%% nested functions
function retake(~,~)
fidpic = capic(cutup.*ones(fssiz));
set(fidimg,'cdata',fidpic);
drawnow expose;
end
function pic = capic(cdat)
set(fsimg,'cdata',cdat);
drawnow expose;
pause(0.5);
start(vid);
pic = uint8(squeeze(mean(getdata(vid),4)));
end
function slicechart(~,event,~)
cdat = mean(event.Data,3); % if image is in color
slic = getPosition(linroi);
tvec = diff(slic,1,1);
tdist = sqrt(sum(tvec.^2));
162
if tdist==0
return;
end
tval = linspace(0,1,ceil(tdist)).';
tpxy = round(bsxfun(@plus,slic(1,:),tval*tvec));
tpid = sub2ind(size(cdat),tpxy(:,2),tpxy(:,1));
tdat0 = cdat(tpid);
tdat = (tdat0-min(tdat0))./(max(tdat0)-min(tdat0)).*2-1; % normalize to interval
[-1,1]
aspec = 10; % plot aspect ratio Width/halfHeight
if round(slic(1,1))==round(slic(2,1))
zvec = [tdist/aspec,0];
else
zvec = [-1,1].*tvec([2,1])./aspec;
zvec = -sign(zvec(2)).*zvec;
end
xy = bsxfun(@plus,slic(1,:),tval*tvec+tdat*zvec);
set(slicplot,'xdata',xy(:,1),'ydata',xy(:,2));
set(slicax(1),'xdata',zvec(1).*[-1;1]+slic(1,1),'ydata',zvec(2).*[-
1;1]+slic(1,2));
set(slicax(2),'xdata',zvec(1).*[-1;1]+slic(2,1),'ydata',zvec(2).*[-
1;1]+slic(2,2));
set(imgprev,'cdata',cdat);
drawnow expose;
end
function peradj(slid,~,vh)
val0 = get(slid,'value');
val = round(val0);
set(slid,'value',val);
switch vh
case 1
dir = [1,0];
case 2
dir = [0,1];
end
apod = DW_apodizationgen(dir,val*monpp(vh),0,'cos',[cutdn,cutup],monpp);
caxis(fsax,[0,255]);
set(fsimg,'cdata',apod);
end
function savdat(~,~,pn)
uisave({'cutup','cutdn','v1234lin','h1234lin','linmm','permm','CalibrationData','fidpic',
'fidist'},pn);
end
function wizFE()
set(txwiz,'string','Adjust Focus and/or Exposure?');
163
buttonset({'Exit','Focus','Exposure','Next'},{@cancel,@focadj,@expadj,@OK},{'off','on','o
n','off'});
set([gcam,gmir,gmon,gpar,grai],'visible','off');
uiwait(figwiz);
end
function expadj(~,~)
set(txwiz,'string','Position MIRROR and PART in camera''s field of view.');
set([gcam,gmir,gmon,gpar,grai],'visible','on');
buttonset({'Cancel','','','Continue'},{{@cancel,figwiz},0,0,@(~,~)
uiresume(figwiz)});
caxis(fsax,[0,255]);
set(fsimg,'cdata',cutup.*ones(fssiz));
drawnow expose;
preview(vid,imgprev);
uiwait(figwiz);
hideprev();
if exitflag
exitflag = false;
wizFE();
return;
end
set(txwiz,'string','Adjust slider until pixels are bright but do not saturate.');
figcon = DW_ExposureAdjust(cutup);
buttonset({'','','','Done'},{0,0,0,{@OK,figcon}});
uiwait(figcon);
if ishandle(figcon)
close(figcon);
end
wizFE(); % reset wizard window
end
function focadj(~,~)
set(txwiz,'string','Position mirror in camera''s field of view.');
set([gcam,gmir,gmon,grai],'visible','on');
buttonset({'Cancel','','','Continue'},{{@cancel,figwiz},0,0,@(~,~)
uiresume(figwiz)});
set(fsimg,'cdata',255.*ones(fssiz));
preview(vid,imgprev);
uiwait(figwiz);
hideprev();
if exitflag
exitflag = false;
wizFE();
return;
end
set(txwiz,'string','');
figimg = pptfig('Focus Helper',7);
set(figimg,'visible','off');
buttonset({'','','',''},{0,0,0,''});
164
DW_FocusAdjust(figimg,txwiz,but(4));
wizFE(); % reset wizard window
end
% function fig = prevlink(xfcn)
% fig = preview(vid);
% % if the object is a figure or figure descendent, return the figure. Otherwise
return [].
% while ~isempty(fig) && ~strcmp('figure', get(fig,'type'))
% fig = get(fig,'parent');
% end
% set(fig,'CloseRequestFcn',xfcn);
% end
function hideprev(~,~)
if strcmp(get(figprev,'visible'),'on');
closepreview(vid);
set(figprev,'visible','off');
end
end
function buttonset(strings,callbacks,varargin)
% strings is a cell array of strings corresponding to the buttons in the
% wizard figure.
% an empty string will hide the associated button
% callbacks is a cell array of callback function handles
exind = find(~strcmpi(strings,'')); % find indices of non-empty strings
set(but,'visible','off');
if nargin>2
intrup = varargin{1};
else
intrup = {'off','off','off','off'};
end
for ji = exind(:).'
set(but(ji),'string',strings{ji},'visible','on','callback',callbacks{ji},'interruptible',
intrup{ji});
end
drawnow expose;
end
function OK(~,~,varargin)
if nargin>2
uiresume(varargin{1});
else
uiresume(figwiz);
end
end
function cancel(~,~,varargin)
if nargin>2
165
exitflag = true;
uiresume(varargin{1});
else
qans = questdlg('Exit the Deflectometer Wizard?','Quit?','No','Yes','Yes');
if strcmp(qans,'Yes');
exitflag = true;
figHandles = findobj('Type','figure');
set(figHandles,'CloseRequestFcn','');
uiresume(figwiz);
delete(figHandles);
close all;
end
end
end
end
%% accessory functions
% function [tax,txt] = axtext(fhan,string,varargin)
% p = inputParser;
% p.KeepUnmatched = true;
% addRequired(p,'fhan',@ishandle);
% addRequired(p,'string',@ischar);
% addParamValue(p,'units','normal',@(x)
any(validatestring(x,{'normalized','inches','centimeters','points','pixels','characters'}
)));
% addParamValue(p,'position',[0.1,0.1,0.8,0.8],@(x) (isnumeric(x) &&
all(size(x)==[1,4])));
% addParamValue(p,'HorizontalAlignment','left',@(x)
any(validatestring(x,{'left','center','right'})));
% addParamValue(p,'VerticalAlignment','bottom',@(x)
any(validatestring(x,{'bottom','middle','top'})));
% parse(p,fhan,string,varargin{:});
%
% textinputs = transpose(fieldnames(p.Unmatched));
% for ij = 1:numel(textinputs)
% textinputs{2,ij} = p.Unmatched.(textinputs{1,ij});
% end
%
% switch p.Results.HorizontalAlignment
% case 'left'
% x = -1;
% case 'center'
% x = 0;
% case 'right'
% x = 1;
% end
% switch p.Results.VerticalAlignment
% case 'bottom'
% y = -1;
% case 'middle'
166
% y = 0;
% case 'top'
% y = 1;
% end
% tax =
axes('parent',p.Results.fhan,'units',p.Results.units,'position',p.Results.position,'xtick
',[],'ytick',[],'xlim',[-1,1],'ylim',[-1,1],'visible','off');
% txt =
text(x,y,p.Results.string,'parent',tax,'HorizontalAlignment',p.Results.HorizontalAlignmen
t,'VerticalAlignment',p.Results.VerticalAlignment,textinputs{:});
% end
DataProcessor.m
This section shows the high level MATLAB code for the fringe reflection deflectometer’s
data processing function. Images of the figures that appear during its execution are
interspersed. The purpose of this section is to illustrate the user interface of the data processing
code. The queried input requires a data file produced by DeflectometerWizard.m.
Get data file from data acquisition
pn0 = 'C:\Users\Dan\Google Drive\Thesis\Fringe Reflection Metrology\Deflectometer
Wizard\Data';
[fn, pn] = uigetfile('*.mat', 'Select a data file', pn0);
if isequal(fn,0)
disp('User selected Cancel')
return;
end
load('-mat', [pn fn]);
str = {'R3mini'; 'R3wrong'; 'R3fixed';'flat'};
[s,v] = listdlg('PromptString','Select a
shape:','SelectionMode','single','ListString',str);
if isequal(v,0)
disp('User selected Cancel')
return;
elseif s==4
shapename_cell = inputdlg({'Dimension in guiding direction (mm)','Dimension in
extrusion direction (mm)'});
shapename = reshape(cellfun(@str2double, shapename_cell),1,2);
else
shapename = str{s};
end
167
Unwrap phase
[unwpx,unwpy,croprect,xyoffset,nmask,wpx,wpy] =
DP_PhaseUnwrapper(v1234lin,h1234lin,linmm,permm);
Figure B.1: Shows vertical and horizontal wrapped phase data and asks user to outline part leaving a buffer of background pixels.
168
Figure B.2: PUMA algorithm unwraps data within region of interest.
169
Figure B.3: Results of noise amplitude analysis.
Figure B.4: Histogram of noise amplitudes. Red line shows cutoff amplitude for what is considered noise.
170
Figure B.5: Left column: noisy data deleted. Right column: noise mask edges smoothed and rouge data pixels mended.
171
Figure B.6: Calculated X and Y positions on the monitor. Shading relates loosely to surface slope in each direction.
172
Edit mask if necessary
Gives opportunity to manually edit noise mask.
v1234lincrop = zeros([size(nmask),5]);
h1234lincrop = v1234lincrop;
for ij = 1:5
v1234lincrop(:,:,ij) = imcrop(v1234lin(:,:,ij),croprect);
h1234lincrop(:,:,ij) = imcrop(h1234lin(:,:,ij),croprect);
end
fidpicrop = imcrop(fidpic,croprect);
nmask = DP_MaskEditor(nmask,v1234lincrop,h1234lincrop,wpx,wpy,unwpx,unwpy,fidpicrop);
unwpxc = unwpx;
unwpxc(~nmask) = nan;
unwpyc = unwpy;
unwpyc(~nmask) = nan;
Find approximate location of data points relative to camera based on ideal shape
[xs,ys,zs,xc,yc,Ropt,Topt,lindist,lmask1,lmask2,shapename] =
DP_placepart3d_edge(CalibrationData.f,CalibrationData.k1,CalibrationData.cxcy,Calibration
Data.dxy,CalibrationData.Rmir,CalibrationData.Tmir,nmask,xyoffset,shapename,imcrop(fidpic
,croprect),fidist);
173
Figure B.7: Sample points from ideal surface shape are overlayed over data from the deflectometer camera. The green and cyan dots on the edge denote the surface points used as fiducial lines pertaining to the part edges. If a caliper tip fiducial is used, the user must pick the location of the caliper tips in the image instead.
Find xyz position of each pixel of data
[surfptsx,surfptsy,surfptsz] =
DP_lsqiter(nmask,unwpx,unwpy,CalibrationData.R,CalibrationData.T,xyoffset,CalibrationData
.cxcy,CalibrationData.dxy,CalibrationData.f,CalibrationData.k1,xs,ys,zs,xc,yc,Ropt,Topt,l
indist,lmask1,lmask2,CalibrationData.Rmir,CalibrationData.Tmir);
174
Figure B.8: Optimization iterations to find calculated XYZ points of the part surface. The value is the average distance from the camera origin. In this case, the initial guess is rather accurate.
175
Figure B.9: Initial guess vs. optimization solution.
Figure B.10: XYZ data for calculated surface.
176
Figure B.11: Principal curvature maps of calculated data. Principal curvature k1 (left), principal curvature k2 (center), Gaussian curvature (right).
Register data to model shape and position to relative to assembled system origin
The user is asked to provide input to position the data with respect to the ideal surface
coordinate system by adjusting translational and rotational variables in a semi-automated
fashion. The surface error from ideal is calculated from the final registered position.
if isnumeric(shapename)
spacing = 0.5;
sampnum = ceil(shapename./spacing);
else
sampnum = [29,200];%[114,200]; % number of samples [along curve, in extrusion
direction]
end
edthresh = 1; % mm, longest allowed edge of triangulation simplex (to get rid of
"webbing")
[xyzreg,xyzfin,Mxyzfin,err,errvec] =
DP_DataRegister3D(surfptsx,surfptsy,surfptsz,shapename,sampnum,edthresh);
177
Figure B.12: Registered data showing error from ideal surface.
Dependency: DW_apodizationgen.m
Generates fringe images at native monitor resolution for accurate display in
deflectometer apparatus.
function [apod,X,Y] = DW_apodizationgen(dir,per,phas,shape,lvls,varargin)
% apodizationgen(siz,dir,per,varargin)
%
% INPUTS
% dir = direction vector of modulation [x,y]
%
% per = period of modulation in mm
%
% phas = phase shift (radians)
%
% shape = modulation shape ('sine'|'sin', 'cosine'|'cos', 'step')
%
% lvls = [low,high] displayed level cuttoff between 0 and 255 for uint8 display (e.g.
[cutdn,cutup])
%
178
% varargin{1} = pixel pitch in mm (scalar or 1x2 vector [x,y])
% or
% varargin{1,2} = physical size of display in mm (x,y)
% need one of these options
%
% OUTPUTS
% X = x spatial coordinates in mm
%
% Y = y spatial coordinates in mm
%
% apod = apodization function
global fs
siz = fs.Size([2,1]); % matrix size [x,y] of apodization file
switch nargin
case 6
% sizmm = siz.*varargin{1};
pp = [1,1].*varargin{1};
case 7
% sizmm = [varargin{1},varargin{2}];
pp = [varargin{1},varargin{2}]./siz;
otherwise
error('Invalid pixel pitch or screen size inputs');
end
% umin = -sizmm(1)/2;
% vmin = -sizmm(2)/2;
% umax = -umin;
% vmax = -vmin;
% x = linspace(umin,umax,siz(1))./siz(1).*(siz(1)-1);
% y = linspace(vmin,vmax,siz(2))./siz(2).*(siz(2)-1);
x = (1:1:siz(1)).*pp(1);
y = (1:1:siz(2)).*pp(2);
[X,Y] = meshgrid(x,y);
dirnorm = dir./norm(dir);
dist = X.*dirnorm(1) + Y.*dirnorm(2); % distance from origin in direction of 'dir'
vector
switch shape
case {'sine','sin'}
apod = sin(2.*pi.*(dist)./per + phas);
apod = uint8((apod+1)./2.*diff(lvls)+lvls(1));
case {'cosine','cos'}
apod = cos(2.*pi.*(dist)./per + phas);
apod = uint8((apod+1)./2.*diff(lvls)+lvls(1));
case 'step'
179
apod = uint8((mod(dist+phas/(2*pi)*per,per) > (per/2)).*diff(lvls)+lvls(1));
otherwise
error('Invalid shape input');
end
% % write to LT apodization file
% fn = 'C:\Users\Dan\Documents\Thesis\Fringe Reflection Metrology\TempApod.txt';
% fid = fopen(fn,'w');
% % header = ['MESH: ' num2str(n) ' ' num2str(m) ' ' num2str(umin) ' ' num2str(vmin) ' '
num2str(umax) ' ' num2str(vmax)];
% fprintf(fid,'MESH: %u\t%u\t%0.3f\t%0.3f\t%0.3f\t%0.3f\r\n',n,m,umin,vmin,umax,vmax);
% fclose(fid);
% dlmwrite(fn,apod,'-append','delimiter','\t');
%
% % plot
% figure(1);
% imagesc(x,y,apod);
% set(gca,'YDir','normal');
% hold on;
% plot(0,0,'dr');
% hold off;
% colormap('gray');
% axis equal;
Dependency: DW_CamCalibration.m
Camera calibration routine that finds camera position and orientation relative to
calibration flat coordinate system and intrinsic camera properties (lens focal length and radial
distortion).
function [R,T,f,k1,mert,cxcy] = DW_CamCalibration(CamInfo,TargetInfo,img0,varargin)
%
% Based on paper:
% "A Versatile Camera Calibration Technique for High-Accuracy 3D Machine
% Vision Metrology Using Off-the-Shelf TV Cameras and Lenses", Roger Y.
% Tsai, IEEE Journal of Robotics and Automation, Vol. RA-3, NO.4, August
% 1987
% Note paper confuses units of variables Xd, Yd, Xu, Yu, so they don't line
% up with how they are used in the following code
%
% [R,T,f,k1,mert] = CamCalibration(CamInfo,TargetInfo,Image);
% [R,T,f,k1,mert] = CamCalibration(___,'ParameterName',ParameterValue);
%
% INPUT:
% CamInfo = structure containing camera data, fields: 'dx','Ncx','dy'
% TargetInfo = structure containing target data, fields: 'ptx','pty','names'
% Image = input image of calibration points
180
% INPUT PARAMETERS:
% 'fk1' = [f,k1] if known
% 'cpts' = image coordinates of control points if known
% 'invert' = logical flag of whether to invert image before processing (want black
background)
% 'opense' = imopen structing element i.e. strel('disk',7). if empty then no opening
will be performed (default)
%
% OUTPUT:
% R = Rotation matrix to go from target object plane to image plane
% T = Translation matrix to go from target object plane to image plane
% where [ximg;yimg;zimg] = R*[xtarget;ytarget;ztarget] + T
% f = lens focal length
% k1 = lens distortion coefficient ( X_real = X_distorted*(1+k1*r^2), where r^2 =
X_distorted^2 + Y_distorted^2 )
% mert = merit function value of fit (greatest deviation from control point, in
pixels)
% parse input arguments
p = inputParser;
p.addRequired('CameraInformation',@(x) all(isfield(x,{'dx','Ncx','dy'})));
p.addRequired('TargetInformation',@(x) all(isfield(x,{'ptx','pty','names'})));
p.addRequired('Image',@isnumeric);
p.addParamValue('fk1',[0,0],@(x) isnumeric(x) & numel(x)==2);
p.addParamValue('cpts',[0,0],@(x) isnumeric(x) & size(x,2)==2);
p.addParamValue('invert',true,@(x) numel(x)==1);
p.addParamValue('opense',[],@(x) numel(x)<2); % imopen structing element i.e.
strel('disk',7), if = [], then no opening will be performed
p.parse(CamInfo,TargetInfo,img0,varargin{:});
fk1 = p.Results.fk1;
cpts = p.Results.cpts;
invert = p.Results.invert;
opense = p.Results.opense;
fk1_unknown = all(fk1==0); % true if f and k1 are not provided
cpts_unknown = all(cpts==0); % true if image coordinates are not provided
%%% 1)a)ii) Obtain Ncx, Nfx, dxp, dy according to (6c)-(6h) using information of camera
and frame memory supplied by manufacturer.
dx = CamInfo.dx; % x direction pixel pitch in mm
Ncx = CamInfo.Ncx; % number of pixels in x direction on camera sensor
dy = CamInfo.dy; % y direction pixel pitch in mm
sx = 1; % uncertainty scale factor for x, due to TV camera scanning error and CCD
acquisition timing error
%%% 1)a)i) Grab a frame into the computer frame memory. Detect the row and column number
of each calibration point i. Call it (Xfi, Yfi).
if size(img0,3) == 3;
img = rgb2gray(img0);
181
else
img = img0;
end
imgsiz = size(img);
Nfx = imgsiz(2); % number of pixels in raw captured image
dxp = dx*Ncx/Nfx; % Ncx/Nfx will probably always be unity for the cameras used (not so
for TV cameras from 1987)
%%% 1)a)iii)
Cx = ceil(imgsiz(2)/2);
Cy = ceil(imgsiz(1)/2);
cxcy = [Cx,Cy];
xw = TargetInfo.ptx;
yw = TargetInfo.pty;
names = TargetInfo.names;
gsiz = size(xw);
zw = zeros(gsiz);
numpts = numel(xw);
% plot original image
figimg = pptfig('Original Image', 1); % set(gcf,'name','Original Image');
imshow(img);
aximg = gca;
origxlim = xlim;
origylim = ylim;
% might need some extra steps here before converting to binary (e.g. imopen)
if ~isempty(opense)
if invert
img = imclose(img,opense);
else
img = imopen(img,opense);
end
figopen = pptfig('Morphologically Opened Image', 2);
imshow(img);
figure(figimg);
end
imgbw = im2bw(img, graythresh(img)); % convert to binary image using automatic threshold
value
if invert
imgbw = ~imgbw; % invert image
end
imgcc = bwconncomp(imgbw, 8); % find connected components
ccnum0 = imgcc.NumObjects;
bndsiz = [1,1,imgsiz([2,1])];
if ccnum0 > 2*numpts
mbo = msgbox('Too many objects found. Select a region of interest.');
uiwait(mbo);
figure(figimg);
set(figimg,'name','Choose ROI');
roimask = 0;
182
okbut = uicontrol(figimg,'style','pushbutton','units','normal','position',[.45 .01 .1
.08],'string','Continue','callback',@roisel,'fontsize',12,'fontweight','bold');
roih = imrect(aximg);
uiwait(figimg);
delete(okbut);
bndsiz = getPosition(roih);
set(roih,'visible','off');
set(figimg,'name','Original Image');
drawnow;
imgbw = imgbw.*roimask;
imgcc = bwconncomp(imgbw, 8); % find connected components
ccnum0 = imgcc.NumObjects;
end
imgrp = regionprops(imgcc,img,'all'); % find connected component properties (Area,
Centroid, BoundingBox)
% areas = [imgrp.Area]; % get vector of CC areas
% [~, backind] = max(areas); % find large foreground object (originally black background
beyond mirror edges)
bbs = reshape([imgrp.BoundingBox],4,[]).';
bbs(:,3) = bbs(:,1)+bbs(:,3);
bbs(:,4) = bbs(:,2)+bbs(:,4);
bndsiz(3) = bndsiz(1)+bndsiz(3);
bndsiz(4) = bndsiz(2)+bndsiz(4);
backind = find( bbs(:,1)<=(bndsiz(1)+0.5) | bbs(:,3)>=(bndsiz(3)-0.5) |
bbs(:,2)<=(bndsiz(2)+0.5) | bbs(:,4)>=(bndsiz(4)-0.5) ); % find foreground objects that
touch edges of frame
% % display binary image
% imgbw(imgcc.PixelIdxList{backind}) = false; % delete "backind" object
% figure(5); set(gcf,'name','Dot Find');
% imshow(imgbw); % show new binary image
% axbw = gca;
% update connected component and region properties lists
ccnum = ccnum0-numel(backind);
newcc = setdiff(1:ccnum0,backind);
imgcc.NumObjects = ccnum;
imgcc.PixelIdxList = imgcc.PixelIdxList(newcc);
imgrp = imgrp(newcc);
centroids = [imgrp.Centroid];
centroids = reshape(centroids,2,ccnum).';
diams = [imgrp.EquivDiameter];
% plot found points
for ri = 1:ccnum
line(imgrp(ri).ConvexHull(:,1),imgrp(ri).ConvexHull(:,2),'color','g','parent',aximg,'line
width',2);
end
% get input for camera coordinates of calibration points
ccind = zeros(gsiz);
183
cplab = ccind;
txtoff = mean(diams);
Xf = zeros(gsiz);
Yf = Xf;
if cpts_unknown
% poind = [1;gsiz(1);numpts-
gsiz(1)+1;numpts;sub2ind(gsiz,ceil(gsiz(1)/2),ceil(gsiz(2)/2))]; % indicies of initial
colibration points: [top left; bottom left; top right; bottom right; center]
poind = [1;3;7;9;4];
figure(figimg);
for ci = poind(:).'
title(['Click near "' names{ci} '"']);
[Xf0,Yf0] = ginput(1);
[~,ccind(ci)] = min( (centroids(:,1)-Xf0).^2 + (centroids(:,2)-Yf0).^2 );
cplab(ci) =
text(centroids(ccind(ci),1)+txtoff,centroids(ccind(ci),2)+txtoff,names{ci},'parent',aximg
,'color','r');
xlim(origxlim);
ylim(origylim);
end
title('Calibrataion Points');
Xf(poind) = centroids(ccind(poind),1);
Yf(poind) = centroids(ccind(poind),2);
scootcoord = 100.*max([max(abs(Xf(:))),max(abs(Yf(:)))]); % scalar, out-of-the-way
coordinate value (max of x and y) to put invalid centroids so they are not picked later
gooddiam = mean(diams(ccind(poind)));
badlist = unique([find(diams>1.5*gooddiam);find(diams<0.5*gooddiam)]);
centroids(badlist,:) = scootcoord;
% initial calibration with 5 points
Xui = Xf-Cx; % image plane coordinates in px
Yui = Yf-Cy;
%%% 1)a)iv) Compute (Xdi, Ydi) using (6a) and (6b)
Xdi = sx^(-1) .* dxp .* (Xui); % image plane coordinates in mm
Ydi = dy .* (Yui);
%%% 1)b) Compute the five unknowns r1/Ty, r2/Ty, Tx/Ty, r4/Ty, r5/Ty
initlinsysLi = [Ydi(poind).*xw(poind), Ydi(poind).*yw(poind), Ydi(poind), -
Xdi(poind).*xw(poind), -Xdi(poind).*yw(poind)]; % A
initlinsysRi = Xdi(poind); % b
fui = initlinsysLi\initlinsysRi; % solution to: A * x = b where x = fui (see Matlab
"systems of linear equations" help)
%%% 1)c)1) Compute abs(Ty) from r1/Ty, r2/Ty, Tx/Ty, r4/Ty, r5/Ty
Ci = fui([1,2;4,5]);
if any(sum(Ci.^2,1)==0) || any(sum(Ci.^2,2)==0)
Ty2i = 1/sum(Ci(:).^2);
else
184
Sri = sum(Ci(:).^2);
Ty2i = (Sri-sqrt(Sri.^2-4*det(Ci)^2))/(2*det(Ci)^2);
end
%%% 1)c)2)i) Pick an object point i whose computer image coordinate (Xfi, Yfi) is
away from the image center (Cx, Cy)
[~,Tytestind0] = max(Ydi(poind).^2+Xdi(poind).^2);
Tytestind = poind(Tytestind0);
%%% 1)c)2)ii) Pick the sign of Ty to be +1
Ty0i = sqrt(Ty2i);
%%% 1)c)2)iii) Compute r1, r2, r4, r5, Tx, x, and y
Ri = zeros(3); % 3D rotation matrix, Ri
Ri(1:2,1:2) = Ci.*Ty0i;
Txi = fui(3)*Ty0i;
xi = Ri(1).*xw(Tytestind) + Ri(4).*yw(Tytestind) + Txi;
yi = Ri(2).*xw(Tytestind) + Ri(5).*yw(Tytestind) + Ty0i;
%%% 1)c)2)iv) Calculate sign of Ty
if sign(xi)==sign(Xdi(Tytestind)) && sign(yi)==sign(Ydi(Tytestind));
Tyi = Ty0i;
else
%%% 1)c)3)i) Adjust calculated values from 1)c)2)iii) if Ty<0
Tyi = -Ty0i;
Ri = -Ri;
Txi = -Txi;
end
%%% 1)c)3)ii) Compute R
si = -sign(Ri(1)*Ri(2)+Ri(4)*Ri(5));
Ri(7) = sqrt(1-Ri(1)^2-Ri(4)^2);
Ri(8) = si*sqrt(1-Ri(2)^2-Ri(5)^2);
Ri(3,:) = cross(Ri(1,:),Ri(2,:));
Ri(3,:) = Ri(3,:)./norm(Ri(3,:));
%%% 2)d) Compute an approximation of f and Tz by ignoring lens distortion
yi = Ri(2).*xw(poind) + Ri(5).*yw(poind) + Tyi;
wi = Ri(3).*xw(poind) + Ri(6).*yw(poind);
if fk1_unknown
soliniti = [yi(:), -dy.*Yui(poind)] \ (wi(:).*dy.*Yui(poind));
finiti = soliniti(1);
Tziniti = soliniti(2);
else
soliniti0 = [yi(:), -dy.*Yui(poind)] \ (wi(:).*dy.*Yui(poind));
finiti = sign(soliniti0(1))*fk1(1);
soliniti = (dy.*Yui(poind)) \ (yi(:).*finiti-wi(:).*dy.*Yui(poind));
Tziniti = soliniti;
end
%%% 1)c)3)iii) IF (f < 0) from 2)d), THEN do the following sign switches
if finiti<0
Ri = Ri.*[1 1 -1;1 1 -1;-1 -1 1];
finiti = -finiti;
185
Tziniti = -Tziniti;
end
%% guess where the rest of calibration points are located on the image plane
% disp(Ri);
[Xftst,Yftst,~] =
world2cam(xw,yw,zw,Ri,[Txi;Tyi;Tziniti],finiti,0,[Cx,Cy],[dxp/sx,dy]);
poindi = poind; % indicies of initial calibration points
poind = (1:numpts).'; % indices of all calibration points
poindn = setdiff(poind,poindi); % indices of just the new calibration points
else
poindn = (1:numpts).';
Xftst = reshape(cpts(:,1),gsiz);
Yftst = reshape(cpts(:,2),gsiz);
end
Xf(poindn) = Xftst(poindn);
Yf(poindn) = Yftst(poindn);
line(Xftst(:),Yftst(:),'linestyle','none','marker','x','color','r','parent',aximg);
% find closest centroid to test points
for ci = poindn(:).'
[~,ccind(ci)] = min( (centroids(:,1)-Xf(ci)).^2 + (centroids(:,2)-Yf(ci)).^2 );
cplab(ci) =
text(centroids(ccind(ci),1)+txtoff,centroids(ccind(ci),2)+txtoff,names{ci},'parent',aximg
,'color','r');
end
Xf(poindn) = centroids(ccind(poindn),1);
Yf(poindn) = centroids(ccind(poindn),2);
line(Xf(:),Yf(:),'linestyle','none','marker','+','color','g','parent',aximg);
%% calibration using all calibration points
% method finding all possible solutions, then averaging results
Xu = Xf-Cx; % focal plane coordinates in px
Yu = Yf-Cy;
%%% 1)a)iv) Compute (Xdi, Ydi) using (6a) and (6b)
Xd = sx^(-1) .* dxp .* (Xu);
Yd = dy .* (Yu);
%%% 1)b) Compute the five unknowns r1/Ty, r2/Ty, Tx/Ty, r4/Ty, r5/Ty
initlinsysL = [Yd(:).*xw(:), Yd(:).*yw(:), Yd(:), -Xd(:).*xw(:), -Xd(:).*yw(:)]; % A
initlinsysR = Xd(:); % b
fu = initlinsysL\initlinsysR; % solution to: A * x = b where x = fu (see 'Matlab systems
of linear equations' help)
%%% 1)c) Compute (rl, ..., r9, Tx, Ty) from (r1/Ty, r2/Ty, Tx/Ty, r4/Ty, r5/Ty):
%%% 1)c)1) Compute abs(Ty) from r1/Ty, r2/Ty, Tx/Ty, r4/Ty, r5/Ty
C = fu([1,2;4,5]);
if any(sum(C.^2,1)==0) || any(sum(C.^2,2)==0)
186
Ty2 = 1/sum(C(:).^2);
else
Sr = sum(C(:).^2);
Ty2 = (Sr-sqrt(Sr.^2-4*det(C)^2))/(2*det(C)^2);
end
%%% 1)c)2)i) Pick an object point i whose computer image coordinate (Xfi, Yfi) is away
from the image center (Cx, Cy)
[~,Tytestind] = max(Yd(:).^2+Xd(:).^2);
%%% 1)c)2)ii) Pick the sign of Ty to be +1
Ty0 = sqrt(Ty2); % col vec
%%% 1)c)2)iii) Compute r1, r2, r4, r5, Tx, x, and y
R = zeros(3); % 3D rotation matrix, Ri
R(1:2,1:2) = C.*Ty0;
Tx = fu(3)*Ty0;
x = R(1).*xw(Tytestind) + R(4).*yw(Tytestind) + Tx;
y = R(2).*xw(Tytestind) + R(5).*yw(Tytestind) + Ty0;
%%% 1)c)2)iv) Calculate sign of Ty
if sign(x)==sign(Xd(Tytestind)) && sign(y)==sign(Yd(Tytestind));
Ty = Ty0;
else
%%% 1)c)3)i) Adjust calculated values from 1)c)2)iii) if Ty<0
Ty = -Ty0;
R = -R;
Tx = -Tx;
end
%%% 1)c)3)ii) Compute R
s = -sign(R(1)*R(2)+R(4)*R(5));
R(7) = sqrt(1-R(1)^2-R(4)^2);
R(8) = s*sqrt(1-R(2)^2-R(5)^2);
R(3,:) = cross(R(1,:),R(2,:));
R(3,:) = R(3,:)./norm(R(3,:));
%%% 2)d) Compute an approximation of f and Tz by ignoring lens distortion
y_i = R(2).*xw(:) + R(5).*yw(:) + Ty;
w_i = R(3).*xw(:) + R(6).*yw(:);
if fk1_unknown
solinit = [y_i(:), -dy.*Yu(:)] \ (w_i(:).*dy.*Yu(:));
finit = solinit(1);
Tzinit = solinit(2);
else
solinit0 = [y_i(:), -dy.*Yu(:)] \ (w_i(:).*dy.*Yu(:));
finit = sign(solinit0(1))*fk1(1);
solinit = (dy.*Yu(:)) \ (y_i(:).*finit-w_i(:).*dy.*Yu(:));
Tzinit = solinit;
end
%%% 1)c)3)iii) IF (f < 0) from 2)d), THEN do the following sign switches
if finit<0
R = R.*[1 1 -1;1 1 -1;-1 -1 1];
187
finit = -finit;
Tzinit = -Tzinit;
end
% calculate euler angles from rotation matrix for each case
theta = atan2(-R(7),sqrt(R(1).^2+R(4).^2)); % pitch (rotation about y)
psi = atan2(R(4),R(1)); % roll (rotation about x)
phi = atan2(R(8),R(9)); % yaw (rotation about z)
%%% 2)e) Compute the exact solution for f, Tz, k1
fTzk10 = [finit,Tzinit,0];
if fk1_unknown % f and k1 are NOT provided, optimize over variables f, Tz, and k1
% options = optimset('plotfcns',{@optimplotx,@optimplotfval,@optimplotstepsize});
% flim = [0, finit*2];
% Tzlim = [0, Tzinit*2];
% fTzk1opt = lsqnonlin(@genmert,fTzk10,[min(flim),min(Tzlim),-
0.1],[max(flim),max(Tzlim),0.1]);
% fTzk1opt = lsqnonlin(@custmert,fTzk10,[-7 -800 -0.5],[-3 -200 0.5],options);
% fTzk1opt = fTzk10;
fTzk1opt = fminsearch(@genmert,fTzk10);
else % f and k1 are provided, optimize over variable Tz only
Tzopt = fminsearch(@(x) genmert([fTzk10(1),x,fTzk10(3)]), fTzk10(2));
fTzk1opt = fTzk10;
fTzk1opt(2) = Tzopt;
end
f = fTzk1opt(1);
Tz = fTzk1opt(2);
k1 = fTzk1opt(3);
% mert = eq8b(fTzk1opt);
[mert0,mert0i] = genmert(fTzk10);
[mert,merti] = genmert(fTzk1opt);
T = [Tx;Ty;Tz];
[Xfin,Yfin,xyzfin] = world2cam(xw,yw,zw,R,T,f,k1,[Cx,Cy],[dxp/sx,dy]);
% % plot camera and calibration points in 3D
% fname = '3D Plot';
% fogm = findobj('-regexp','Name',fname,'type','figure');
% if isempty(fogm);
% fig3d = figure(); % create figure
% else
% figure(fogm(1));
% fig3d = clf('reset'); % clear previous figure
% end
% set(fig3d,'Name',fname);
% cpts3 = plot3(xyzfin(:,1),xyzfin(:,2),xyzfin(:,3),'ob');
% camlin3 = line([0;0],[0;0],[0;mean(xyzfin(:,3))],'linestyle','-
','color','k','linewidth',2);
% xlabel('X');ylabel('Y');zlabel('Z');
% buff = [0.5 0.5 0.2];
188
% limt = zeros(3,2);
% limt(1,:) = get(gca,'xlim');
% limt(2,:) = get(gca,'ylim');
% limt(3,:) = get(gca,'zlim');
% line([limt(1,1)-buff(1)*diff(limt(1,:));limt(1,2)+buff(1)*diff(limt(1,:))],...
% [limt(2,1)-buff(2)*diff(limt(2,:));limt(2,2)+buff(2)*diff(limt(2,:))],...
% [limt(3,1)-buff(3)*diff(limt(3,:));limt(3,2)+buff(3)*diff(limt(3,:))],...
% 'linestyle','none','marker','.','color','w');
% axis equal;
% plot final points
figure(figimg);
blucirc = line(Xfin(:),Yfin(:),'linestyle','none','marker','o','color','b');
errsca = 100;
errhi = zeros(size(Xfin));
errh = errhi;
for cp = 1:numpts
set(cplab(cp),'color','b','position',[Xfin(cp),Yfin(cp)]+txtoff);
errhi(cp) = line([Xf(cp);Xf(cp)+errsca*(Xftst(cp)-
Xf(cp))],[Yf(cp);Yf(cp)+errsca*(Yftst(cp)-Yf(cp))],'color','r','linewidth',2);
errh(cp) = line([Xf(cp);Xf(cp)+errsca*(Xfin(cp)-
Xf(cp))],[Yf(cp);Yf(cp)+errsca*(Yfin(cp)-Yf(cp))],'color','b','linewidth',2);
end
errlabi = text(Xf(mert0i)+errsca*(Xftst(mert0i)-
Xf(mert0i)),Yf(mert0i)+errsca*(Yftst(mert0i)-
Yf(mert0i)),num2str(mert0,3),'fontweight','bold','color','r');
errlab = text(Xf(merti)+errsca*(Xfin(merti)-Xf(merti)),Yf(merti)+errsca*(Yfin(merti)-
Yf(merti)),num2str(mert,3),'fontweight','bold','color','b');
if true
else
% create manual adjustment control figure
fname = 'Manual Controls';
fpos = [200 200 800 400];
fogm = findobj('-regexp','Name',fname,'type','figure');
if isempty(fogm);
fhan = figure(); % create figure
else
figure(fogm(1));
fhan = clf('reset'); % clear previous figure
end
set(fhan,'Position',fpos,'color','w','units','pixels','Name',fname);
% create 3 UIpanels for T (Tx,Ty,Tz), R (roll, pitch, yaw), and (f,k1)
pan(1) = uipanel(fhan,'units','normal','position',[0.05 0.2 0.2875
0.75],'title','Translation','backgroundcolor','w');
pan(2) = uipanel(fhan,'units','normal','position',[0.3875 0.2 0.2875
0.75],'title','Rotation','backgroundcolor','w');
pan(3) = uipanel(fhan,'units','normal','position',[0.725 0.2 0.225
0.75],'title','Focal Length and Distortion','backgroundcolor','w');
% create sliders, edit boxes, and titles
slidenames = {{'Tx','Ty','Tz'},{'Roll','Pitch','Yaw'},{'f','Distortion (k1)'}};
189
def = {[Tx,Ty,Tz],[psi,theta,phi].*180/pi,[f,k1]}; % default starting positions
rnghi = cell(size(def));
rnglo = rnghi;
rngt = 20; % plus or minus range for T
rngf = 1; % plus or minus range for f
rngk = 0.02; % plus or minus range for k1
% rnghi{1} = (1+sign(def{1}).*rngfactor).*def{1};
% rnglo{1} = (1-sign(def{1}).*rngfactor).*def{1};
rnghi{1} = def{1}+rngt;
rnglo{1} = def{1}-rngt;
rnghi{2} = 180.*ones(size(def{2}));
rnglo{2} = -rnghi{2};
% rnghi{3} = (1+sign(def{3}).*rngfactor).*def{3};
% rnglo{3} = (1-sign(def{3}).*rngfactor).*def{3};
rnghi{3} = def{3}+[rngf,rngk];
rnglo{3} = def{3}-[rngf,rngk];
numc = cellfun(@numel,def); % number of control groups in each panel
numcc = cumsum(numc);
numcc = [0,numcc(1:end-1)];
slidehan = zeros(1,sum(numc));
edithan = slidehan;
for ip = 1:numel(numc)
ppos = getpixelposition(pan(ip));
hpos = ppos(3).*linspace(1/numc(ip)/2,1-1/numc(ip)/2,numc(ip));
wid = ppos(3)/numc(ip);
for ic = 1:numc(ip)
slidehan(numcc(ip)+ic) =
uicontrol(pan(ip),'style','slider','position',[hpos(ic)-10 10 20 ppos(4)-
85],'min',rnglo{ip}(ic),'max',rnghi{ip}(ic),'value',def{ip}(ic),'callback',@slidecall);
edithan(numcc(ip)+ic) =
uicontrol(pan(ip),'style','edit','position',[hpos(ic)-(wid-10)/2, ppos(4)-65, wid-10,
20],'string',num2str(def{ip}(ic)),'callback',@editcall);
uicontrol(pan(ip),'style','text','position',[hpos(ic)-(wid-10)/2, ppos(4)-40,
wid-10, 20],'string',slidenames{ip}{ic},'backgroundcolor','w');
end
end
set(slidehan(4:6),'sliderstep',[1/360, 1/60]);
axmert = axes('parent',fhan,'units','normal','position',[0.05 0.01 0.7
0.18],'xtick',[],'ygrid','on');
merthist = ones(30,1).*mert;
mertlin = line('xdata',(0:(numel(merthist)-
1)).','ydata',merthist,'color','b','linewidth',2,'parent',axmert);
mertxt = uicontrol(fhan,'style','text','units','normal','position',[0.76 0.01 0.13
0.18],'backgroundcolor','w','horizontalalignment','left','string',num2str(mert),'fontsize
',20,'fontweight','bold');
updateplot();
end
% save_to_base(1);
%% accessory functions
190
function [delt] = eq8b(fTzk1)
f0 = fTzk1(1);
Tz0 = fTzk1(2);
k10 = fTzk1(3);
r = sqrt( (dxp.*Xu./sx).^2 + (dy.*Yu).^2 );
LHS = dy.*Yu + dy.*Yu.*k10.*r.^2;
RHS = f0 .* (R(2).*xw+R(5).*yw+R(8).*zw+Ty) ./ (R(3).*xw+R(6).*yw+R(9).*zw+Tz0);
delt = LHS(:)-RHS(:);
end
function [delt] = custmert(fTzk1)
f0 = fTzk1(1);
Tz0 = fTzk1(2);
k10 = fTzk1(3);
r = sqrt( (dxp.*Xu./sx).^2 + (dy.*Yu).^2 );
LHSy = dy.*Yu + dy.*Yu.*k10.*r.^2;
RHSy = f0 .* (R(2).*xw+R(5).*yw+R(8).*zw+Ty) ./ (R(3).*xw+R(6).*yw+R(9).*zw+Tz0);
LHSx = sx^(-1).*dxp.*Xu + sx^(-1).*dxp.*Xu.*k10.*r.^2;
RHSx = f0 .* (R(1).*xw+R(4).*yw+R(7).*zw+Tx) ./ (R(3).*xw+R(6).*yw+R(9).*zw+Tz0);
delt = sqrt((LHSy(:)-RHSy(:)).^2+(LHSx(:)-RHSx(:)).^2);
end
function [delt,delti] = genmert(fTzk1,varargin)
f0 = fTzk1(1);
Tz0 = fTzk1(2);
k10 = fTzk1(3);
if nargin>1
T0 = [varargin{1}(:);Tz0];
else
T0 = [Tx;Ty;Tz0];
end
[Xup,Yup,~] = world2cam(xw,yw,zw,R,T0,f0,k10,[Cx,Cy],[dxp/sx,dy]);
[delt,delti] = max(sqrt((centroids(ccind(:),1)-Xup(:)).^2 +
(centroids(ccind(:),2)-Yup(:)).^2));
end
function slidecall(~,~)
vals0 = get(slidehan,'value');
vals = cellfun(@num2str,vals0,'UniformOutput',false);
set(edithan,{'string'},vals);
T = cell2mat(vals0(1:3));
angs = cell2mat(vals0(4:6)).*pi./180;
R = [ cos(angs(1))*cos(angs(2))
sin(angs(1))*cos(angs(2)) -sin(angs(2)) ;...
-sin(angs(1))*cos(angs(3))+cos(angs(1))*sin(angs(2))*sin(angs(3))
cos(angs(1))*cos(angs(3))+sin(angs(1))*sin(angs(2))*sin(angs(3))
cos(angs(2))*sin(angs(3));...
sin(angs(1))*sin(angs(3))+cos(angs(1))*sin(angs(2))*cos(angs(3)) -
cos(angs(1))*sin(angs(3))+sin(angs(1))*sin(angs(2))*cos(angs(3))
cos(angs(2))*cos(angs(3))];
191
f = vals0{7};
k1 = vals0{8};
updateplot();
end
function editcall(~,~)
vals0 = get(edithan,'string');
vals = cellfun(@str2num,vals0);
mins = [vals(1:3)-rngt;-180.*ones(3,1);vals(7)-rngf;vals(8)-rngk];
maxs = [vals(1:3)+rngt;180.*ones(3,1);vals(7)+rngf;vals(8)+rngk];
for ij = 1:numel(slidehan)
set(slidehan(ij),'value',vals(ij),'min',mins(ij),'max',maxs(ij));
end
T = vals(1:3);
angs = vals(4:6).*pi./180;
R = [ cos(angs(1))*cos(angs(2))
sin(angs(1))*cos(angs(2)) -sin(angs(2)) ;...
-sin(angs(1))*cos(angs(3))+cos(angs(1))*sin(angs(2))*sin(angs(3))
cos(angs(1))*cos(angs(3))+sin(angs(1))*sin(angs(2))*sin(angs(3))
cos(angs(2))*sin(angs(3));...
sin(angs(1))*sin(angs(3))+cos(angs(1))*sin(angs(2))*cos(angs(3)) -
cos(angs(1))*sin(angs(3))+sin(angs(1))*sin(angs(2))*cos(angs(3))
cos(angs(2))*cos(angs(3))];
f = vals(7);
k1 = vals(8);
updateplot();
end
function updateplot()
[Xup,Yup,xyzup] = world2cam(xw,yw,zw,R,T,f,k1,[Cx,Cy],[dxp/sx,dy]);
set(blucirc,'xdata',Xup(:),'ydata',Yup(:));
for ck = 1:numpts
set(cplab(ck),'position',[Xup(ck),Yup(ck)]+txtoff);
end
mert = genmert([f,T(3),k1],T(1:2));
merthist = [merthist(2:end);mert];
set(mertlin,'ydata',merthist);
set(mertxt,'string',num2str(mert));
set(cpts3,'xdata',xyzup(:,1),'ydata',xyzup(:,2),'zdata',xyzup(:,3));
% set(camlin3,'zdata',[0;mean(xyzup(:,3))]);
end
function [Xw2c,Yw2c,xyzw2c] = world2cam(xw,yw,zw,R,T,f,k1,Cxy,dxy)
% INPUT:
% xw,yw,zw are world coordinates (zw(:) = 0 for planar coordinate points)
% R is 3x3 rotation matrix (world to camera)
% T is three element translation vector [Tx;Ty;Tz] (world to camera)
% f is lens focal length
% k1 is r^2 coefficient of distortion
% Cxy is two element vector [x,y] of pixel position of optical center in computer
frame memory
192
% dxy is two element vector [x,y] of pixel pitch (units of length)
% OUTPUT:
% Xw2c is an array of X pixel coordinates on camera sensor of real world points,
the same size as xw input
% Yw2c is an array of Y pixel coordinates on camera sensor of real world points,
the same size as xw input
% xyzw2c is an array of [x1,y1,z1;x2,y2,z2;...] 3D camera coordinates of world
points
camcoordsw2c = R*[xw(:).'; yw(:).'; zw(:).'] + repmat(T(:),1,numel(xw));
xyzw2c = camcoordsw2c.';
xw2c = reshape(camcoordsw2c(1,:),size(xw));
yw2c = reshape(camcoordsw2c(2,:),size(xw));
zw2c = reshape(camcoordsw2c(3,:),size(xw));
Xdw2c0 = f.*xw2c./zw2c;
Ydw2c0 = f.*yw2c./zw2c;
rsqw2c = Xdw2c0.^2 + Ydw2c0.^2;
Xdw2c = Xdw2c0./(1+k1.*rsqw2c);
Ydw2c = Ydw2c0./(1+k1.*rsqw2c);
Xw2c = dxy(1)^(-1).*Xdw2c + Cxy(1);
Yw2c = dxy(2)^(-1).*Ydw2c + Cxy(2);
end
function [out] = inbounds(in,dir) % dir = 'x' or 'y'
switch dir
case 'x'
dfd = 2; %dimension from 'dir' input
case 'y'
dfd = 1;
end
out = in + max(1-min(in(:)),0);
out = out + min(imgsiz(dfd)-max(in(:)),0);
end
function [] = continuebutton(~,~)
% set(prevnextbut,'enable','off');
set(contbut,'enable','off');
set(prevnextbut,'visible','off');
set(contbut,'visible','off');
end
function roisel(~,~)
% set([okbut,roih],'visible','off');
% drawnow;
roimask = createMask(roih);
uiresume;
end
end
193
Dependency: DW_DeflectometerCalibration.m
Deflectometer calibration routine that finds relative position and orientation of camera
and display.
function [f,k1,R,T,Rmir,Tmir,cxcy,dxy,xflag] = DW_DeflectometerCalibration(txwiz,xbut)
global vid fs;
fsfig = fs.FigureHandle;
fsax = fs.AxisHandle;
fsimg = fs.ImageHandle;
fssiz = fs.Size;
% set output default values
f=0; k1=0; R=0; T=0; Rmir=0; Tmir=0; cxcy=0; dxy=0;
xflag = false;
set(xbut,'callback',@exitnow);
% Capture image of mirror calibration points
set(fsimg,'cdata',255.*ones(fssiz));
drawnow expose;
mirrorimg = getsnapshot(vid);
% Calibrate camera to mirror calibration points
sensor = camerasensordatabase('Marlin');
dxy = [sensor.dx,sensor.dy];
target = targetcoorddatabase('mirror');
set(txwiz,'string','Finding mirror position and lens specs. Point out mirror control
points on image.');
[Rmir,Tmir,f,k1,~,cxcy] =
DW_CamCalibration(sensor,target,mirrorimg,'opense',strel('disk',7));
if xflag
return;
end
% Interactively create control points on monitor
discpoint = nan(16);
[Xpointergen,Ypointergen]=meshgrid(linspace(-7.5,7.5,16),linspace(-7.5,7.5,16));
discpoint(sqrt(Xpointergen.^2+Ypointergen.^2)<=7.6) = 2; % disk pointer icon
pointercenter = [1,1];
[yfill,xfill] = find(~isnan(discpoint));
yfill = yfill - pointercenter(1)+1;
xfill = xfill - pointercenter(2)+1;
pointercenterf = pointercenter.*[-1,1]+[17,0]; % flip y direction of pointer center since
picture axis y direction is un-reversed
194
set(fsfig,'pointer','custom','pointershapecdata',discpoint,'pointershapehotspot',pointerc
enterf);
% set(fsimg,'hittest','off');
% set(fsax,'hittest','on');
% capture initial comparison frame
blackscreen = zeros(fssiz);
blackscreen(1) = 1;
% %%%
% blackscreen(105.5+[-8.5,8.5],:) = 1;
% blackscreen(:,200.5+[-8.5,8.5]) = 1;
% %%%
fsdisp = blackscreen; % CData to display on monitor
set(fsimg,'cdata',fsdisp); % turn screen to black (with one white pixel for contrast)
initimg = getsnapshot(vid);
drawnow expose;
if xflag
return;
end
% set up point coordinate databases and control figure
moncoords = [];
imgcoords = [];
figcon = pptfig('Control Point Selector',1);
set(figcon,'position',[100,100,fliplr(round(size(initimg)./[2,4/3]))]); % rightmost 2/3
of figure is for image preview
set(figcon,'DefaultUicontrolFontSize',14,'DefaultUicontrolFontWeight','bold');
prevax = axes('parent',figcon,'units','normal','position',[1/3,0,2/3,1],'visible','off');
pancon = uipanel(figcon,'units','normal','position',[0,0,1/3,1],'title','Control Panel');
preimg = image(ones(size(initimg)),'parent',prevax);
monptlist =
uicontrol(pancon,'style','listbox','units','normal','position',[0.05,0.4,0.425,0.5],'min'
,0,'max',10,'value',[],'callback',@listpoint);
imgptlist =
uicontrol(pancon,'style','listbox','units','normal','position',[0.525,0.4,0.425,0.5],'min
',0,'max',10,'value',[],'callback',@listpoint);
delbut =
uicontrol(pancon,'style','pushbutton','units','normal','position',[0.1,0.05,0.35,0.1],'st
ring','Delete Point','callback',@deletepoint);
contbut =
uicontrol(pancon,'style','pushbutton','units','normal','position',[0.55,0.05,0.35,0.1],'s
tring','Continue (5)','enable','on','callback',@contin);
checkx =
uicontrol(pancon,'style','checkbox','units','normal','position',[0.1,0.20,0.8,0.05],'stri
ng','Reverse X Axis','min',0,'max',1,'value',0,'callback',@(~,~) updatecontrols([]));
checky =
uicontrol(pancon,'style','checkbox','units','normal','position',[0.1,0.25,0.8,0.05],'stri
ng','Reverse Y Axis','min',0,'max',1,'value',1,'callback',@(~,~) updatecontrols([]));
selpt =
line('xdata',0,'ydata',0,'parent',prevax,'marker','x','linestyle','none','color','r','vis
ible','off');
195
updatecontrols([]);
if xflag
return;
end
% pick points with mouse
preview(vid,preimg);
set(fsimg,'ButtonDownFcn',@addpoint,'interruptible','on');
set(txwiz,'string','Draw a minimum of five(5) control points on monitor where camera can
view them.');
uiwait(figcon);
stoppreview(vid);
close(figcon);
if xflag
return;
end
monimg = getsnapshot(vid);
set(txwiz,'string','Calculating monitor position...');
% Calibrate camera to monitor (reflection) control points for extrinsic parameters (R,T)
only
monpp = [0.258,0.258]; % monitor pixel pitch, [x,y] mm/pixel
monptnames = arrayfun(@(x) num2str(x), (1:size(moncoords,1)).', 'UniformOutput', false);
monitarget =
struct('ptx',moncoords(:,1).*monpp(1),'pty',moncoords(:,2).*monpp(2),'names',[]);
monitarget.names = monptnames;
[Rmon,Tmon,~,~,~] =
DW_CamCalibration(sensor,monitarget,monimg,'fk1',[f,k1],'cpts',imgcoords,'invert',false);
%,'opense',strel('disk',7));
if xflag
return;
end
% Find monitor position relative to camera using mirror position and monitor reflected
image postion
invz = [1 0 0; 0 1 0; 0 0 -1];
Rmon = Rmon*invz; % invz is to create left handed coordinate system for the monitor
reflection
R = Rmir*invz*Rmir.'*Rmon;
T = Rmir*invz*Rmir.'*(Tmon-Tmir) + Tmir;
if xflag
return;
end
% plot setup in 3D
fig3d = pptfig('3D Render',1);
196
siz = size(initimg);
ax3d = axes;
axis equal;
% camera graphic
mx = sensor.dx*siz(2)/2/f;
my = sensor.dy*siz(1)/2/f;
camsca = 100;
camverts0 = [[-mx -my 1;... % bottom left corner
mx -my 1;... % bottom right corner
mx my 1;... % top right corner
-mx my 1].*camsca;... % top left corner, scaled
0 0 0;... % origin
eye(3) ]; % unit vectors
% take camera vertices from camera reference frame to mirror reference frame
camverts = (Rmir.'*(camverts0.'-repmat(Tmir,1,size(camverts0,1)))).';
camfaces = [1 2 5;...
2 3 5;...
3 4 5;...
4 1 5];
patch('vertices',camverts,'faces',camfaces,'facecolor','k','facealpha',0.3,'edgecolor','k
');
cosysplot(camverts(5:8,:),50);
% monitor graphic
mx = fssiz(2).*monpp(1);
my = fssiz(1).*monpp(2);
monverts0 = [0 0 0;... % corners
0 my 0;...
mx my 0;...
mx 0 0;...
0 0 0;... % origin
eye(3) ]; % unit vectors
% take monitor vertices from monitor reference frame to camera reference frame
monverts1 = R*monverts0.'+repmat(T,1,size(monverts0,1));
% take monitor vertices from camera reference frame to mirror reference frame
monverts = (Rmir.'*(monverts1-repmat(Tmir,1,size(monverts0,1)))).';
patch('vertices',monverts,'faces',[1 2 3
4],'facecolor','b','facealpha',0.5,'edgecolor','k');
xyzlin = cosysplot(monverts(5:8,:),50);
legend(xyzlin,{'X','Y','Z'});
% reflected monitor graphic
% take monitor vertices from monitor reference frame to camera reference frame
monvertsr1 = Rmon*monverts0.'+repmat(Tmon,1,size(monverts0,1));
% take monitor vertices from camera reference frame to mirror reference frame
monvertsr = (Rmir.'*(monvertsr1-repmat(Tmir,1,size(monverts0,1)))).';
patch('vertices',monvertsr,'faces',[1 2 3
4],'facecolor','b','facealpha',0.3,'edgecolor','k','linestyle','--');
cosysplot(monvertsr(5:8,:),50);
197
% mirror graphic
ang = linspace(0,2*pi,5*4+1).';
ang = ang(1:end-1);
dotx = cos(ang);
doty = sin(ang);
dotz = zeros(size(ang));
for di = 1:numel(target.ptx)
patch(dotx+target.ptx(di),doty+target.pty(di),dotz,dotz,'facecolor','k');
end
cosysplot([zeros(1,3);eye(3)],50);
% viewing area graphic
[xv,yv] =
atz0(camverts(5,1),camverts(5,2),camverts(5,3),camverts(1:4,1),camverts(1:4,2),camverts(1
:4,3));
line('xdata',xv([1;2;3;4;1]),'ydata',yv([1;2;3;4;1]),'zdata',zeros(5,1),'linestyle','--
','color','k');
set(ax3d,'zdir','reverse','ydir','reverse');
%% Nested Functions/Callbacks
function exitnow(~,~)
xflag = true;
end
function addpoint(~,~)
cp = get(fsax,'currentpoint'); % get the position of the mouse click
set(fsax,'hittest','off'); % make axis inactive
set(fsfig,'pointershapecdata',nan(16)); % hide cursor
cpx = round(cp(1,1));
cpy = round(cp(1,2));
% %%%
% disp(cp);
% disp([cpx,cpy]);
% save_to_base(1); pause(1);
% %%%
fillinds = sub2ind(fssiz,yfill+cpy-1,xfill+cpx-1); % indices to "paint" the area
where the cursor was when clicked
fsdisp(fillinds) = 255;
set(fsimg,'cdata',fsdisp); % update display data
drawnow expose; pause(0.5); % update graphics
initimg0 = initimg; % store previous image
initimg = getsnapshot(vid); % capture new image
imgdiff = initimg-initimg0; % image difference
xsignal = sum(imgdiff,1); % 1-D image difference in X direction
xsignal = xsignal./max(xsignal); % normalized
ysignal = sum(imgdiff,2); % 1-D image difference in Y direction
ysignal = ysignal./max(ysignal); % normalized
[~,xloc] = findpeaks(xsignal,'SortStr','descend','NPeaks',1); % finds tallest
peak location in X signal
198
[~,yloc] = findpeaks(ysignal,'SortStr','descend','NPeaks',1); % finds tallest
peak location in Y signal
imgcoords(end+1,:) = [xloc,yloc]; % approximate coordinates of new spot in camera
frame
moncoords(end+1,:) = [cpx,cpy]-pointercenter([2,1])+8.5; % exact coordinates of
control point on monitor
updatecontrols(size(moncoords,1));
set(fsax,'hittest','on'); % make axis active
set(fsfig,'pointershapecdata',discpoint); % show cursor
if xflag
uiresume(figcon);
end
end
function updatecontrols(selind) % input is logical flag whether to change the
selected values of the list boxes
if isempty(moncoords)
monptstr = {''};
imgptstr = {''};
else
monptstr = arrayfun(@(x,y) sprintf('(%0.1f, %0.1f)',x,y), moncoords(:,1),
moncoords(:,2), 'UniformOutput', false);
imgptstr = arrayfun(@(x,y) sprintf('(%0.1f, %0.1f)',x,y), imgcoords(:,1),
imgcoords(:,2), 'UniformOutput', false);
end
set(monptlist, 'string', monptstr);
set(imgptlist, 'string', imgptstr);
if size(moncoords,1) < 5
set(contbut,'string',['Continue (' int2str(5-size(moncoords,1))
')'],'enable','off');
else
set(contbut,'string','Continue','enable','on');
end
% selind = get(monptlist,'value');
set([monptlist,imgptlist], 'value', selind);
if isempty(selind) || all(selind==0)
set(selpt,'visible','off');
else
set(selpt,'visible','on','xdata',imgcoords(selind,1),'ydata',imgcoords(selind,2));
end
if get(checkx,'value')>0
set(prevax,'xdir','reverse');
else
set(prevax,'xdir','normal');
end
if get(checky,'value')>0
set(prevax,'ydir','normal');
else
set(prevax,'ydir','reverse');
end
199
end
function deletepoint(~,~)
delind = get(monptlist,'value');
moncoords(delind,:) = [];
imgcoords(delind,:) = [];
set(monptlist,'value',[]);
updatecontrols([]);
end
function listpoint(src,~)
selind = get(src,'value');
updatecontrols(selind);
end
function contin(~,~)
uiresume(figcon);
end
function linh = cosysplot(pts,sca) % pts must contain 4 row unit vectors
[origin;X_hat;Y_hat;Z_hat], sca is coordinate glyph scale
diffs = pts(2:4,:)-repmat(pts(1,:),3,1);
pts(2:4,:) = (diffs.*sca)+repmat(pts(1,:),3,1);
linh = zeros(3,1);
linh(1) =
line('xdata',pts([1,2],1),'ydata',pts([1,2],2),'zdata',pts([1,2],3),'color','r','linewidt
h',3);
linh(2) =
line('xdata',pts([1,3],1),'ydata',pts([1,3],2),'zdata',pts([1,3],3),'color','g','linewidt
h',3);
linh(3) =
line('xdata',pts([1,4],1),'ydata',pts([1,4],2),'zdata',pts([1,4],3),'color','b','linewidt
h',3);
end
function [x,y] = atz0(x1,y1,z1,x2,y2,z2)
% parameterized equation of line in 3D
% x = (x2-x1)*t + x1
% y = (y2-y1)*t + y1
% z = (z2-z1)*t + z1
t = (0-z1)./(z2-z1); % t at z=0
x = (x2-x1).*t + x1;
y = (y2-y1).*t + y1;
end
end
Dependency: DW_ExposureAdjust.m
Camera exposure adjustment routine.
200
function [figcon] = DW_ExposureAdjust(maxval)
global vid src fs
% Create full screen display figure
assignin('base','fs_in_wxpadj',fs);
fsax = fs.AxisHandle;
fssiz = fs.Size;
fsimg = fs.ImageHandle;
caxis(fsax,[0 255]); % 8-bit color data
cdat = maxval.*ones(size(fssiz));
set(fsimg,'cdata',cdat);
drawnow expose;
src = getselectedsource(vid);
% Marlin
expvar = 'Shutter'; % video source setting name to change
explims = [1,4095]; % slider limits
expsteps = [10,100]./diff(explims); % slider step sizes
extvar = 'ExtendedShutter'; % video source setting name to change
extlims = [0 67108863]; % slider limits
extsteps = [0.01, 0.1]; % slider step sizes
% % Webcam
% set(src,'ExposureMode','Manual');
% set(vid,'FramesPerTrigger',1);
% expvar = 'Exposure';
% explims = [-9,-1];
% steps = [1,3]./diff(explims);
set(vid,'FramesPerTrigger',5);
shutter = get(src,expvar);
set(src,expvar,shutter);
extshutter = get(src,extvar);
set(src,extvar,extshutter);
% create control figure
figcon = pptfig('Exposure Control',1);
set(figcon,'position',[100,100,round(get(vid,'VideoResolution')./[4/1.25,4/2])]); %
leftmost 4/5 of figure is for image preview and histogram
set(figcon,'DefaultUicontrolFontSize',14,'DefaultUicontrolFontWeight','bold');
imgpan = uipanel(figcon,'units','normal','position',[0,0.5,0.8,0.5],'title','Image
Preview');
histpan = uipanel(figcon,'units','normal','position',[0,0,0.8,0.5],'title','Histogram');
conpan = uipanel(figcon,'units','normal','position',[0.8,0,0.2,1],'title','Shutter');
imgax = axes('parent',imgpan,'units','normal','position',[0,0,1,1],'visible','off');
histax = axes('parent',histpan);
grayred = gray(256);
grayred(end,:) = [1 0 0]; % make saturated pixels red
201
colormap(grayred);
shlider =
uicontrol(conpan,'style','slider','units','normal','position',[0.1,0.1,0.3,0.7],...
'min',explims(1),'max',explims(2),'value',shutter,'sliderstep',expsteps,...
'callback',@shlidercall);
shedit =
uicontrol(conpan,'style','edit','units','normal','position',[0,0.85,0.5,0.05],'string',in
t2str(shutter),'callback',@sheditcall,'fontsize',11);
extshlider =
uicontrol(conpan,'style','slider','units','normal','position',[0.6,0.1,0.3,0.7],...
'min',extlims(1),'max',extlims(2),'value',extshutter,'sliderstep',extsteps,...
'callback',@extshlidercall);
extshedit =
uicontrol(conpan,'style','edit','units','normal','position',[0.5,0.85,0.5,0.05],'string',
int2str(extshutter),'callback',@extsheditcall,'fontsize',11);
imgh = imagesc(ones(fliplr(get(vid,'VideoResolution'))),'parent',imgax);
set(imgax,'visible','off');
updatepic();
function updatepic()
set([shlider,shedit,extshlider,extshedit],'enable','off');
set(shlider,'value',shutter);
set(shedit,'string',int2str(shutter));
set(extshlider,'value',extshutter);
set(extshedit,'string',int2str(extshutter));
drawnow expose;
set(src,expvar,shutter);
set(src,extvar,extshutter);
start(vid);
pic = mean(getdata(vid),4);
pic = mean(pic,3); % in case image is in color
pic = pic./255; % 8-bit image
caxis(imgax,[0,1]);
set(imgh,'cdata',pic);
hist(histax,pic(:),256);
set([shlider,shedit,extshlider,extshedit],'enable','on');
drawnow expose;
end
function shlidercall(~,~)
shutter = round(get(shlider,'value'));
shutter = min([shutter,explims(2)]);
shutter = max([shutter,explims(1)]);
updatepic();
end
function sheditcall(~,~)
202
shutter = round(str2double(get(shedit,'string')));
shutter = min([shutter,explims(2)]);
shutter = max([shutter,explims(1)]);
updatepic();
end
function extshlidercall(~,~)
extshutter = round(get(extshlider,'value'));
extshutter = min([extshutter,extlims(2)]);
extshutter = max([extshutter,extlims(1)]);
updatepic();
end
function extsheditcall(~,~)
extshutter = round(str2double(get(extshedit,'string')));
extshutter = min([extshutter,extlims(2)]);
extshutter = max([extshutter,extlims(1)]);
updatepic();
end
end
Dependency: DW_FocusAdjust.m
Manual camera focus adjustment routine based on user defined regions of interest.
function DW_FocusAdjust(figimg,txwiz,donebut)
% Provides focus merit functions in real time based on selected ROIs for
% manual focusing of camera lens
global vid fs
% get frame
img = getsnapshot(vid);
imgsiz = size(img);
imgsiz = imgsiz(1:2); % if video input is rgb
% display frame
figure(figimg);
set(figimg,'Renderer','opengl')
imgprev = imshow(img,gray(256));
colorbar;
aximg = gca;
preview(vid,imgprev);
% choose ROI(s)
set(txwiz,'string','Choose region(s) of interest.');
roicolors = repmat(get(0,'DefaultAxesColorOrder'),[5,1]);
figure(figimg);
roih = {};
203
okbut = uicontrol(figimg,'style','pushbutton','units','normal','position',[.51 .01 .19
.06],'string','Finish','callback',@roifinish,'fontsize',12,'fontweight','bold');
addbut = uicontrol(figimg,'style','pushbutton','units','normal','position',[.30 .01 .19
.06],'string','Another ROI','callback',@roisel,'fontsize',12,'fontweight','bold');
roisel(0,0);
set([okbut,addbut],'visible','off');
ROI(numel(roih)) = struct;
for ri = 1:numel(roih)
% ROI(ri).handle = roih(ri);
ROI(ri).position = getPosition(roih{ri});
ROI(ri).mask = createMask(roih{ri});
% [riX,riY] = meshgrid(linspace(-1,1,ROI(ri).position(3))./sqrt(2),linspace(-
1,1,ROI(ri).position(4))./sqrt(2));
[riX,riY] = meshgrid(linspace(-1,1,ROI(ri).position(3)),linspace(-
1,1,ROI(ri).position(4)));
ridist = sqrt(riX.^2+riY.^2);
[ridistunique,~,revorder] = unique(ridist(:));
ROI(ri).centerdist = ridistunique;
pixind = arrayfun(@(ind) find(revorder==ind), 1:numel(ridistunique),
'UniformOutput',false);
ROI(ri).pixelindices = pixind;
ROI(ri).size = size(ridist);
end
drawnow;
% create focus feedback figure
figfoc = pptfig('Focus Merit Function',2);
set(figfoc,'units','pixels','position',[100,100,500,800]);
subwid = 3;
margins = [0.07,0.02];
axmert = subplot_tight(numel(ROI)+1,subwid,1:subwid,[margins(1),.1]);
% fftthresh = 0.95;
results = evalfocfft(img,ROI);%,fftthresh);
assignin('base', 'results', results);
set(axmert,'xlim',[0,1],'xtick',[],'box','on');
maxavgmert = max(0,mean([results.merit]));
maxavglin = line('xdata',[0;1],'ydata',maxavgmert.*[1;1],'color','r','linewidth',3);
avglin =
line('xdata',linspace(0,1,50).','ydata',[0;ones(49,1).*mean([results.merit])],'linewidth'
,2);
avgtit = title(['Average Focus Index = ' num2str(mean([results.merit]),2) ' (max. '
num2str(maxavgmert,2) ')'],'fontweight','bold');
soundfreqs = (261.63/20).*[20;25;30;36]*(1:3); % list of sound frequencies in Hz
axroi = zeros(numel(ROI),1);
imroi = axroi;
axfft = axroi;
linefft = axroi;
linemert = axroi;
fftit = axroi;
maxmert = axroi;
linemaxmert = axroi;
204
aph = cell(size(axroi)); % audio player objects
for rj = 1:numel(axroi)
axroi(rj) = subplot_tight(numel(ROI)+1,subwid,subwid*rj+1,margins);
imroi(rj) = imshow(reshape(img(ROI(rj).mask),ROI(rj).size),'parent',axroi(rj));
set(axroi(rj),'visible','on','box','on','xtick',[],'ytick',[],'xcolor',roicolors(rj,:),'y
color',roicolors(rj,:));
axfft(rj) = subplot_tight(numel(ROI)+1,subwid,subwid*rj+(2:subwid),margins);
set(axfft(rj),'xlim',[0,1],'ylim',[0,1],'xtick',0:0.25:1,'ytick',[],'box','on','xcolor',r
oicolors(rj,:),'ycolor',roicolors(rj,:));
maxmert(rj) = max(maxmert(rj),results(rj).merit);
linemaxmert(rj) =
line('xdata',ones(2,1).*maxmert(rj),'ydata',[0;1],'color',roicolors(rj,:),'linewidth',3);
linefft(rj) =
line('xdata',results(rj).fftx(:),'ydata',results(rj).ffty(:),'color','k');
linemert(rj) =
line('xdata',ones(2,1).*results(rj).merit,'ydata',[0;1],'color',0.4.*[1 1
1],'linewidth',2);
fftit(rj) =
title(num2str(results(rj).merit,2),'color',roicolors(rj,:),'fontweight','bold');
[svec,fs0] = VibratoGen(10,soundfreqs(rj));
aph{rj} = audioplayer(svec,fs0);
end
% threshlide = uicontrol(figfoc,'style','slider','units','normal','position',[0.875-
0.025,0.1,0.05,1-1/(numel(ROI)+1)-
0.2],'min',0,'max',1,'value',fftthresh,'sliderstep',[0.001,0.05],'callback',@threshcall);
% threshtxt = uicontrol(figfoc,'style','text','units','normal','position',[0.875-0.075,1-
1/(numel(ROI)+1)-0.1,0.15,0.05],'string',['Threshold' char(10)
num2str(fftthresh,3)],'backgroundcolor','w','fontweight','bold');
updatemertfig();
%% Focus Evaluation Loop
set(txwiz,'string','Adjust lens focus. Tone indicates proximity to historically best
focus for each ROI');
set(donebut,'callback',@(~,~)
set([figimg,figfoc],'visible','off'),'visible','on','string','Done');
set([figimg,figfoc],'CloseRequestFcn',@(x,y) set([figimg,figfoc],'visible','off'));
runLoop = true;
frameCount = 0;
fochist = zeros(numel(ROI),10);
while runLoop && frameCount < 4000
% get the next frame
img = getsnapshot(vid);
frameCount = frameCount + 1;
% evaluate focus
results = evalfocfft(img,ROI);
instfoc = [results.merit];
fochist = [instfoc(:),fochist(:,1:(end-1))];
newmert = mean(fochist,2);
for nf = 1:numel(ROI)
205
results(nf).merit = newmert(nf);
end
updatemertfig();
% check whether the video preview window has been "closed"
runLoop = all(strcmp('on',{get(figimg,'visible'),get(figfoc,'visible')}));
end
% clean up
if ishandle(figimg)
delete(figimg);
end
if ishandle(figfoc)
delete(figfoc);
end
%% Nested Functions
function roisel(~,~)
roitemp = imrect(aximg,[round(imgsiz([2,1])./2)-50.5, 101, 101]);
resume(roitemp);
roinum = numel(roih)+1;
roih{roinum} = roitemp;
setColor(roitemp,roicolors(roinum,:));
setFixedAspectRatioMode(roitemp,true);
uiwait(figimg);
end
function squareroi(newpos,roi)
centerxy = round(newpos(1:2)+newpos(3:4)./2);
hafsiz = min(round(max(newpos(3:4))/2) + 0.5, ceil(min(imgsiz)/2)-0.5);
if centerxy(1)-hafsiz<0.5
centerxy(1) = 0.5+hafsiz;
elseif centerxy(1)+hafsiz>imgsiz(2)+0.5
centerxy(1) = imgsiz(2)+0.5-hafsiz;
end
if centerxy(2)-hafsiz<0.5
centerxy(2) = 0.5+hafsiz;
elseif centerxy(2)+hafsiz>imgsiz(1)+0.5
centerxy(2) = imgsiz(1)+0.5-hafsiz;
end
squarepos = [centerxy-hafsiz, ones(1,2).*2.*hafsiz];
setPosition(roi,squarepos);
end
function roifinish(~,~)
for rl = 1:numel(roih)
squareroi(getPosition(roih{rl}),roih{rl});
setResizable(roih{rl},false);
end
uiresume(figimg);
end
function outstruct = evalfocfft(frame,ROI)%,thresh)
206
outstruct(numel(ROI)) = struct;
sampnum = 100;
for rk = 1:numel(ROI)
roiimg = reshape(frame(ROI(rk).mask),ROI(rk).size);
roifft = abs(fftshift(fft2(roiimg))); % in this case, 'abs' returns the
complex amplitude
fftx0 = ROI(rk).centerdist;
ffty0 = cellfun(@(ind) mean(roifft(ind)), ROI(rk).pixelindices);
eefft = cumsum(ffty0); % encircled energy of fft
fftx = linspace(min(fftx0),max(fftx0),sampnum).';
eefftsamp = interp1(fftx0,eefft,fftx,'pchip'); % sampled using cubic
interpolation
eefftsampn = eefftsamp./max(eefftsamp);
ffty = max(0,diff([0;eefftsamp]));
% ffty(2:end+1) = ffty;
fftyn = ffty./max(ffty(2:end));
% mert = interp1(eefft,fftx0,thresh*max(eefft(:))); % encircled energy
threshold method
mert = sum(fftx(:).*ffty(:)) / sum(ffty(:)); % weighted mean method
% avglen = 3;
% movavg = conv(ffty,ones(avglen,1),'same');
% mert = sum(fftx(:).*movavg(:)) / sum(movavg(:)); % smoothed weighted mean
method
outstruct(rk).fftx = fftx;
outstruct(rk).ffty = fftyn;
outstruct(rk).eefft = eefftsampn;
outstruct(rk).merit = mert;
outstruct(rk).fft2d = roifft;
end
end
function updatemertfig()
ytemp = get(avglin,'ydata');
set(avglin,'ydata',[ytemp(2:end),mean([results.merit])]);
set(avgtit,'string',['Average Focus Index = ' num2str(mean([results.merit]),2) '
(max. ' num2str(maxavgmert,2) ')']);
maxavgmert = max(maxavgmert,mean([results.merit]));
set(maxavglin,'ydata',maxavgmert.*[1;1]);
for rm = 1:numel(ROI)
set(imroi(rm),'cdata',reshape(img(ROI(rm).mask),ROI(rm).size));
% set(imroi(rm),'cdata',reshape((results(rm).fft2d).^(1/2),ROI(rm).size));
set(linefft(rm),'ydata',results(rm).ffty(:));
set(linemert(rm),'xdata',ones(2,1).*results(rm).merit);
set(fftit(rm),'string',num2str(results(rm).merit,2));
maxmert(rm) = max(maxmert(rm),results(rm).merit);
set(linemaxmert(rm),'xdata',ones(2,1).*maxmert(rm));
if results(rm).merit>=0.9*maxmert(rm)
play(aph{rm});
set(axroi(rm),'linewidth',4);
else
pause(aph{rm});
207
set(axroi(rm),'linewidth',0.5);
end
end
drawnow;
end
% function threshcall(src,~)
% fftthresh = max(0,min(1,get(src,'value')));
% set(threshtxt,'string',['Threshold' char(10) num2str(fftthresh,3)]);
% maxavgmert = 0;
% maxmert(:) = 0;
% results = evalfocfft(img,ROI,fftthresh);
% updatemertfig();
% end
end
Dependency: DW_PhaseShiftCapture.m
Function that iterates phase images, triggering the camera after each pattern change.
function [v1234lin,h1234lin,linmm,permm,xflag] =
DW_PhaseShiftCapture(txwiz,cutdn,cutup,monpp,permm,xbut)
global vid fs;
% set output default values
v1234lin=0; h1234lin=0; linmm=0;
xflag = false;
set(xbut,'callback',@exitnow);
% Create full screen display figure
fsfig = fs.FigureHandle;
fsax = fs.AxisHandle;
fsimg = fs.ImageHandle;
fssiz = fs.Size;
blkscrn = zeros(fssiz);
set(fsimg,'cdata',blkscrn);
% Take pics of horizontal and vertical lines
% prevsize = round(get(vid,'VideoResolution')./2);
% fig = figure('name','Choose Line
Positions','units','pixels','position',[100,100,prevsize+100]);
% prevax = axes('parent',fig,'units','pixels','position',[50,50,prevsize]);
% previmg = imshow(ones(prevsize),'parent',prevax);
% set(prevax,'xdir','reverse');
set(txwiz,'string','Place crosshair so both vertical and horizontal lines are reflected
off of test part.');
fig = figure('name','Choose Line Positions');
previmg = imshow(ones(fliplr(get(vid,'VideoResolution'))));
208
set(gca,'xdir','normal','ydir','normal');
preview(vid,previmg);
axes(fsax);
linx = line([100 100],get(fsax,'ylim'),'linewidth',3,'color','w');
liny = line(get(fsax,'xlim'),[100 100],'linewidth',3,'color','w');
set(fsfig,'WindowButtonMotionFcn',@moti,'WindowButtonDownFcn',@sel);
x = 0;
y = 0;
set(fsfig, 'PointerShapeCData', nan(16));
set(fsfig, 'Pointer', 'custom'); % hide mouse cursor
uiwait(fsfig);
% [x,y] = ginput(1); % pick position of line
x = round(x);
y = round(y);
linmm = [x,y].*monpp;
v1234lin = uint8(zeros([fliplr(get(vid,'VideoResolution')),5]));
h1234lin = v1234lin;
stoppreview(vid);
close(fig)
if xflag
return;
end
% background pic
bkgnd = capic(blkscrn);
if xflag
return;
end
% vertical line pic
vscrn = zeros(fssiz);
vscrn(:,(x-0):(x+0)) = 255; % 1 pixel(s) wide
v1234lin(:,:,5) = capic(vscrn);
if xflag
return;
end
% horizontal line pic
hscrn = zeros(fssiz);
hscrn((y-0):(y+0),:) = 255; % 1 pixel(s) wide
h1234lin(:,:,5) = capic(hscrn);
if xflag
return;
end
209
% line phase shifting pics
phaseshift = (0:0.25:0.75).*2.*pi;
% permm = monpp.*100.1; % period in mm
for ij = 1:numel(phaseshift)
apodv = DW_apodizationgen([1,0],permm(1),phaseshift(ij),'cos',[cutdn,cutup],monpp);
v1234lin(:,:,ij) = capic(apodv);
if xflag
return;
end
apodh = DW_apodizationgen([0,1],permm(2),phaseshift(ij),'cos',[cutdn,cutup],monpp);
h1234lin(:,:,ij) = capic(apodh);
if xflag
return;
end
end
v1234lin = bsxfun(@minus,v1234lin,bkgnd);
h1234lin = bsxfun(@minus,h1234lin,bkgnd);
set(fsfig, 'Pointer', 'arrow');
function exitnow(~,~)
xflag = true;
end
function pic = capic(cdat)
set(fsimg,'cdata',cdat);
drawnow expose;
pause(0.5);
start(vid);
pic = uint8(squeeze(mean(getdata(vid),4)));
end
function moti(~,~)
cp = get(fsax,'CurrentPoint');
xdat = [1,1].*cp(1,1);
ydat = [1,1].*cp(1,2);
set(linx,'XData',xdat);
set(liny,'YData',ydat);
drawnow;
end
function sel(~,~)
cp = get(fsax,'CurrentPoint');
x = cp(1,1);
y = cp(1,2);
set([linx,liny],'visible','off');
set(fsfig,'WindowButtonMotionFcn',[]);
set(fsax,'ButtonDownFcn',[]);
uiresume(fsfig);
210
end
end
Dependency: DP_DataRegister3D.m
Registers reconstructed surface data to shape and position of ideal part.
function [xyzreg,xyzfin,Mxyzfin,err,errvec] =
DP_DataRegister3D(surfptsx,surfptsy,surfptsz,shapename,samples,edthresh)
% pn = 'C:\Users\Dan\Google Drive\Thesis\Reflector Profile from QVI\';
% fn =
{'Roch3_20mm_InverseFlex1.0_FullScan_1.DAT','Roch3_20mm_InverseFlex1.0_FullScan_2.DAT','R
och3_20mm_InverseFlex1.0_PartialHighDensityScan.DAT'};
% % scandir1 = [1,1,1];
% % scandir2 = [2,2,2];
% % edthresh = [3,3,1];
% angxyz = [pi(),0,-pi()/2;...
% pi(),0,-pi()/2;...
% 0,pi(),pi()];
figure(2);
figure(3);
set([2,3],'CloseRequestFcn',@finish);
errthresh = 0.98;
% ij = 1; % for loop implemetation
% raw = importdata([pn,fn{ij}],',',2);
%% Iterative Closest Point (ICP) calculations
shapedata = reflectorshapedatabase(shapename);
shape = shapedata.shape;
% xbnd = shapedata.xbnd;
length = shapedata.length; % extruded length of part
tilt = shapedata.tilt; % degrees
% thik = shapedata.thik; % perpendicular distance from xbnd(1) point on curve to plane
describing the rear face of the part
[Mx,My,Mz] = DP_SLSurfacePoints(shapename,samples);
Mz = -Mz;
M = [Mx(:).';My(:).';Mz(:).'];
D0 = [surfptsx(:),surfptsy(:),surfptsz(:)].';
D0(:,isnan(sum(D0,1))) = [];
R = eye(3);
D1 = R*D0;
T = mean(M,2)-mean(D1,2);
D = bsxfun(@plus,D1,T);
211
mplot = [0;0];
ICPplot(0,0,false);
%%
x = D(1,:).';
y = D(2,:).';
z = D(3,:).';
% dt = delaunay(x,y);
dt0temp = DelaunayTri(x,y);
% ed = edges(dt0);
% edlen = sqrt( diff(x(ed),1,2).^2 + diff(y(ed),1,2).^2 );
% edel = edlen>edthresh(ij);
% si0 = edgeAttachments(dt0,ed(edel,:));
% si = cell2mat(transpose(si0)).';
% sikeep = ~ismember((1:size(dt0,1)).',si);
% dt = dt0(sikeep,:);
% tri = TriRep(dt,x,y,z);
% fe = unique(freeBoundary(dt));
% fehi = fe(y(fe)>0);
% felo = fe(y(fe)<0);
% figure(1);
% clf;
% trisurf(tri);
% shading interp;
% xlabel('X'); ylabel('Y'); zlabel('Z');
% tsi = TriScatteredInterp(dt0,z);
% zs = tsi(Mx(:),My(:));
% err = Mz(:)-zs;
% zs(isnan(zs)) = 0;
%
line('xdata',Mx(:),'ydata',My(:),'zdata',zs,'color','k','linestyle','none','marker','d');
% axis equal;
tsitemp = TriScatteredInterp(dt0temp,z);
zstemp = tsitemp(Mx(:),My(:));
err = -Mz(:)+zstemp;
figure(3);
clf;
chlen = 32; % colormap half length
grad = linspace(0,1,chlen)';
cmp = [grad,grad,ones(chlen,1);
ones(chlen,1),flipud(grad),flipud(grad)];
colormap(3,cmp);
erax(1) = subplot_tight(1,2,1,0.05);
errmap = surf(Mx,My,Mz,reshape(err,size(Mx)));
if all(isnan(err))
caxis([-1,1]);
212
else
caxis(max(abs(err)).*[-1,1]);
end
xlabel('X'); ylabel('Y'); zlabel('Z');
axis equal;
colorbar;
erax(2) = subplot_tight(1,2,2,0.05);
errsurf = surf(Mx,My,reshape(err,size(Mx)));
if all(isnan(err))
caxis([-1,1]);
else
caxis(max(abs(err)).*[-1,1]);
end
xlabel('X'); ylabel('Y'); zlabel('Z');
% figure(2);
% plot3(x,y,z);
% axis equal;
% xlabel('X');
% ylabel('Y');
% zlabel('Z');
% manual adjustment figure
figure(4);
clf;
set(4,'color','w','position',[766 309 300 420],'CloseRequestFcn',@finish);
lab = {'X','Y','Z'};
lft = [0.05,0.25,0.65];
bot = [0.6,0.35,0.1];
bw = 0.3;
bh = 0.08;
for ik = 1:3
uicontrol(4,'style','text','string',lab{ik},'units','normal','position',[lft(1),bot(ik),0
.1,0.12],'backgroundcolor','w','fontweight','bold','fontsize',12);
uicontrol(4,'style','pushbutton','string','-
','units','normal','position',[lft(2),bot(ik),bw,bh],'UserData',-
ik,'callback',@rotclick,'fontweight','bold','fontsize',16,'backgroundcolor',[1 .5 .5]);
uicontrol(4,'style','pushbutton','string','+','units','normal','position',[lft(2),bot(ik)
+0.1,bw,bh],'UserData',ik,'callback',@rotclick,'fontweight','bold','fontsize',12,'backgro
undcolor',[1 .5 .5]);
uicontrol(4,'style','pushbutton','string','-
','units','normal','position',[lft(3),bot(ik),bw,bh],'UserData',-
ik,'callback',@transclick,'fontweight','bold','fontsize',16,'backgroundcolor',[.5 .5 1]);
uicontrol(4,'style','pushbutton','string','+','units','normal','position',[lft(3),bot(ik)
+0.1,bw,bh],'UserData',ik,'callback',@transclick,'fontweight','bold','fontsize',12,'backg
roundcolor',[.5 .5 1]);
end
213
rotinc =
uicontrol(4,'style','edit','string','0.1','units','normal','position',[lft(2),0.8,bw,0.05
],'UserData',0.1,'callback',@numinput);
transinc =
uicontrol(4,'style','edit','string','0.5','units','normal','position',[lft(3),0.8,bw,0.05
],'UserData',0.5);
uicontrol(4,'style','text','string','Increment','units','normal','position',[0.02,0.8,0.1
8,0.05],'backgroundcolor','w');
uicontrol(4,'style','text','string',sprintf('Rotation\ndegrees'),'units','normal','positi
on',[lft(2),0.87,bw,0.12],'backgroundcolor',[1 .5 .5],'fontweight','bold','fontsize',12);
uicontrol(4,'style','text','string',sprintf('Translation\nmm'),'units','normal','position
',[lft(3),0.87,bw,0.12],'backgroundcolor',[.5 .5 1],'fontweight','bold','fontsize',12);
uicontrol(4,'style','pushbutton','string','Rerun Iterative Closest
Point','units','normal','position',[0.05,0.01,0.9,0.07],'callback',{@ICPplot,true},'fonts
ize',12);
uiwait(4);
% perform final spatial transformations on original measured data (just in case)
Dreg = bsxfun(@plus,R*D0,T);
xreg = Dreg(1,:).';
yreg = Dreg(2,:).';
zreg = Dreg(3,:).';
xyzreg = [xreg,yreg,zreg]; % unsampled data for output
% get registered point locations (regular grid in x,y)
xsamp = Mx;
ysamp = My;
zsamp = updaterr();
zsamp = reshape(zsamp,size(xsamp));
% replace z=NaN points with value of nearest neighbor and change x and y values to be
near edge of valid data
nans = isnan(zsamp);
nnind = knnsearch([xreg,yreg],[xsamp(nans),ysamp(nans)]);
zsamp(nans) = zreg(nnind);
xsamp(nans) = xsamp(nans)+(xreg(nnind)-xsamp(nans)).*0.99;
ysamp(nans) = ysamp(nans)+(yreg(nnind)-ysamp(nans)).*0.99;
% position points relative to CPV origin
T1 = [-Mx(end);-length/2;-Mz(end)];
R1 = [cosd(-tilt),0,sind(-tilt);0,1,0;-sind(-tilt),0,cosd(-tilt)];
T2 = [0;0;shape(end)];
% Rfin = R1*R;
% Tfin = R1*(T+T1) + T2;
xyzfin = bsxfun(@plus,R1*[xsamp(:),ysamp(:),zsamp(:)].',R1*T1+T2);
xyzfin = reshape(xyzfin.',[size(xsamp),3]);
Mxyzfin = bsxfun(@plus,R1*[Mx(:),My(:),Mz(:)].',R1*T1+T2);
Mxyzfin = reshape(Mxyzfin.',[size(Mx),3]);
xyzreg = bsxfun(@plus,R1*xyzreg.',R1*T1+T2).';
% xfin = reshape(xyzfin(1,:),size(xsamp));
214
% yfin = reshape(xyzfin(2,:),size(ysamp));
% zfin = reshape(xyzfin(3,:),size(zsamp));
errvec = (R1*[0;0;1]).';
delete(2,3,4);
pause(0.1);
figure(2);
surf(xyzfin(:,:,1),xyzfin(:,:,2),xyzfin(:,:,3),reshape(err,size(xyzfin(:,:,1))));
errlistfin = sort(err);
cmaxfin = [errlistfin(round(sum(~isnan(err))*(1-
errthresh))),errlistfin(round(sum(~isnan(err))*errthresh))];
caxis(cmaxfin);
shading interp;
colorbar;
hold on;
modsurf = surf(Mxyzfin(:,:,1),Mxyzfin(:,:,2),Mxyzfin(:,:,3));
hold off;
axis equal;
surfchek =
uicontrol('style','checkbox','units','pixels','position',[10,10,200,15],'string','Fill
ideal surface','min',0,'max',1,'callback',@filltoggle);
filltoggle(surfchek,0);
%% Nested Functions
function filltoggle(src,~)
switch get(src,'value')
case 0
set(modsurf,'facecolor','none');
case 1
set(modsurf,'facecolor','k');
end
end
function zs = updaterr()
x = D(1,:).';
y = D(2,:).';
z = D(3,:).';
dt0 = DelaunayTri(x,y);
ed = edges(dt0);
edlen = sqrt( diff(x(ed),1,2).^2 + diff(y(ed),1,2).^2 );
edel = edlen>edthresh;
si0 = edgeAttachments(dt0,ed(edel,:));
si = cell2mat(transpose(si0)).';
% sikeep = ~ismember((1:size(dt0,1)).',si);
% dt1 = TriRep(dt0(sikeep,:),x,y);
% fe = unique(freeBoundary(dt1));
tsi = TriScatteredInterp(dt0,z);
215
zs = tsi(Mx(:),My(:));
pls = pointLocation(dt0,Mx(:),My(:));
zs(ismember(pls,si)) = NaN; % values in non-valid simplexes are set to NaN
err = -Mz(:)+zs;
set(errmap,'cdata',reshape(err,size(Mx)));
set(errsurf,'zdata',reshape(err,size(Mx)));
if all(isnan(err))
cmax = 1;
else
errlist = sort(abs(err));
cmax = errlist(round(sum(~isnan(err))*errthresh));
end
caxis(erax(1),cmax.*[-1,1]);
caxis(erax(2),cmax.*[-1,1]);
set(erax(2),'zlim',cmax.*1.1.*[-1,1]);
set(mplot(2),'xdata',x,'ydata',y,'zdata',z); % update ICP Result plot data
end
function ICPplot(~,~,errup)
[Ricp Ticp ER t] = icp(M, D, 25, 'Matching', 'kDtree', 'WorstRejection', 1-
errthresh);
R = Ricp*R;
T = T+Ticp;
% Plot model points blue and transformed points red
figure(2);
clf;
sp(1) = subplot(2,2,1);
plot3(M(1,:),M(2,:),M(3,:),'bo',D(1,:),D(2,:),D(3,:),'r.');
axis equal;
xlabel('x'); ylabel('y'); zlabel('z');
title('Red: measured, blue: modeled');
% Transform data-matrix using ICP result
D = bsxfun(@plus,R*D0,T);
% Plot the results
sp(2) = subplot(2,2,2);
mplot = plot3(M(1,:),M(2,:),M(3,:),'bo',D(1,:),D(2,:),D(3,:),'r.'); % modeled and
measure results
axis equal;
xlabel('x'); ylabel('y'); zlabel('z');
title('ICP result');
linkprop(sp, 'CameraPosition');
% Plot RMS curve
subplot(2,2,[3 4]);
plot((1:numel(ER))-1,ER,'--x');
xlabel('iteration#');
ylabel('d_{RMS}');
216
title(['Total elapsed time: ' num2str(t(end),2) ' s']);
if errup
updaterr();
end
end
function rotclick(bhan,~)
rax = abs(get(bhan,'UserData'));
dir = sign(get(bhan,'UserData'));
inc = abs(str2double(get(rotinc,'string')));
Rinc = [1,0,0;0,cosd(dir*inc),-sind(dir*inc);0,sind(dir*inc),cosd(dir*inc)];
switch rax
case 1 % rotation about x axis
case 2 % rotation about y axis
Rinc = Rinc([3,1,2],[3,1,2]);
case 3 % rotation about z axis
Rinc = Rinc([2,3,1],[2,3,1]);
end
Tinc = mean(D,2);
R = Rinc*R;
T = Rinc*(T-Tinc)+Tinc; % rotates about the data centroid
D = bsxfun(@plus,R*D0,T); % update D
updaterr();
end
function transclick(bhan,~)
tax = abs(get(bhan,'UserData'));
dir = sign(get(bhan,'UserData'));
inc = abs(str2double(get(transinc,'string')));
Tinc = zeros(3,1);
Tinc(tax) = dir*inc;
T = T+Tinc;
D = bsxfun(@plus,R*D0,T); % update D
updaterr();
end
function numinput(han,~)
val = str2double(get(han,'string'));
if isnan(val)
set(han,'string',num2str(get(han,'UserData'))); % if input is not numeric,
set to default
else
set(han,'string',num2str(val));
end
end
function finish(~,~)
uiresume(4);
end
end
217
Dependency: DP_datazoom.m
Resamples surface data in a user input region of interest and subtracts a two
dimensional polynomial of user-specified order.
function [x,y,z,Ds,A,Ps,polyv,Aexp] = DP_datazoom(xyzorig,xsamp,ysamp,polyord,varargin)
% xyzorig = [x,y,z] containing pointcloud data, each row defining a point
% xsamp = vector of x positions for sampling
% ysamp = vector of y positions for sampling
% sample points will be a mesh of xsamp and ysamp, size of numel(ysamp)
% by numel(xsamp)
% polyord = order of 2D polynomial for subtracting out surface figure
% % create interpolated data set
% F = TriScatteredInterp(xyzorig(:,1),xyzorig(:,2),xyzorig(:,3));
% [x,y] = meshgrid(xsamp,ysamp);
% z = F(x,y); % resampled raw data
% create inrerpolated data set while omitting gaps in data
edthresh = max([mean(diff(xsamp)),mean(diff(ysamp))]).*3;
dt0 = DelaunayTri(xyzorig(:,1),xyzorig(:,2));
ed = edges(dt0);
edlen = sqrt( (xyzorig(ed(:,2),1)-xyzorig(ed(:,1),1)).^2 + (xyzorig(ed(:,2),2)-
xyzorig(ed(:,1),2)).^2 );
edel = edlen>edthresh;
si0 = edgeAttachments(dt0,ed(edel,:));
si = cell2mat(transpose(si0)).';
F = TriScatteredInterp(dt0,xyzorig(:,3));
[x,y] = meshgrid(xsamp,ysamp);
z = F(x(:),y(:));
pls = pointLocation(dt0,x(:),y(:));
z(ismember(pls,si)) = NaN; % values in non-valid simplexes are set to NaN
z = reshape(z,size(x));
% % calcs for best fit plane analysis
% Xs = x-mean(x(:));
% Ys = y-mean(y(:));
% Zs = z-mean(z(:));
% XYZs = [Xs(:),Ys(:),Zs(:)];
% [V,D] = eig(XYZs.'*XYZs); % Find eigenvectors, columns of V [Z,Y,X] axes, where Z is
normal to plane. D contains the eigenvalues.
% dists = XYZs*V(:,1);
% Ds = reshape(dists,size(Zs)); % data point perpendicular distances from best fit plane
Ds = 0; % placeholder value
% calcs for best fit 2D nth order polynomial subtraction
nnind = ~isnan(x) & ~isnan(y) & ~isnan(z);
xZ = x(nnind);
218
yZ = y(nnind);
zZ = z(nnind);
polylen = sum(0:(polyord+1));
Aexp = zeros(2,polylen);
for ord = 0:polyord
posoff = sum(0:ord);
Aexp(1:2,(1:(ord+1))+posoff) = [ord:-1:0;0:1:ord];
end
A = bsxfun(@power,xZ(:),Aexp(1,:)) .* bsxfun(@power,yZ(:),Aexp(2,:)) \ zZ(:);
% A = [ones(size(xZ(:))) xZ(:) yZ(:) xZ(:).^2 xZ(:).*yZ(:) yZ(:).^2] \ zZ(:);
Ps = z-polyvaln(A,Aexp,x,y);
fsiz = fliplr(size(x));
scrn = [1600,800];
if fsiz(1)/fsiz(2) >= scrn(1)/scrn(2)
wh = 1;
else
wh = 2;
end
fsiz = fsiz./fsiz(wh).*scrn(wh);
fig = figure('color','w','position',[40,1050-(100+fsiz(2)),fsiz]);
ax = subplot(4,4,[1:3,5:7,9:11]);
axv = subplot(4,4,[4,8,12]);
axh = subplot(4,4,13:15);
flipy = false;
% contourf(x,y,Ps,50,'parent',ax);
% surf(x,y,Ps,'parent',ax,'edgecolor','none');
if nargin>4
cutofffrac = varargin{1};
else
cutofffrac = 0.01;
end
PsSort = sort(Ps(~isnan(Ps)));
cutlim = PsSort(round([numel(PsSort)*cutofffrac+1,numel(PsSort)*(1-cutofffrac)]));
imagesc(xsamp,ysamp,Ps,'parent',ax);
caxis(ax,cutlim);
title(ax, ['Subtracted 2D Polynomial of order ' int2str(polyord)]);
if flipy
set(axv,'ydir','reverse');
elseif ~flipy
set(ax,'ydir','normal');
end
set(ax,'dataaspectratio',[1,1,1],'dataaspectratiomode','manual');
axis(ax,'fill');
slicept = [mean(get(ax,'xlim')),mean(get(ax,'ylim'))];
colh = [0,.5,0];
colv = [0,0,1];
linh = line('xdata',[0,1],'ydata',[0,0],'parent',ax,'linewidth',2,'color',colh);
linv = line('xdata',[0,0],'ydata',[0,1],'parent',ax,'linewidth',2,'color',colv);
slich = line('xdata',[0,1],'ydata',[0,1],'parent',axh,'linewidth',2,'color',colh);
slicv = line('xdata',[0,1],'ydata',[0,1],'parent',axv,'linewidth',2,'color',colv);
219
pth = line('xdata',0,'ydata',0,'marker','o','markerfacecolor',colv,'parent',axh);
ptv = line('xdata',0,'ydata',0,'marker','o','markerfacecolor',colh,'parent',axv);
upslice(0,0);
set(fig,'WindowButtonDownFcn',@(dum1,dum2)
set(fig,'WindowButtonMotionFcn',@sliclick),'WindowButtonUpFcn',@(dum1,dum2)
set(fig,'WindowButtonMotionFcn',[]));
set(axv,'xgrid','on','YAxisLocation','right');
set(axh,'ygrid','on');
% zoh = zoom;
% setAllowAxesZoom(zoh,ax,true);
% setAllowAxesZoom(zoh,axh,false);
% setAllowAxesZoom(zoh,axv,false);
% set(zoh,'ActionPostCallback',@upslice);
axc = subplot(4,4,16);
colorvec = linspace(cutlim(1),cutlim(2),100).';
imagesc([0,abs(diff(cutlim))/10],colorvec,repmat(colorvec,1,2));
axis image;
set(axc,'YAxisLocation','right','XTick',[],'YDir','normal');
polyv = @(x,y) polyvaln(A,Aexp,x,y);
function sliclick(~,~)
cp = get(ax,'currentpoint');
slicept = cp(1,1:2);
upslice(0,0);
end
function upslice(~,~)
[~,slicexind] = min(abs(x(1,:)-slicept(1)));
[~,sliceyind] = min(abs(y(:,1)-slicept(2)));
slicexval = x(1,slicexind);
sliceyval = y(sliceyind,1);
slicezval = Ps(sliceyind,slicexind);
hdata = [x(sliceyind,:).',Ps(sliceyind,:).'];
vdata = [y(:,slicexind),Ps(:,slicexind)];
set(linh,'xdata',[x(1,1);x(1,end)],'ydata',sliceyval.*[1;1]);
set(linv,'xdata',slicexval.*[1;1],'ydata',[y(1,1);y(end,1)]);
set(slich,'xdata',hdata(:,1),'ydata',hdata(:,2));
set(slicv,'xdata',vdata(:,2),'ydata',vdata(:,1));
set(pth,'xdata',slicexval,'ydata',slicezval);
set(ptv,'xdata',slicezval,'ydata',sliceyval);
limx = get(ax,'xlim');
limy = get(ax,'ylim');
set(axh,'xlim',limx);
set(axv,'ylim',limy);
set(axh,'ylimmode','auto');
set(axv,'xlimmode','auto');
sliclim0 = [get(axh,'ylim');get(axv,'xlim')];
sliclim1 = [min(sliclim0(:,1)),max(sliclim0(:,2))];
sliclim = [max(sliclim1(1),cutlim(1)), min(sliclim1(2),cutlim(2))];
220
set(axh,'ylim',sliclim);
set(axv,'xlim',sliclim);
end
end
function z = polyvaln(P,Pexp,x,y)
zc = sum(bsxfun(@times, bsxfun(@power,x(:),Pexp(1,:)) .* bsxfun(@power,y(:),Pexp(2,:)),
P(:).'),2);
z = reshape(zc, size(x));
% z = P(1) + P(2).*x + P(3).*y + P(4).*x.^2 + P(5).*x.*y + P(6).*y.^2;
end
Dependency: DP_DualNoiseDeleteFilter.m
Detects white noise in two coincident images and creates a mask to isolate larger
smooth data regions.
function nmask = DP_DualNoiseDeleteFilter(nimgs,mask,aximg)
% nimgs = stack of 2D images to filter on;
% masks = ROI mask to apply to all input images
merts = nan(size(nimgs));
mask([1,end],:) = 0;
mask(:,[1,end]) = 0;
for im = 1:size(nimgs,3)
nimg = nimgs(:,:,im);
intinds = find(mask);
merts0 = nan(size(mask));
% tic;
for ij = intinds(:).'
merts0(ij) = stdnn(ij,nimg);
end
% toc;
% normalize merit values from each image before combining
merts0 = merts0-nanmin(merts0(:));
merts0 = merts0./nanmax(merts0(:));
merts(:,:,im) = merts0;
end
mertsum = nansum(merts,3); % sum merit values pixel by pixel across all images
mertsum(sum(~isnan(merts),3)==0) = nan;
mertsum = mertsum-nanmin(mertsum(:)); % re-normalize
mertsum = mertsum./nanmax(mertsum(:));
numbins = 100;
[yh,xh] = hist(mertsum(:),numbins);
[~,plocs] = findpeaks(yh,'sortstr','descend','minpeakdistance',round(numbins/10));
thresh = mean(xh(plocs(1:2)));
timg = nimgs; % thresholded image
nanfilt = mertsum>thresh | isnan(mertsum);
221
timg(repmat(nanfilt,[1,1,size(nimgs,3)])) = nan;
imgbw = imclose(~nanfilt,strel('square',3));
% tic;
stats = regionprops(imgbw,{'FilledArea','FilledImage','BoundingBox'});
% toc;
[~,ccind] = max([stats.FilledArea]);
nmask = stats(ccind).FilledImage;
bb = stats(ccind).BoundingBox;
nmask = padarray(nmask,[bb(2)-0.5,bb(1)-0.5],0,'pre');
nmask = padarray(nmask,[size(nimgs,1)-(bb(2)+0.5+bb(4)),size(nimgs,2)-
(bb(1)+0.5+bb(3))]+1,0,'post');
% gimg = imcrop(nimg,bb+[.5 .5 -1 -1]);
% gimg(~ccmask) = nan;
% gimg = padarray(gimg,[bb(2)-0.5,bb(1)-0.5],nan,'pre');
% gimg = padarray(gimg,[size(nimg,1)-(bb(2)+0.5+bb(4)),size(nimg,2)-
(bb(1)+0.5+bb(3))],nan,'post');
gimg = nimgs;
gimg(repmat(~nmask,[1,1,size(nimgs,3)])) = nan;
figure();
imagesc(mertsum);
colormap(jet);
colorbar;
axmer = gca;
figure();
subplot(2,1,1);
imagesc(nimgs(:,:,1));
colormap(jet);
aximg(1) = gca;
subplot(2,1,2);
imagesc(nimgs(:,:,2));
colormap(jet);
aximg(2) = gca;
figure();
bar(xh,yh);
line('xdata',[1;1].*thresh,'ydata',[0;max(yh)],'color','r');
figure();
subplot(2,1,1);
imagesc(timg(:,:,1));
colormap(jet);
axnew(1) = gca;
subplot(2,1,2);
imagesc(timg(:,:,2));
colormap(jet);
axnew(2) = gca;
figure();
222
subplot(2,1,1);
imagesc(gimg(:,:,1));
colormap(jet);
axfin(1) = gca;
subplot(2,1,2);
imagesc(gimg(:,:,2));
colormap(jet);
axfin(2) = gca;
linkaxes([axmer,axnew,axfin,aximg]);
% works well, but takes a while to run
function out = stdnn(ind,nimg) % std dev of nearest neighbors' distance from best fit
plane
inds = bsxfun(@plus,ind+(-1:1).',(-1:1).*size(nimg,1));
inds = inds(:);
[Xfit,Yfit] = meshgrid(-1:1,-1:1);
ptsc = [Xfit(:),Yfit(:),nimg(inds)-mean(nimg(inds))]; % points centered around
the mean in each dimension
[V,D] = eig(ptsc.'*ptsc); % Find eigenvectors, columns of V [Z,Y,X] axes, where Z
is normal to plane. D contains the eigenvalues.
dists = ptsc*V(:,1);
out = std(dists);
end
% toc = 17.0
% % bad filter for nearly flat data with a small amount of noise
% % doesn't pick up severe noise reliably
% function out = pathwalk(ind) % walk path around pixel and count number of
inflection points
% inds0 = nebind(ind,size(nimg,1),1);
% inds = [inds0;inds0(1)];
% out = nnz(diff(sign(diff(nimg(inds))))); % number of inflection points while
walking around pixel (max = 7);
% end
% % toc = 4.6
end
% function inds = nebind(ind,siz1,ord) % gives pixel indices of nearest neighbors of
order 'ord' around pixel with index 'ind' in image with 'siz1' number of rows
% top = ind + (-ord:ord).'.*siz1 - ord;
% bottom = ind + (-ord:ord).'.*siz1 + ord;
% left = ind + (-ord:ord).' - ord*siz1;
% right = ind + (-ord:ord).' + ord*siz1;
% inds = [top(2:1:end);right(2:1:end);bottom(end-1:-1:1);left(end-1:-1:1)];
% end
223
Dependency: DP_puma_ho.m
This code is identical to puma_ho.m provided in [50], except it points to
DP_energy_ho.m (below) instead of the original energy_ho.m function.
Dependency: DP_energy_ho.m
Function modified from [50] to completely ignore specified regions. The vast majority of
this code is unmodified from its original, publicly available source.
function erg = DP_energy_ho(kappa,psi,base,p,cliques,disc_bar,th,quant)
%energy_ho Energy from kappa labeling and psi phase measurements.
% erg = energy_ho(kappa,psi,base,p,cliques,disc_bar,p,th,quant) returns the energy of
kappa labeling given the
% psi measurements image, the base ROI image (having ones in the region of interest
(psi) and a passe-partout
% made of zeros), the exponent p, the cliques matrix (each row indicating a
displacement vector corresponding
% to each clique), the disc_bar (complement to one of the quality maps), a threshold th
defining a region for
% which the potential (before a possible quantization) is quadratic, and quant which is
a flag defining whether
% the potential is or is not quantized.
% (see J. Bioucas-Dias and G. Valadão, "Phase Unwrapping via Graph Cuts"
% submitted to IEEE Transactions Image Processing, October, 2005).
% SITE: www.lx.it.pt/~bioucas/
[m,n] = size(psi);
[cliquesm,cliquesn] = size(cliques); % Size of input cliques
maxdesl = max(max(abs(cliques))); % This is the maximum clique length used
% Here we put a passe-partout (constant length = maxdesl+1) in the images kappa and psi
base_kappa = zeros(2*maxdesl+2+m,2*maxdesl+2+n); base_kappa(maxdesl+2:maxdesl+2+m-
1,maxdesl+2:maxdesl+2+n-1) = kappa;
psi_base = zeros(2*maxdesl+2+m,2*maxdesl+2+n); psi_base(maxdesl+2:maxdesl+2+m-
1,maxdesl+2:maxdesl+2+n-1) = psi;
z = size(disc_bar,3);
base_disc_bar = repmat(zeros(2*maxdesl+2+m,2*maxdesl+2+n),[1 1 z]);
base_disc_bar(maxdesl+2:maxdesl+2+m-1,maxdesl+2:maxdesl+2+n-1,:) = disc_bar;
for t = 1:cliquesm
% The allowed start and end pixels of the "interpixel" directed edge
base_start(:,:,t) = circshift(base,[-cliques(t,1),-cliques(t,2)]).*base;
base_end(:,:,t) = circshift(base,[cliques(t,1),cliques(t,2)]).*base;
% By convention the difference images have the same size as the
224
% original ones; the difference information is retrieved in the
% pixel of the image that is subtracted (end of the diff vector)
auxili = circshift(base_kappa,[cliques(t,1),cliques(t,2)]);
t_dkappa(:,:,t) = (base_kappa-auxili);
auxili2 = circshift(psi_base,[cliques(t,1),cliques(t,2)]);
dpsi = auxili2 - psi_base;
% Beyond base, we must multiply by
% circshift(base,[cliques(t,1),cliques(t,2)]) in order to
% account for frontier pixels that can't have links outside ROI
a(:,:,t) = (2*pi*t_dkappa(:,:,t)-
dpsi).*base.*circshift(base,[cliques(t,1),cliques(t,2)])...
.*base_disc_bar(:,:,t);
end
erg = sum(sum(sum((clique_energy_ho(a,p,th,quant)))));
Dependency: DP_lsqiter.m
This code implements the iterative slope matching process described in Chapter 3 [52].
function [surfptsx,surfptsy,surfptsz] =
DP_lsqiter(nmask,unwpx,unwpy,R,T,xyoffset,cxcy,dxy,f,k1,xs,ys,zs,xc,yc,Ropt,Topt,lindist,
lmask1,lmask2,Rmir,Tmir)
% Least Squares Iteration Method
% find l vector for each data pixel
l = bsxfun(@plus,R*[unwpx(nmask),unwpy(nmask),zeros(nnz(nmask),1)].',T).';
% lmir = (Rmir.'*bsxfun(@minus,lcam.',Tmir)).';
% find if pixels in the up, down, left, and/or right directions are valid
imask = zeros(size(nmask));
numpix = nnz(nmask);
imask(nmask) = 1:numpix;
up = padarray(imask(1:(end-1),:),[1,0],0,'pre');
up = up(nmask);
uplog = logical(up);
down = padarray(imask(2:end,:),[1,0],0,'post');
down = down(nmask);
downlog = logical(down);
left = padarray(imask(:,1:(end-1)),[0,1],0,'pre');
left = left(nmask);
leftlog = logical(left);
right = padarray(imask(:,2:end),[0,1],0,'post');
right = right(nmask);
rightlog = logical(right);
% form sparse matrix D for slope averaging (slope vector will have u
% component of slopes followed by the v component of slopes
pind = repmat((1:numpix).',2,1); % pixel index (repeated once to have a copy for u and v)
225
nextp = [right;down]; % adjacent pixel index, u then v (adjacent pixel in the u direction
is to the right, v is down)
Diu0 = find(right); % row position for elements in D (u quadrant)
Dju = [Diu0; right(rightlog)]; % column position for elements in D (u quadrant)
Diu = [Diu0; Diu0];
Div0 = find(down); % row position for elements in D (v quadrant)
Djv = [Div0; down(downlog)]; % column position for elements in D (v quadrant)
Div = [Div0; Div0];
D = sparse([Diu;Div+numpix],[Dju;Djv+numpix],0.5,2*numpix,2*numpix); % v subscripts
shifted by numpix to put values in lower right quadrant
% find 3D ray direction vectors and their partial derivatives in u and v for all data
pixels
xo = xyoffset(1)-cxcy(1); % xyoffset(1): match indicies to uncropped camera frame,
cxcy(1): move origin to optical center
yo = xyoffset(2)-cxcy(2);
dx = dxy(1);
dy = dxy(2);
[v,u] = find(nmask);
sx =
dx.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(u+xo).*1.0./sqrt(f.^2+dx.^2.*(k1.*(dx
.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*
(v+yo).^2)+1.0).^2.*(v+yo).^2);
sy =
dy.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(v+yo).*1.0./sqrt(f.^2+dx.^2.*(k1.*(dx
.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*
(v+yo).^2)+1.0).^2.*(v+yo).^2);
sz =
f.*1.0./sqrt(f.^2+dx.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^
2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(v+yo).^2);
s = [sx(:),sy(:),sz(:)];
sxdu =
dx.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*1.0./sqrt(f.^2+dx.^2.*(k1.*(dx.^2.*(u+
xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^
2)+1.0).^2.*(v+yo).^2)+dx.^3.*k1.*(u.*2.0+xo.*2.0).*(u+xo).*1.0./sqrt(f.^2+dx.^2.*(k1.*(d
x.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.
*(v+yo).^2)+1.0).^2.*(v+yo).^2)-
dx.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(u+xo).*(dx.^2.*(u.*2.0+xo.*2.0).*(k1.
*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2+dx.^4.*k1.*(u.*2.0+xo.*2.0).*(k1.*(dx.^2.*(u
+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(u+xo).^2.*2.0+dx.^2.*dy.^2.*k1.*(u.*2.0+xo.*2.0).*(k1.*(
dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(v+yo).^2.*2.0).*1.0./(f.^2+dx.^2.*(k1.*(dx.^2.*
(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo
).^2)+1.0).^2.*(v+yo).^2).^(3.0./2.0).*(1.0./2.0);
sydu =
dy.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(v+yo).*(dx.^2.*(u.*2.0+xo.*2.0).*(k1.
*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2+dx.^4.*k1.*(u.*2.0+xo.*2.0).*(k1.*(dx.^2.*(u
+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(u+xo).^2.*2.0+dx.^2.*dy.^2.*k1.*(u.*2.0+xo.*2.0).*(k1.*(
dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(v+yo).^2.*2.0).*1.0./(f.^2+dx.^2.*(k1.*(dx.^2.*
(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo
226
).^2)+1.0).^2.*(v+yo).^2).^(3.0./2.0).*(-
1.0./2.0)+dx.^2.*dy.*k1.*(u.*2.0+xo.*2.0).*(v+yo).*1.0./sqrt(f.^2+dx.^2.*(k1.*(dx.^2.*(u+
xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^
2)+1.0).^2.*(v+yo).^2);
szdu =
f.*(dx.^2.*(u.*2.0+xo.*2.0).*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2+dx.^4.*k1.*
(u.*2.0+xo.*2.0).*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(u+xo).^2.*2.0+dx.^2.*dy
.^2.*k1.*(u.*2.0+xo.*2.0).*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(v+yo).^2.*2.0)
.*1.0./(f.^2+dx.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k
1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(v+yo).^2).^(3.0./2.0).*(-1.0./2.0);
sdu = [sxdu(:),sydu(:),szdu(:)];
sdu = bsxfun(@rdivide,sdu,sqrt(sum(sdu.^2,2)));
sxdv =
dx.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(u+xo).*(dy.^2.*(v.*2.0+yo.*2.0).*(k1.
*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2+dy.^4.*k1.*(v.*2.0+yo.*2.0).*(k1.*(dx.^2.*(u
+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(v+yo).^2.*2.0+dx.^2.*dy.^2.*k1.*(v.*2.0+yo.*2.0).*(k1.*(
dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(u+xo).^2.*2.0).*1.0./(f.^2+dx.^2.*(k1.*(dx.^2.*
(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo
).^2)+1.0).^2.*(v+yo).^2).^(3.0./2.0).*(-
1.0./2.0)+dx.*dy.^2.*k1.*(v.*2.0+yo.*2.0).*(u+xo).*1.0./sqrt(f.^2+dx.^2.*(k1.*(dx.^2.*(u+
xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^
2)+1.0).^2.*(v+yo).^2);
sydv =
dy.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*1.0./sqrt(f.^2+dx.^2.*(k1.*(dx.^2.*(u+
xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^
2)+1.0).^2.*(v+yo).^2)+dy.^3.*k1.*(v.*2.0+yo.*2.0).*(v+yo).*1.0./sqrt(f.^2+dx.^2.*(k1.*(d
x.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.
*(v+yo).^2)+1.0).^2.*(v+yo).^2)-
dy.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(v+yo).*(dy.^2.*(v.*2.0+yo.*2.0).*(k1.
*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2+dy.^4.*k1.*(v.*2.0+yo.*2.0).*(k1.*(dx.^2.*(u
+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(v+yo).^2.*2.0+dx.^2.*dy.^2.*k1.*(v.*2.0+yo.*2.0).*(k1.*(
dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(u+xo).^2.*2.0).*1.0./(f.^2+dx.^2.*(k1.*(dx.^2.*
(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo
).^2)+1.0).^2.*(v+yo).^2).^(3.0./2.0).*(1.0./2.0);
szdv =
f.*(dy.^2.*(v.*2.0+yo.*2.0).*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2+dy.^4.*k1.*
(v.*2.0+yo.*2.0).*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(v+yo).^2.*2.0+dx.^2.*dy
.^2.*k1.*(v.*2.0+yo.*2.0).*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).*(u+xo).^2.*2.0)
.*1.0./(f.^2+dx.^2.*(k1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(u+xo).^2+dy.^2.*(k
1.*(dx.^2.*(u+xo).^2+dy.^2.*(v+yo).^2)+1.0).^2.*(v+yo).^2).^(3.0./2.0).*(-1.0./2.0);
sdv = [sxdv(:),sydv(:),szdv(:)];
sdv = bsxfun(@rdivide,sdv,sqrt(sum(sdv.^2,2)));
% create sparse matrix, 'H', used to calculate 'h', applied to previous iteration's sigma
vector
hustat = acos(dot(s(rightlog,:),s(right(rightlog),:),2));
hvstat = acos(dot(s(downlog,:),s(down(downlog),:),2));
H = sparse([Diu;Div+numpix],[Dju;Djv],[hustat;hustat;hvstat;hvstat]./2,2*numpix,numpix);
% apply to old sigma vector to get new 'h' values
227
% Aones = sparse([Diu;Div+numpix],[Dju;Djv],[-ones(size(Diu0));ones(size(Diu0));-
ones(size(Div0));ones(size(Div0))],2*numpix,numpix);
% to create matrix A = bsxfun(@rdivide,Aones,H*sigma_old);
% % give initial values for sigma
% sigold = 420.*ones(nnz(nmask),1);
% initial control point values
XinitFcn = TriScatteredInterp(xc(:),yc(:),xs(:)); % using instead of 'griddata' function
for speed
YinitFcn = TriScatteredInterp(xc(:),yc(:),ys(:));
xinit = XinitFcn(u,v);
yinit = YinitFcn(u,v);
zinit = interp2(xs,ys,zs,xinit,yinit);
initmir = bsxfun(@plus,Ropt*[xinit(:),yinit(:),zinit(:)].',Topt);
initcam = bsxfun(@plus,Rmir*initmir,Tmir);
sig = reshape(sqrt(sum(initcam.^2,1)),size(u));
siguess = sig;
% create sparse matrices to find discrete slope vectors (u and v) at each point
ucenter = find(rightlog & leftlog);
uleftedge = find(rightlog & ~leftlog);
urightedge = find(~rightlog & leftlog);
vcenter = find(downlog & uplog);
vtopedge = find(downlog & ~uplog);
vbottomedge = find(~downlog & uplog);
unextpix = [right(ucenter);right(uleftedge);urightedge];
uprevpix = [left(ucenter);uleftedge;left(urightedge)];
vnextpix = [down(vcenter);down(vtopedge);vbottomedge];
vprevpix = [up(vcenter);vtopedge;up(vbottomedge)];
Bu =
sparse(repmat([ucenter;uleftedge;urightedge],2,1),[unextpix;uprevpix],[ones(size(unextpix
));-ones(size(uprevpix))],numpix,numpix);
Bv =
sparse(repmat([vcenter;vtopedge;vbottomedge],2,1),[vnextpix;vprevpix],[ones(size(vnextpix
));-ones(size(vprevpix))],numpix,numpix);
% prepare edge pixel data
edge1 = imask(logical(lmask1)); % valid pixel indices of edge 1
edge2 = imask(logical(lmask2)); % valid pixel indices of edge 2
fidflag = false; % flag for fiducial registration
if any(lmask1(:)>0 & lmask1(:)<1) || any(lmask2(:)>0 & lmask2(:)<1)
fidflag = true;
wedge1 = lmask1(logical(lmask1));
wedge2 = lmask2(logical(lmask2));
end
count = 1;
if fidflag
numit = 20;
else
numit = 5;
228
end
sigiter = nan(numit,1);
sigmeans = sigiter;
sigiter(1) = 0;
sigmeans(1) = mean(sig);
% plot
close all;
figure(7);
siglin = plot(sigiter,sigmeans,'-b','linewidth',2);
set(gca,'ygrid','on');
drawnow
% sub sampling indicies for plots
% sampvec = 1:30:length(nmask);
% [ssu,ssv] = meshgrid(sampvec,sampvec);
% subsamp = [];
% for ti = 1:numel(ssu)
% subsamp = [subsamp;find(u==ssu(ti) & v==ssv(ti))];
% end
xcc = round(xc(2:(end-1),2:(end-1)));
ycc = round(yc(2:(end-1),2:(end-1)));
offscrind = find( xcc<1 | xcc>size(imask,2) | ycc<1 | ycc>size(imask,1) );
xcc(offscrind) = 1; % false x subscript for sample points outside the ROI where there is
no image data
ycc(offscrind) = 1; % false y subscript for sample points outside the ROI where there is
no image data
ic = sub2ind(size(imask),ycc,xcc);
ic(offscrind) = []; % get rid of indices from false subscripts
subsamp0 = imask(ic);
subsamp = subsamp0(:);
subsamp(subsamp<1) = [];
% corner indicies for mirror plane
ucorner = [1;1;size(nmask,2);size(nmask,2)];
vcorner = [1;size(nmask,1);size(nmask,1);1];
sxcorner =
dx.*(k1.*(dx.^2.*(ucorner+xo).^2+dy.^2.*(vcorner+yo).^2)+1.0).*(ucorner+xo).*1.0./sqrt(f.
^2+dx.^2.*(k1.*(dx.^2.*(ucorner+xo).^2+dy.^2.*(vcorner+yo).^2)+1.0).^2.*(ucorner+xo).^2+d
y.^2.*(k1.*(dx.^2.*(ucorner+xo).^2+dy.^2.*(vcorner+yo).^2)+1.0).^2.*(vcorner+yo).^2);
sycorner =
dy.*(k1.*(dx.^2.*(ucorner+xo).^2+dy.^2.*(vcorner+yo).^2)+1.0).*(vcorner+yo).*1.0./sqrt(f.
^2+dx.^2.*(k1.*(dx.^2.*(ucorner+xo).^2+dy.^2.*(vcorner+yo).^2)+1.0).^2.*(ucorner+xo).^2+d
y.^2.*(k1.*(dx.^2.*(ucorner+xo).^2+dy.^2.*(vcorner+yo).^2)+1.0).^2.*(vcorner+yo).^2);
szcorner =
f.*1.0./sqrt(f.^2+dx.^2.*(k1.*(dx.^2.*(ucorner+xo).^2+dy.^2.*(vcorner+yo).^2)+1.0).^2.*(u
corner+xo).^2+dy.^2.*(k1.*(dx.^2.*(ucorner+xo).^2+dy.^2.*(vcorner+yo).^2)+1.0).^2.*(vcorn
er+yo).^2);
scorner0 = [sxcorner(:),sycorner(:),szcorner(:)];
scorner1 = [scorner0;0,0,0].';
mircorner0 = Rmir.'*bsxfun(@minus,scorner1,Tmir);
229
mircorner1 = bsxfun(@minus,mircorner0(:,1:4),mircorner0(:,5));
sigcorner = -mircorner0(3,5)./mircorner1(3,1:4);
mircorner = bsxfun(@plus,mircorner0(:,5),bsxfun(@times,sigcorner,mircorner1));
scorner = bsxfun(@plus,Rmir*mircorner,Tmir).';
figure(1);
ho =
plot3(s(subsamp(:),1).*siguess(subsamp(:)),s(subsamp(:),2).*siguess(subsamp(:)),s(subsamp
(:),3).*siguess(subsamp(:)),'or');
ax1 = gca;
hold on;
hn =
plot3(s(subsamp(:),1).*sig(subsamp(:)),s(subsamp(:),2).*sig(subsamp(:)),s(subsamp(:),3).*
sig(subsamp(:)),'+b');
% hl = 30;
% plot3([lindat.pt1(1)+hl.*lindat.dir1(1).*[-1;1],lindat.pt2(1)+hl.*lindat.dir2(1).*[-
1;1]],...
% [lindat.pt1(2)+hl.*lindat.dir1(2).*[-1;1],lindat.pt2(2)+hl.*lindat.dir2(2).*[-
1;1]],...
% [lindat.pt1(3)+hl.*lindat.dir1(3).*[-1;1],lindat.pt2(3)+hl.*lindat.dir2(3).*[-
1;1]],'-k','linewidth',2);
%
plot3([lindat.allpts1(:,1);lindat.allpts2(:,1)],[lindat.allpts1(:,2);lindat.allpts2(:,2)]
,[lindat.allpts1(:,3);lindat.allpts2(:,3)],'.g');
patch(scorner(:,1),scorner(:,2),scorner(:,3),zeros(4,1),'facecolor','k','facealpha',0.5);
hold off;
axis equal;
set(gca,'ydir','reverse','zdir','reverse');
legend([ho,hn],{'Start','Final'});
for it = 1:numit
%%%%%%%%%%% iteration start
tic;
sigold = sig;
[~,~,Su,Sv] = slpuv(l,sigold,s,sdu,sdv);
DS = D*[Su;Sv];
h = H*sigold;
hu = h((1:numpix).');
hv = h(numpix+(1:numpix).');
A = sparse([Diu;Div+numpix],[Dju;Djv],[-1./hu(rightlog);1./hu(rightlog);-
1./hv(downlog);1./hv(downlog)],2*numpix,numpix);
sig0 = A\DS;
sigshift0 = mean(sigold)-mean(sig0);
% find piston error (sigshift)
options = optimset('TolX',0.1,'PlotFcns',{@optimplotfval,@optimplotx});
if fidflag
% sigshift = fminsearch(@(ss) mertfid(ss,sig0), sigshift0, options);
% [~,surfptsx,surfptsy,surfptsz] = mertfid(sigshift,sig0);
[sigshift,fidold,fidnew] = fidsig(sigshift0,sig0);
line(fidold(:,1),fidold(:,2),fidold(:,3),'color','g','marker','d','parent',ax1);
% line connecting fiducial points on each iteration
230
line(fidnew(:,1),fidnew(:,2),fidnew(:,3),'color','c','marker','d','parent',ax1);
% line connecting fiducial points on each iteration
else
sigshift = fminsearch(@(ss) mertedge(ss,sig0), sigshift0, options);
% [~,surfptsx,surfptsy,surfptsz,lindat] = mertedge(sigshift,sig0);
end
% [~,~,~,~,C1,C2] = mertcurv(sigshift,sig0);
sig = sig0+sigshift;
sigiter(it+1) = it+1;
sigmeans(it+1) = mean(sig);
set(siglin,'xdata',sigiter,'ydata',sigmeans);
[~,surfptsx,surfptsy,surfptsz] = mertedge(0,sig);
set(hn,'xdata',s(subsamp(:),1).*sig(subsamp(:)));
set(hn,'ydata',s(subsamp(:),2).*sig(subsamp(:)));
set(hn,'zdata',s(subsamp(:),3).*sig(subsamp(:)));
drawnow
if all(sig==sigold)
break
end
% sigshifts = linspace(sigshift0-200, sigshift0+600, 81);
% merts = zeros(size(sigshifts));
% merts0 = merts;
% merts1 = merts;
% for ij = 1:numel(sigshifts)
% merts(ij) = mertedge(sigshifts(ij),sig0);
% [merts0(ij),merts1(ij)] = mertslpmtch(sigshifts(ij),sig0);
% end
% [~,surfptsx,surfptsy,surfptsz] = mertedge(sigshift0,sig0);
% sig = sig0+sigshift0;
toc;
%%%%%%%%%%% iteration end
end
[~,~,~,~,C1,C2] = mertcurv(0,sig);
% % incident, reflected, and normal unit vectors for old sigma values
% figure(2);
% nquiver =
quiver3(s(subsamp(:),1).*sigold(subsamp(:)),s(subsamp(:),2).*sigold(subsamp(:)),s(subsamp
(:),3).*sigold(subsamp(:)),n(subsamp(:),1),n(subsamp(:),2),n(subsamp(:),3),0);
% axis equal;
% set(gca,'ydir','reverse','zdir','reverse');
% hold on;
% squiver = quiver3(s(subsamp(:),1).*(sigold(subsamp(:))-
1),s(subsamp(:),2).*(sigold(subsamp(:))-1),s(subsamp(:),3).*(sigold(subsamp(:))-
1),s(subsamp(:),1),s(subsamp(:),2),s(subsamp(:),3),0,'color','r');
% rquiver =
quiver3(s(subsamp(:),1).*sigold(subsamp(:)),s(subsamp(:),2).*sigold(subsamp(:)),s(subsamp
(:),3).*sigold(subsamp(:)),r(subsamp(:),1),r(subsamp(:),2),r(subsamp(:),3),0,'color','g')
;
231
% % ulins =
permute(cumsum(cat(3,bsxfun(@times,s(subsamp(:),:),sigold(subsamp(:))),sdu(subsamp(:),:),
bsxfun(@times,s(subsamp(:),:),Su(subsamp(:)))),3),[3,1,2]);
% % plot3(ulins(:,:,1),ulins(:,:,2),ulins(:,:,3),'-k');
% hold off;
% new surface in mirror reference frame
figure(3);
surfl(surfptsx,surfptsy,surfptsz);
shading interp;
colormap(gray);
axis equal;
set(gca,'ydir','reverse','zdir','reverse');
% % ray error plot with sigshift slider
% figure(4);
% panh = uipanel('units','normal','position',[0 0 .9 1]);
% axes('parent',panh);
% rays =
plot3(s(subsamp(:),1).*(sig0(subsamp(:))+sigshift),s(subsamp(:),2).*(sig0(subsamp(:))+sig
dhift),s(subsamp(:),3).*(sig0(subsamp(:))+sigshift),'+b');
% % merit functions plot
% norm21 = @(x) (x-min(x(:)))./(max(x(:))-min(x(:)));
% merts = norm21(merts);
% merts0 = norm21(merts0);
% merts1 = norm21(merts1);
% figure(5);
% mertlins = plot(sigshifts,merts,sigshifts,merts0,sigshifts,merts1);
% legend(mertlins,{'Part Size','Raytrace Distance','Surface Normal Angle'});
% curvatures plot
opengl software;
figure(6);
set(6,'position',[194 61 1469 376]);
clohi = round(numpix.*[0.1,0.9]);
C12sort = sort([C1(:);C2(:)]);
C1t2sort = sort(C1(:).*C2(:));
C12lim = C12sort(clohi.*2).';
C1t2lim = C1t2sort(clohi).';
axc(1) = subplot_tight(1,7,1:2,0.05);
im(1) = imagesc(C1,C12lim);
axis image off;
colorbar;
title('Principle Curvature 1 = k_1');
axc(2) = subplot_tight(1,7,3:4,0.05);
im(2) = imagesc(C2,C12lim);
axis image off;
colorbar;
title('Principle Curvature 2 = k_2');
axc(3) = subplot_tight(1,7,5:6,0.05);
232
im(3) = imagesc(C1.*C2,C1t2lim);
axis image off;
colorbar;
title('Gaussian Curvature = k_1 x k_2');
linkaxes(axc);
set(im, 'AlphaData', ~isnan(C1));
% save_to_base(1);pause(1);
function [dsp,fidold,fidnew] = fidsig(ds,sig0)
% function calculates new sigshift(="delta sigma prime"=dsp) given current
sigshift(="delta sigma"=ds) and distance between fiducials
% get xyz edge points in camera reference frame
edge3d1 = bsxfun(@times,s(edge1,:),sig0(edge1)+ds);
edge3d2 = bsxfun(@times,s(edge2,:),sig0(edge2)+ds);
fid1 = sum(bsxfun(@times,wedge1,edge3d1),1); % xyz coords of fiducial point 1
fid2 = sum(bsxfun(@times,wedge2,edge3d2),1); % xyz coords of fiducial point 2
fidold = [fid1;fid2];
adist = sqrt(sum((fid2-fid1).^2)); % current distance between fiducials
r = lindist/adist; % ratio of actual distance between fiducials to calculated one
s1pds = norm(fid1);
s2pds = norm(fid2);
cosgam = sum(fid1.*fid2)/(s1pds*s2pds); % cosine of angle between fiducial
vectors (from camera origin)
s1 = s1pds-ds; % distance to fiducial 1 without sigshift(ds)
s2 = s2pds-ds;
a = 2*(1-cosgam); % quadratic formula "a"
b = 2*(1-cosgam)*(s1+s2); % quadratic formula "b"
c = s1^2+s2^2-2*s1*s2*cosgam-r^2*(s1pds^2+s2pds^2-2*s1pds*s2pds*cosgam); %
quadratic formula "c"
dsp = (-b+sqrt(b^2-4*a*c))/(2*a); % "delta sigma prime", take "+" solution since
the "-" solution will put the part behind the camera
edge3d1n = bsxfun(@times,s(edge1,:),sig0(edge1)+dsp);
edge3d2n = bsxfun(@times,s(edge2,:),sig0(edge2)+dsp);
fid1n = sum(bsxfun(@times,wedge1,edge3d1n),1); % xyz coords of new fiducial point
1
fid2n = sum(bsxfun(@times,wedge2,edge3d2n),1); % xyz coords of new fiducial point
2
fidnew = [fid1n;fid2n];
end
function [mert,surfptsx,surfptsy,surfptsz] = mertfid(sigshift,sig0)
% get xyz edge points in mirror reference frame
surfpts0 = (Rmir.'*bsxfun(@minus,bsxfun(@times,s,sig0+sigshift).',Tmir)).'; %
into mirror reference frame
edge3d1 = surfpts0(edge1,:);
edge3d2 = surfpts0(edge2,:);
fid1 = sum(bsxfun(@times,wedge1,edge3d1),1);
fid2 = sum(bsxfun(@times,wedge2,edge3d2),1);
adist = sqrt(sum((fid2-fid1).^2));
mert = abs(adist-lindist);
233
if nargout > 1
surfptsx = nan(size(nmask));
surfptsy = nan(size(nmask));
surfptsz = nan(size(nmask));
surfptsx(nmask) = surfpts0(:,1);
surfptsy(nmask) = surfpts0(:,2);
surfptsz(nmask) = surfpts0(:,3);
end
end
function [mert,surfptsx,surfptsy,surfptsz,lindat] = mertedge(sigshift,sig0)
% get xyz edge points in mirror reference frame
surfpts0 = (Rmir.'*bsxfun(@minus,bsxfun(@times,s,sig0+sigshift).',Tmir)).'; %
into mirror reference frame
edge3d1 = surfpts0(edge1,:);
edge3d2 = surfpts0(edge2,:);
L1 = mean(edge3d1,1);
L2 = mean(edge3d2,1);
[coeff1] = princomp(edge3d1);
[coeff2] = princomp(edge3d2);
dir1 = coeff1(:,1).';
dir2 = coeff2(:,1).';
dist1 = norm(L1-L2-dot(L1-L2,dir2).*dir2);
dist2 = norm(L2-L1-dot(L2-L1,dir1).*dir1);
adist = (dist1+dist2)/2;
mert = abs(adist-lindist);
if nargout > 1
surfptsx = nan(size(nmask));
surfptsy = nan(size(nmask));
surfptsz = nan(size(nmask));
surfptsx(nmask) = surfpts0(:,1);
surfptsy(nmask) = surfpts0(:,2);
surfptsz(nmask) = surfpts0(:,3);
lindat =
struct('pt1',L1,'dir1',dir1./norm(dir1),'allpts1',edge3d1,'pt2',L2,'dir2',dir2./norm(dir2
),'allpts2',edge3d2);
end
end
function [mert,surfptsx,surfptsy,surfptsz,C1,C2] = mertcurv(sigshift,sig0)
% get xyz surface points in mirror reference frame
surfpts0 = (Rmir.'*bsxfun(@minus,bsxfun(@times,s,sig0+sigshift).',Tmir)).'; %
into mirror reference frame
surfptsx = nan(size(nmask));
surfptsy = nan(size(nmask));
surfptsz = nan(size(nmask));
surfptsx(nmask) = surfpts0(:,1);
234
surfptsy(nmask) = surfpts0(:,2);
surfptsz(nmask) = surfpts0(:,3);
% find surface curvatures
distx = diff(surfptsx,1,2);
disty = diff(surfptsy,1,1);
fx = diff(surfptsz,1,2)./distx;
fxx = diff(fx,1,2)./distx(:,1:(end-1));
fxx = fxx(1:(size(nmask,1)-2),1:(size(nmask,2)-2));
fy = diff(surfptsz,1,1)./disty;
fyy = diff(fy,1,1)./disty(1:(end-1),:);
fyy = fyy(1:(size(nmask,1)-2),1:(size(nmask,2)-2));
fxy = diff(fx,1,1)./disty(:,1:(end-1));
fxy = fxy(1:(size(nmask,1)-2),1:(size(nmask,2)-2));
fx = fx(1:(size(nmask,1)-2),1:(size(nmask,2)-2));
fy = fy(1:(size(nmask,1)-2),1:(size(nmask,2)-2));
K = (fxx.*fyy-fxy.^2)./(1+fx.^2+fy.^2).^2; % gaussian curvature
Hc = ((1+fx.^2).*fyy+(1+fy.^2).*fxx-2.*fx.*fy.*fxy)./(2.*(1+fx.^2+fy.^2).^(3/2));
% mean curvature
kern = Hc.^2-K;
C1 = Hc+sqrt(kern); % principal curvature 1
C2 = Hc-sqrt(kern); % principal curvature 2
% calculate merit value (sum of minimum absolute curvature)
mert0 = min(abs(C1),abs(C2))./max(abs(C1),abs(C2));
mert = nansum(K(:));
end
function [mert,mert0,surfptsx,surfptsy,surfptsz,monpts,nangs] =
mertslpmtch(sigshift,sig0)
nrefl = slpuv(l,sig0+sigshift,s,0,0);
% get xyz surface points in mirror reference frame
surfpts0 = (Rmir.'*bsxfun(@minus,bsxfun(@times,s,sig0+sigshift).',Tmir)).'; %
into mirror reference frame
if nargout > 1
surfptsx = nan(size(nmask));
surfptsy = nan(size(nmask));
surfptsz = nan(size(nmask));
surfptsx(nmask) = surfpts0(:,1);
surfptsy(nmask) = surfpts0(:,2);
surfptsz(nmask) = surfpts0(:,3);
end
uvec = Bu*surfpts0;
vvec = Bv*surfpts0;
ndisc0 = cross(uvec,vvec,2);
ndisc = bsxfun(@rdivide,ndisc0,sqrt(nansum(ndisc0.^2,2)));
nangs = acos(nansum(nrefl.*ndisc,2));
mert0 = sqrt(sum(nangs(:).^2));
235
% find reflection vectors
reflvec = s - bsxfun(@times, 2.*sum(ndisc.*s,2), ndisc);
% move S and S+r into the monitor reference frame
S = bsxfun(@times,sig0+sigshift,s);
Spr = S+reflvec;
amon = (R.'*bsxfun(@minus,S.',T)).';
bmon = (R.'*bsxfun(@minus,Spr.',T)).'-amon;
% find positions of reflected rays on monitor (z=0 plane)
xmon = -amon(:,3)./bmon(:,3).*bmon(:,1) + amon(:,1);
ymon = -amon(:,3)./bmon(:,3).*bmon(:,2) + amon(:,2);
if nargout > 4
monpts = bsxfun(@plus,R*[xmon,ymon,zeros(size(xmon))].',T).';
end
% find positional error
err = sqrt( (xmon-unwpx(nmask)).^2 + (ymon-unwpy(nmask)).^2 );
mert = sqrt(nansum(err(:).^2)); % sum of squares
if count==1
assignin('base','ndisc',ndisc);
count = 2;
end
end
end
function [n,r,Su,Sv] = slpuv(l,sig,s,sdu,sdv) % for l, s, sdu, and sdv, rows are x,y,z
components of vectors pertaining to each data pixel, sig is a column vector
rlong = l-bsxfun(@times,s,sig);
r = bsxfun(@rdivide,rlong,sqrt(sum(rlong.^2,2)));
nlong = s-r;
n = bsxfun(@rdivide,nlong,sqrt(sum(nlong.^2,2)));
if nargout > 2
Su = -sum(sdu.*n,2)./sum(s.*n,2);
Sv = -sum(sdv.*n,2)./sum(s.*n,2);
end
end
Dependency: DP_MaskEditor.m
Manual noise mask editor implemented in case of obvious errors in
DP_DualNoiseDeleteFilter.m. User may “paint” new valid regions as well as delete mistakenly
valid regions.
function nmask =
DP_MaskEditor(nmasko,v1234lincrop,h1234lincrop,wpx,wpy,unwpx,unwpy,fidpicrop)
236
% process images to be uint8 rgb and store in a cell array
imnames = {'Original Mask';'Vertical Fringe 1';'Vertical Fringe 2';'Vertical Fringe
3';'Vertical Fringe 4';'Vertical Line';...
'Horizontal Fringe 1';'Horizontal Fringe 2';'Horizontal Fringe 3';'Horizontal Fringe
4';'Horizontal Line';...
'Wrapped X Phase';'Wrapped Y Phase';'Unwrapped X Phase';'Unwrapped Y Phase';'Fiducial
Picture';'None'};
nmask = nmasko;
border = bordcalc(nmask);
numimg = length(imnames);
bgs = cell(numimg,1);%uint8(zeros([size(nmask),3,numimg])); % background images
for im = 1:(numimg-1)
switch im
case 1
imin = nmasko;
case {2,3,4,5,6}
imin = v1234lincrop(:,:,im-1);
case {7,8,9,10,11}
imin = h1234lincrop(:,:,im-6);
case 12
imin = wpx;
case 13
imin = wpy;
case 14
imin = unwpx;
case 15
imin = unwpy;
case 16
imin = fidpicrop;
case 17
imin = zeros(size(nmask));
end
if (max(imin(:))-min(imin(:)))==0
iminsca = uint8(zeros(size(nmask)));
else
imin = double(imin);
iminsca = uint8((imin-min(imin(:)))./(max(imin(:))-min(imin(:))).*255); % scale
to [0,255] and convert to uint8 to save memory
end
bgs{im} = repmat(iminsca,[1,1,3]);
clear imin
end
clear v1234lincrop h1234lincrop unwpx unwpy wpx wpy fidpicrop
% initialize figure
mfig = pptfig('Mask Editor',1);
opengl hardware;
ofigpos = get(mfig,'position');
imsiz = size(nmask);
wid = 250;
237
figsiz = [round(ofigpos(4)/imsiz(1)*imsiz(2)+wid),ofigpos(4)]; % figure size [width,
height]: 'wfactor' times width of image
set(mfig,'position',[ofigpos(1:2),figsiz],'PointerShapeCData',nan(16),'WindowButtonMotion
Fcn',@pointerswitch);
imax =
axes('units','pixels','position',[1,1,round(ofigpos(4)/imsiz(1)*imsiz(2)),ofigpos(4)]);
img = imshow(bgs{1});
axis image
ovax =
axes('units','pixels','position',[1,1,round(ofigpos(4)/imsiz(1)*imsiz(2)),ofigpos(4)],'vi
sible','off');
noverlay =
imshow(uint8(cat(3,zeros(size(nmask)),zeros(size(nmask)),255.*ones(size(nmask)))));
axis image
linkaxes([imax,ovax]);
% hold on
% noverlay =
imshow(uint8(cat(3,zeros(size(nmask)),zeros(size(nmask)),255.*ones(size(nmask)))));
% hold off
alph = 0.5;
panh =
uipanel(mfig,'units','pixels','position',[round(ofigpos(4)/imsiz(1)*imsiz(2))+1,1,figsiz(
1)-round(ofigpos(4)/imsiz(1)*imsiz(2)),ofigpos(4)]);
butg =
uibuttongroup('units','pixels','position',[round(ofigpos(4)/imsiz(1)*imsiz(2))+1,1,figsiz
(1)-round(ofigpos(4)/imsiz(1)*imsiz(2)),ofigpos(4)]);
% controls
ctexts = {'Overlay','Border','Background','Brush Size (px)','Draw','Erase','Crop To
Original','Reset'};
cstyles =
{'checkbox','checkbox','popupmenu','edit','radio','radio','pushbutton','pushbutton'};
cbacks = {@drawoverlay, @drawoverlay, @backswitch, @brushsize, 0, 0, @crop2org, @reset};
cposind = [1,2,3,5,6,7,9,10];
numcon = length(ctexts);
ch = 0.05;
chan = zeros(numcon,1);
for ci = 1:numcon
ctext = ctexts{ci};
cstyle = cstyles{ci};
cback = cbacks{ci};
cposv = 1-(cposind(ci)/max(cposind))+(1/max(cposind)-ch)/2;
if any(strcmp(cstyle,{'pushbutton','checkbox'}));
chan(ci) =
uicontrol(panh,'style',cstyle,'units','normal','position',[0.3,cposv,0.4,ch],'string',cte
xt,'callback',cback);
elseif strcmp(cstyle,'radio');
chan(ci) =
uicontrol(butg,'style',cstyle,'units','normal','position',[0.3,cposv,0.4,ch],'string',cte
xt);
else
238
uicontrol(panh,'style','text','units','normal','position',[0.05,cposv,0.4,ch],'string',ct
ext,'horizontalalignment','right');
chan(ci) =
uicontrol(panh,'style',cstyle,'units','normal','position',[0.5,cposv,0.45,ch],'string',ct
ext,'horizontalalignment','left','min',0,'max',1,'callback',cback);
end
end
set(chan(1:2),'value',1);
set(chan(3),'string',imnames);
brushsiz = [10,10];
set(chan(4),'string',num2str(brushsiz(1)));
brush =
rectangle('hittest','off','edgecolor','none','facecolor','r','position',[1,1,brushsiz],'v
isible','off');
set(chan(3),'value',2);
backswitch(chan(3),0);
drawoverlay();
%debug
set(mfig,'WindowButtonDownFcn',@(~,~) disp(get(ovax,'currentpoint')));
uiwait(mfig);
%% Nested Functions
function reset(~,~)
nmask = nmasko;
border = bordcalc(nmask);
drawoverlay();
end
function crop2org(~,~)
nmask = nmask & nmasko;
border = bordcalc(nmask);
drawoverlay();
end
function brushsize(~,~)
val = 10; % default brush size
newsiz = str2double(get(chan(4),'string'));
if isnumeric(newsiz) && ~isnan(newsiz)
val = round(abs(newsiz));
val = max(val,1);
val = min(val,50);
end
brushsiz = [val,val];
set(chan(4),'string',num2str(val));
end
function pointerswitch(~,~)
239
cp = get(ovax,'currentpoint');
cp = cp(1,1:2);
axlim = [get(ovax,'xlim');get(ovax,'ylim')].';
if all(cp>=axlim(1,:)) && all(cp<=axlim(2,:))
set(mfig,'pointer','custom','WindowButtonDownFcn',@brushclick);
set(brush,'visible','on','position',[round(cp)-0.5,brushsiz]);
else
set(mfig,'pointer','arrow','WindowButtonDownFcn',[]);
set(brush,'visible','off');
end
end
function brushclick(~,~)
if get(butg,'SelectedObject')==chan(5)
val = 1;
elseif get(butg,'SelectedObject')==chan(6)
val = 0;
end
set(mfig,'WindowButtonMotionFcn',{@paint,val},'WindowButtonUpFcn',@brushrelease);
paint(0,0,val);
end
function brushrelease(~,~)
set(mfig,'WindowButtonMotionFcn',@pointerswitch,'WindowButtonUpFcn',[]);
end
function paint(~,~,val)
cp = get(ovax,'currentpoint');
cp = round(cp(1,1:2));
rows = cp(2):(cp(2)+brushsiz(2)-1);
rows(rows>imsiz(1) | rows<1) = [];
cols = cp(1):(cp(1)+brushsiz(1)-1);
cols(cols>imsiz(2) | cols<1) = [];
nmask(rows,cols) = val;
border = bordcalc(nmask);
set(brush,'position',[round(cp)-0.5,brushsiz]);
drawoverlay();
end
function backswitch(handle,~)
picind = get(handle,'value');
set(img,'cdata',bgs{picind});
drawnow expose;
end
function drawoverlay(varargin)
overval = [get(chan(1),'value'),get(chan(2),'value')];
if all(overval==[0,0])
adat = zeros(size(nmask));
elseif all(overval==[1,0])
adat = nmask.*alph;
240
elseif all(overval==[0,1])
adat = border;
elseif all(overval==[1,1])
adat = nmask.*alph+border.*(1-alph);
end
set(noverlay,'alphadata',adat);
end
end
function border = bordcalc(nmask)
nmasku = circshift(nmask,[1,0]);
nmaskd = circshift(nmask,[-1,0]);
nmaskl = circshift(nmask,[0,1]);
nmaskr = circshift(nmask,[0,-1]);
nmasku(1,:) = 0;
nmaskd(end,:) = 0;
nmaskl(:,1) = 0;
nmaskr(:,end) = 0;
border = nmask & (~nmasku|~nmaskd|~nmaskl|~nmaskr);
end
Dependency: DP_PhaseUnwrapper.m
Phase unwrapping routine that calls on the Puma algorithm [50].
function [unwpx,unwpy,croprect,xyoffset,nmask,vphir,hphir] =
DP_PhaseUnwrapper(v1234lin,h1234lin,linmm,permm)
v = double(v1234lin);
h = double(h1234lin);
vphi = atan2(v(:,:,4)-v(:,:,2),v(:,:,1)-v(:,:,3));
hphi = atan2(h(:,:,4)-h(:,:,2),h(:,:,1)-h(:,:,3));
% plot phase
figwp = pptfig('Wrapped Phase',1);
set(figwp,'position',[100 100 500 800]);
axv = subplot(2,1,1);
colormap(gray);
imagesc(vphi);
axis equal;
title('Interferogram (vert)');
axh = subplot(2,1,2);
colormap(gray);
imagesc(hphi);
axis equal;
title('Interferogram (horz)');
% pick ROI
241
roiconstraintfcn = makeConstrainToRectFcn('impoly',[1,size(vphi,2)],[1,size(vphi,1)]);
roi = impoly(axv,'PositionConstraintFcn',roiconstraintfcn);
wait(roi);
set(roi,'visible','off');
roimask = createMask(roi); % polygon mask
% vphi(~roimask) = nan; % nan out the area outside the ROI polygon to speed up subsequent
calcs
% hphi(~roimask) = nan; % ^
polypos = getPosition(roi);
croprect = [min(polypos(:,1)), min(polypos(:,2)), max(polypos(:,1))-min(polypos(:,1)),
max(polypos(:,2))-min(polypos(:,2))]; % bounding rectangle of ROI polygon
roimaskcrop = imcrop(roimask,croprect);
[xg,yg] = meshgrid(1:1:size(v1234lin,2),1:1:size(v1234lin,1));
xgc = imcrop(xg,croprect);
ygc = imcrop(yg,croprect);
xyoffset = [min(xgc(:)),min(ygc(:))]-1;
rectangle('Position',croprect,'parent',axv,'edgecolor','b','linestyle','--');
rectangle('Position',croprect,'parent',axh,'edgecolor','b','linestyle','--');
line('xdata',[polypos(:,1);polypos(1,1)],'ydata',[polypos(:,2);polypos(1,2)],'linestyle',
'-','color','b','parent',axv);
line('xdata',[polypos(:,1);polypos(1,1)],'ydata',[polypos(:,2);polypos(1,2)],'linestyle',
'-','color','b','parent',axh);
vphir = imcrop(vphi,croprect);
hphir = imcrop(hphi,croprect);
drawnow expose;
pause(0.5);
% discmask = DP_DualNoiseDeleteFilter(cat(3,vphir,hphir),roimaskcrop);
% % vphir(~discmask) = 0;
% % hphir(~discmask) = 0;
% discmaske = imerode(discmask,strel('disk',5));
% discmaskd = imdilate(discmask,strel('disk',5));
% PUMA processing
p=2; % Clique potential exponent
cliques = [1 0; 0 1];%; 1 1; 1 -1];
figpu = pptfig('PUMA Process',2);
set(figpu,'position',[600 100 500 800]);
axvpu = subplot(2,1,1);
[unwpv,iterv,erglistv] =
DP_puma_ho(vphir,p,axvpu,'schedule',[1],'cliques',cliques,'roi',roimaskcrop);%,'qualityma
ps',repmat(~discmaske,[1,1,size(cliques,1)])
axis equal;
title('Vertical Fringe Unwrap');
axhpu = subplot(2,1,2);
[unwph,iterh,erglisth] =
DP_puma_ho(hphir,p,axhpu,'schedule',[1],'cliques',cliques,'roi',roimaskcrop);%,'qualityma
ps',repmat(~discmaske,[1,1,size(cliques,1)])
axis equal;
title('Horizontal Fringe Unwrap');
242
% nmaskv = DP_NoiseDeleteFilter(unwpv,roimaskcrop);
% nmaskh = DP_NoiseDeleteFilter(unwph,roimaskcrop);
% nmask = nmaskv & nmaskh;
nmask = DP_DualNoiseDeleteFilter(cat(3,unwpv,unwph),roimaskcrop);
% convert phase to mm
unwpx = unwpv./2./pi.*permm(1);
vlin = imcrop(v(:,:,5),croprect);
vlin = vlin.*nmask;
vlinbw = im2bw(vlin, graythresh(vlin));
unwpx = unwpx-mean(unwpx(vlinbw))+linmm(1);
unwpxp = unwpx;
unwpxp(~nmask) = nan;
unwpy = unwph./2./pi.*permm(2);
hlin = imcrop(h(:,:,5),croprect);
hlin = hlin.*nmask;
hlinbw = im2bw(hlin, graythresh(hlin));
unwpy = unwpy-mean(unwpy(hlinbw))+linmm(2);
unwpyp = unwpy;
unwpyp(~nmask) = nan;
% plot unwrapped data
figuw = pptfig('Position of Reflected Ray on Monitor',3);
set(figuw,'position',[1100 100 500 800]);
subplot(2,1,1);
surfl(unwpxp);
shading interp;
colormap(gray);
axis equal;
set(gca,'ydir','reverse');
title('X Monitor Position');
subplot(2,1,2);
surfl(unwpyp);
shading interp;
colormap(gray);
axis equal;
set(gca,'ydir','reverse');
title('Y Monitor Position');
end
Dependency: DP_placepart3d_edge.m
Provides initial estimate of observed surface position and orientation for input into
DP_lsqiter.
243
function [xs,ys,zs,xc,yc,Ropt,Topt,lindist,lmask1,lmask2,shapename] =
DP_placepart3d_edge(f,k1,cxcy,dxy,Rmir,Tmir,nmask,xyoffset,shapename,fidpic,fidist)
close all;
samples = [30,30];
[x0,y0,z0,bordfcn] = DP_SLSurfacePoints(shapename,[10,5]);
pt1ind = 1;
pt2ind = sub2ind(size(x0),size(x0,1),1);
initoffset = [-x0(pt1ind),-y0(pt1ind)];
x0 = x0+initoffset(1);
y0 = y0+initoffset(2);
xb = bordfcn(x0);
yb = bordfcn(y0);
zb = bordfcn(z0);
pt1 = [x0(pt1ind);y0(pt1ind);z0(pt1ind)];
pt2 = [x0(pt2ind);y0(pt2ind);z0(pt2ind)];
dz = pt2(3)-pt1(3);
dxysq = sum((pt2(1:2)-pt1(1:2)).^2);
o = Rmir.'*(zeros(3,1)-Tmir);
% display 3d part surface model for reference
f1 = figure();
surf(x0,y0,z0,'facecolor','b','facealpha',0.3,'edgecolor','none');
axis equal;
rotate3d on;
set(gca,'ydir','reverse','zdir','reverse');
line('xdata',xb,'ydata',yb,'zdata',zb,'color','b','linewidth',2);
selecdot =
line('xdata',pt1(1),'ydata',pt1(2),'zdata',pt1(3),'marker','o','markeredgecolor','k','mar
kerfacecolor','r','markersize',10);
% display picture of masked unwrapping results
f2 = figure('position',[56 110 687 797]);
axpic = axes();
impic = imagesc(nmask);
colormap(gray);
axis image off;
contbut = uicontrol(f2,'units','normal','position',[.4 .02 .2
.07],'string','OK','visible','off','fontsize',16,'fontweight','bold');
set(f2,'name','Indicate Position of Point 1');
nerode = imerode(nmask,strel('diamond',1));
nbord = nmask & ~nerode;
[ybord,xbord] = find(nbord);
line('xdata',xbord,'ydata',ybord,'linestyle','none','color','g','marker','.','markersize'
,0.5);
244
% get input for first point
xcam10 = 0;
ycam10 = 0;
set(f2,'WindowButtonDownFcn',{@getcp,axpic},'pointer','crosshair');
uiwait(f2);
set(f2,'WindowButtonDownFcn',[],'pointer','arrow');
xcam1 = xcam10+xyoffset(1);
ycam1 = ycam10+xyoffset(2);
campt1 = [xcam1,ycam1];
campt2 = campt1+1;
% create polygon for displaying surface
polyg =
patch('vertices',[xb+xcam10,yb+ycam10],'faces',1:numel(xb),'facecolor','b','facealpha',0.
3,'edgecolor','b','linewidth',1.5,'parent',axpic);
ptmark =
line('xdata',xb([pt1ind;pt2ind])+xcam10,'ydata',yb([pt1ind;pt2ind])+ycam10,'linestyle','n
one','marker','o','markeredgecolor','k','markerfacecolor','r','markersize',10);
set(selecdot,'xdata',pt2(1),'ydata',pt2(2),'zdata',pt2(3));
% create figure of s1, s2, and surface in mirror reference frame
f3 = figure();
borderline = plot3(xb,yb,zb,'-b','linewidth',2);
axis equal;
grid on;
s1temp = [0;0;1].*abs(o(3));
l1 =
line('xdata',o(1)+[0;s1temp(1)],'ydata',o(2)+[0;s1temp(2)],'zdata',o(3)+[0;s1temp(3)],'co
lor','k','linewidth',2);
l2 =
line('xdata',o(1)+[0;s1temp(1)],'ydata',o(2)+[0;s1temp(2)],'zdata',o(3)+[0;s1temp(3)],'co
lor','r','linewidth',2);
set(gca,'xlimmode','auto','ylimmode','auto','zlimmode','auto','ydir','reverse','zdir','re
verse');
xlabel('X');ylabel('Y');zlabel('Z');
% create callback to draw surface in real time
axes(axpic);
set(f2,'name','Indicate Position of Point 2');
set(f2,'WindowButtonMotionFcn',@setpt2,'WindowButtonDownFcn',@selpt);
set(contbut,'visible','on','callback',@cont);
if isnumeric(shapename) % if surface is flat, let user change dimensions
shapedit(1) = uicontrol(f2,'style','edit','units','normal','position',[.02 .01 .1
.03],'string',num2str(shapename(1)),'userdata',shapename(1),'callback',@editflat);
shapedit(2) = uicontrol(f2,'style','edit','units','normal','position',[.14 .01 .1
.03],'string',num2str(shapename(2)),'userdata',shapename(2),'callback',@editflat);
end
uiwait(f2);
if isnumeric(shapename)
set(shapedit,'visible','off');
245
end
set(contbut,'visible','off');
[Rpart,Tpart] = pts2pos(campt1,campt2);
close([f1 f3]);
xlist0 = 1:size(nmask,2);
ylist0 = 1:size(nmask,1);
[xlist,ylist] = meshgrid(xlist0,ylist0);
%%%%%%%%%% Optimization Start %%%%%%%%%%%%%
% fminsearch (quicker, better if close to right answer)
rpyt0 = [0,0,atan2(Rpart(2),Rpart(1)),Tpart(:).'];
options = optimset('PlotFcns',@optimplotfval,'TolX',1e-2);%,'MaxIter',30);
rpytopt = fminsearch(@edgemert,rpyt0,options);
%%%% OR %%%%%
% % patternsearch (slower, better for bad initial guess?)
% rpyt0 = [0,0,atan2(Rpart(2),Rpart(1)),Tpart(:).'];
% angtol = [10,10,5]./180.*pi; % radians
% tratol = [3,3,20]; % mm
% rpytbnd = [rpyt0(1:3)-angtol,rpyt0(4:6)-tratol;...
% rpyt0(1:3)+angtol,rpyt0(4:6)+tratol];
% psoptions = psoptimset('UseParallel','always','TolMesh',1e-
3,'PlotFcns',{@psplotbestf,@psplotbestx,@psplotmeshsize},'SearchMethod',@MADSPositiveBasi
s2N,'CompletePoll','on');
% psproblem = struct('objective',@(x) posmertsca(x,rpyt0,rpytbnd),...
% 'X0', zeros(1,6),...
% 'Aineq',[],'bineq',[],'Aeq',[],'beq',[],...
% 'lb', -ones(1,6), 'ub', ones(1,6),...
% 'nonlcon',[],...
% 'solver', 'patternsearch',...
% 'options', psoptions,...
% 'rngstate',[]);
% rpytoptsca = patternsearch(psproblem);
% rpytopt = rpytoptsca.*diff(rpytbnd,1,1)./2+rpyt0;
%%%% OR %%%%%
% % two stage fminsearch, high level rotation only optimization with a
% % tranlastion only optimization on every iteration
% % very slow, but gives the good results
% rpyt0 = [0,0,atan2(Rpart(2),Rpart(1)),Tpart(:).'];
% % angtol = [7,7,3]./180.*pi; % radians
% % tratol = [3,3,20]; % mm
% % rpytbnd = [rpyt0(1:3)-angtol,rpyt0(4:6)-tratol;...
% % rpyt0(1:3)+angtol,rpyt0(4:6)+tratol];
% % options =
optimset('PlotFcns',@optimplotfval,'UseParallel','never','algorithm','interior-
point');%,'MaxIter',30);
246
% % ropt = fmincon(@(r)
posmert2stage([r,rpyt0(4:6)]),rpyt0(1:3),[],[],[],[],rpytbnd(1,1:3),rpytbnd(2,1:3),[],opt
ions); % almost always accepts initial point as optimized
% options = optimset('TolX',(1e-2)/180*pi,'display','iter');
% ropt = fminsearch(@(r) posmert2stage([r,rpyt0(4:6)]),rpyt0(1:3),options);
% [~,~,Topt] = posmert2stage([ropt,rpyt0(4:6)]);
% rpytopt = [ropt,Topt(:).'];
%%%%%%%%%%% Optimization End %%%%%%%%%%%%%%%
[mert,Ropt,Topt] = edgemert(rpytopt);
set(f2,'name',num2str(mert));
drawpoly(Ropt,Topt);
[xs,ys,zs,~,lindist,lind1,lind2,lindista,lind1a,lind2a] =
DP_SLSurfacePoints(shapename,samples);
bufs = [max(xs(:))-min(xs(:)),max(ys(:))-min(ys(:))]./2;
xs = [xs(:,1)+bufs(1).*sign(xs(:,1)-xs(:,2)), xs, xs(:,end)+bufs(1).*sign(xs(:,end)-
xs(:,end-1))];
ys = padarray(ys,[0,1],'replicate','both');
zs = [zs(:,1)+bufs(1)./abs(xs(:,2)-xs(:,3)).*(zs(:,1)-zs(:,2)), zs,
zs(:,end)+bufs(1)./abs(xs(:,end-1)-xs(:,end-2)).*(zs(:,end)-zs(:,end-1))];
xs = padarray(xs,[1,0],'replicate','both');
ys = [ys(1,:)+bufs(2).*sign(ys(1,:)-ys(2,:)); ys; ys(end,:)+bufs(2).*sign(ys(end,:)-
ys(end-1,:))];
zs = [zs(1,:)+bufs(2)./abs(ys(2,:)-ys(3,:)).*(zs(1,:)-zs(2,:)); zs;
zs(end,:)+bufs(2)./abs(ys(end-1,:)-ys(end-2,:)).*(zs(end,:)-zs(end-1,:))];
xs = xs+initoffset(1);
ys = ys+initoffset(2);
samptsraw = [xs(:),ys(:),zs(:)].';
samptsposd = bsxfun(@plus,Ropt*samptsraw,Topt);
xr = reshape(samptsposd(1,:),size(xs));
yr = reshape(samptsposd(2,:),size(ys));
zr = reshape(samptsposd(3,:),size(zs));
[samptsx0,samptsy0] = world2cam(xr(:),yr(:),zr(:),Rmir,Tmir,f,k1,cxcy,dxy);
samptsx = samptsx0-xyoffset(1);
samptsy = samptsy0-xyoffset(2);
samplin =
line('xdata',samptsx,'ydata',samptsy,'color','r','marker','+','linestyle','none','parent'
,axpic);
xc = reshape(samptsx,size(xs));
yc = reshape(samptsy,size(ys));
% get sample points on the two opposing straight edges
xcc = xc(2:(end-1),2:(end-1));
ycc = yc(2:(end-1),2:(end-1));
choices = {'long edges','short edges','fiducials'};
if isnumeric(shapename) % if surface is nominally flat
choice = listdlg('PromptString','Choose registering
option','SelectionMode','single','ListString',choices);
if isempty(choice)
247
choice = 1;
end
else % curved surface
choice = listdlg('PromptString','Choose registering
option','SelectionMode','single','ListString',choices([1,3]));
if isempty(choice)
choice = 1;
elseif choice == 2
choice = 3;
end
end
switch choice
case 1
linc = cat(3,[xcc(lind1),ycc(lind1)],[xcc(lind2),ycc(lind2)]);
case 2
lind1 = lind1a;
lind2 = lind2a;
lindist = lindista;
linc = cat(3,[xcc(lind1),ycc(lind1)],[xcc(lind2),ycc(lind2)]);
case 3
lindist = fidist;
set(impic,'cdata',fidpic)
set(samplin,'visible','off');
fidroi = imline(axpic,[50,50;100,50]);
fidpos = wait(fidroi);
lmask12 = zeros([size(nmask),2]);
for ij = 1:2
xfid = fidpos(ij,:).';
pfid = bsxfun(@plus,floor(xfid),[0,0,1,1;0,1,0,1]);
wfid = 1./sqrt(sum(bsxfun(@minus,pfid,xfid).^2,1)).'; % 1/(distance to 4
surrounding vertices)
wfid = wfid./sum(wfid);
for jk = 1:size(pfid,2)
lmask12(pfid(2,jk),pfid(1,jk),ij) = wfid(jk);
end
end
lmask1 = lmask12(:,:,1);
lmask2 = lmask12(:,:,2);
overlayflag = 2;
end
if choice==1 || choice==2
% get distances from aforementioned edges
dlin = zeros(numel(xbord),2);
for li = 1:2
X000 = linc(:,1,li) * ones(1,numel(xbord));
Y000 = linc(:,2,li) * ones(1,numel(ybord));
x000 = ones(size(linc,1),1) * xbord(:).';
y000 = ones(size(linc,1),1) * ybord(:).';
distsl = (x000-X000).^2+(y000-Y000).^2;
[Dl,rowind0l] = min(distsl,[],1);
248
rowind0l(rowind0l==1) = 2;
rowind0l(rowind0l==size(linc,1)) = size(linc,1)-1;
rowindl = [rowind0l-1;rowind0l;rowind0l+1];
colindl = repmat(1:numel(xbord),3,1);
indl = sub2ind(size(x000),rowindl,colindl);
Xl = X000(indl);
Yl = Y000(indl);
xl = repmat(xbord(:).',[2,1]);
yl = repmat(ybord(:).',[2,1]);
% projection
uXl = diff(Xl,1,1);
uYl = diff(Yl,1,1);
LAMBDAl = ((xl - Xl(1:2,:)) .* uXl + (yl - Yl(1:2,:)) .* uYl) ./ (uXl.^2 +
uYl.^2);
PXl = Xl(1:2,:) + LAMBDAl .* uXl;
PYl = Yl(1:2,:) + LAMBDAl .* uYl;
% distance to projections points which is inside a segment
PDl = NaN(size(xl));
bl = ((LAMBDAl > 0) & (LAMBDAl < 1));
PDl(bl) = sqrt((PXl(bl) - xl(bl)).^2 + (PYl(bl) - yl(bl)).^2);
% distance (min of distance to vertex or line segment)
dlin(:,li) = min([Dl; PDl],[],1).';
end
disthresh = 2; % threshold for distance from edge
lmask1 = false(size(nmask));
lmask2 = lmask1;
edgepx1 =
line('xdata',1,'ydata',1,'parent',axpic,'linestyle','none','marker','.','color','g');
edgepx2 =
line('xdata',1,'ydata',1,'parent',axpic,'linestyle','none','marker','.','color','c');
slid = uicontrol(f2,'style','slider','units','normal','position',[.05 .1 .04
.75],'min',0,'max',10,'value',disthresh,'callback',@threshadj);
slidtxt = uicontrol(f2,'style','text','units','normal','position',[.02 .9 .1
.02],'string',sprintf('Threshold\n%0.1f Pixels',disthresh));
threshadj(slid);
set([polyg,ptmark],'visible','off');
overlayflag = 2;
set(contbut,'visible','on','string','Finish');
uiwait(f2);
set([contbut,slid,slidtxt],'visible','off');
end
set(f2,'WindowButtonDownFcn',@toggleoverlay)
% save_to_base(1);
function editflat(~,~)
sntemp = zeros(1,2);
sntemp(1) = str2double(get(shapedit(1),'string'));
sntemp(2) = str2double(get(shapedit(2),'string'));
249
if isnan(sntemp(1))
sntemp(1) = get(shapedit(1),'userdata');
end
if isnan(sntemp(2))
sntemp(2) = get(shapedit(2),'userdata');
end
shapename = sntemp;
[x00,y00,z00,bordfcn] = DP_SLSurfacePoints(shapename,[10,5]);
x00 = x00+initoffset(1);
y00 = y00+initoffset(2);
xb = bordfcn(x00);
yb = bordfcn(y00);
zb = bordfcn(z00);
pt1 = [x00(pt1ind);y00(pt1ind);z00(pt1ind)];
pt2 = [x00(pt2ind);y00(pt2ind);z00(pt2ind)];
dz = pt2(3)-pt1(3);
dxysq = sum((pt2(1:2)-pt1(1:2)).^2);
pts2pos(campt1,campt2);
end
function threshadj(slid,~)
disthresh = get(slid,'value');
subs1 = [ybord(dlin(:,1)<=disthresh),xbord(dlin(:,1)<=disthresh)];
subs2 = [ybord(dlin(:,2)<=disthresh),xbord(dlin(:,2)<=disthresh)];
ind1 = sub2ind(size(nmask),subs1(:,1),subs1(:,2));
ind2 = sub2ind(size(nmask),subs2(:,1),subs2(:,2));
lmask1(:) = false;
lmask2(:) = false;
lmask1(ind1) = true;
lmask2(ind2) = true;
set(edgepx1,'xdata',subs1(:,2),'ydata',subs1(:,1));
set(edgepx2,'xdata',subs2(:,2),'ydata',subs2(:,1));
set(slidtxt,'string',sprintf('%0.1f Pixels',disthresh));
end
function getcp(fig,~,ax)
cp = get(ax,'currentpoint');
xcam10 = cp(1,1);
ycam10 = cp(1,2);
uiresume(fig);
end
function setpt2(~,~)
cp = get(axpic,'currentpoint');
xcam2 = cp(1,1)+xyoffset(1);
ycam2 = cp(1,2)+xyoffset(2);
campt2 = [xcam2,ycam2];
pts2pos(campt1,campt2);
end
250
function [Rpts,Tpts,s1,s2] = pts2pos(campt1,campt2)
xcam = [campt1(1);campt2(1)];
ycam = [campt1(2);campt2(2)];
[sxc,syc,szc] = cam2ray(xcam,ycam,f,k1,cxcy,dxy);
s120 = [sxc,syc,szc].';
s12 = Rmir.'*(s120);
s12 = bsxfun(@rdivide,s12,s12(3,:)); % z component normalized to +1
s1 = s12(:,1);
s2 = s12(:,2);
mxy = (s2(1:2)-s1(1:2))./s1(3); % s1(3) = s2(3) ( = 1 )
cxy = (s2(1:2).*(dz-o(3))+s1(1:2).*o(3))./s1(3); % s1(3) = s2(3) ( = 1 )
aq = sum(mxy.^2);
bq = 2.*sum(mxy.*cxy);
cq = sum(cxy.^2)-dxysq;
zsolve1 = (-bq+sqrt(bq^2-4*aq*cq))/(2*aq);
xsolve1 = (zsolve1-o(3))/s1(3)*s1(1)+o(1);
ysolve1 = (zsolve1-o(3))/s1(3)*s1(2)+o(2);
ptsol1 = [xsolve1;ysolve1;zsolve1];
zsolve2 = zsolve1+dz;
xsolve2 = (zsolve2-o(3))/s2(3)*s2(1)+o(1);
ysolve2 = (zsolve2-o(3))/s2(3)*s2(2)+o(2);
ptsol2 = [xsolve2;ysolve2;zsolve2];
cosang = sum((pt2(1:2)-pt1(1:2)).*(ptsol2(1:2)-ptsol1(1:2)))/dxysq;
crossprod = cross([pt2(1:2)-pt1(1:2);0],[ptsol2(1:2)-ptsol1(1:2);0]);
sinang = sign(crossprod(3)).*norm(crossprod)/dxysq;
Rpts = [cosang -sinang 0;...
sinang cosang 0;...
0 0 1];
Tpts = ptsol1-pt1;
drawpoly(Rpts,Tpts,s1,s2);
end
function drawpoly(Rpts,Tpts,varargin)
pts1 = bsxfun(@plus,Rpts*([xb,yb,zb].'),Tpts);
[xbcam0,ybcam0] =
world2cam(pts1(1,:).',pts1(2,:).',pts1(3,:).',Rmir,Tmir,f,k1,cxcy,dxy);
xbcam = xbcam0-xyoffset(1);
ybcam = ybcam0-xyoffset(2);
set(polyg,'xdata',xbcam,'ydata',ybcam);
set(ptmark,'xdata',xbcam([pt1ind,pt2ind]),'ydata',ybcam([pt1ind,pt2ind]));
if nargin>2
s1 = varargin{1};
s2 = varargin{2};
s1t = s1.*abs(o(3));
s2t = s2.*abs(o(3));
set(borderline,'xdata',pts1(1,:).','ydata',pts1(2,:).','zdata',pts1(3,:).');
set(l1,'xdata',o(1)+[0;s1t(1)],'ydata',o(2)+[0;s1t(2)],'zdata',o(3)+[0;s1t(3)]);
set(l2,'xdata',o(1)+[0;s2t(1)],'ydata',o(2)+[0;s2t(2)],'zdata',o(3)+[0;s2t(3)]);
251
end
drawnow expose;
end
function selpt(~,~)
set(f2,'WindowButtonMotionFcn',@pointerswitch,'WindowButtonDownFcn',[]);
axes(axpic);
set(f2,'name','Adjust Control Points');
end
function pointerswitch(~,~)
cp = get(axpic,'currentpoint');
cp = cp(1,1:2);
if sqrt(sum((cp-(campt1-xyoffset)).^2)) < 10
set(f2,'pointer','fleur','WindowButtonDownFcn',@clickpt1);
elseif sqrt(sum((cp-(campt2-xyoffset)).^2)) < 10
set(f2,'pointer','fleur','WindowButtonDownFcn',@clickpt2);
else
set(f2,'pointer','arrow','WindowButtonDownFcn',[]);
end
end
function clickpt1(~,~)
cp = get(axpic,'currentpoint');
strtpt1 = cp(1,1:2);
set(f2,'WindowButtonMotionFcn',{@dragpt1,strtpt1,campt1},'WindowButtonUpFcn',@releasept);
end
function dragpt1(~,~,strtpt,campt0)
cp = get(axpic,'currentpoint');
movec = cp(1,1:2)-strtpt;
campt1 = campt0+movec;
[Rpts,Tpts,s1,s2] = pts2pos(campt1,campt2);
mertit = edgemert([0,0,atan2(Rpts(2),Rpts(1)),Tpts(:).']);
set(f2,'name',num2str(mertit));
end
function clickpt2(~,~)
cp = get(axpic,'currentpoint');
strtpt = cp(1,1:2);
set(f2,'WindowButtonMotionFcn',{@dragpt2,strtpt,campt2},'WindowButtonUpFcn',@releasept);
end
function dragpt2(~,~,strtpt,campt0)
cp = get(axpic,'currentpoint');
movec = cp(1,1:2)-strtpt;
campt2 = campt0+movec;
[Rpts,Tpts] = pts2pos(campt1,campt2);
252
mertit = edgemert([0,0,atan2(Rpts(2),Rpts(1)),Tpts(:).']);
set(f2,'name',num2str(mertit));
end
function releasept(~,~)
set(f2,'WindowButtonMotionFcn',@pointerswitch,'WindowButtonUpFcn',[]);
end
function cont(~,~)
set(f2,'WindowButtonMotionFcn',[],'WindowButtonDownFcn',[],'WindowButtonUpFcn',[]);
uiresume(f2);
end
function [mert,R,T,xbcam,ybcam] = edgemert(rpyt)
% extract R and T transformation matricies
roll = rpyt(1);
pitch = rpyt(2);
yaw = rpyt(3);
R = [cos(yaw)*cos(pitch), cos(yaw)*sin(pitch)*sin(roll)-sin(yaw)*cos(roll),
cos(yaw)*sin(pitch)*cos(roll)+sin(yaw)*sin(roll);...
sin(yaw)*cos(pitch), sin(yaw)*sin(pitch)*sin(roll)+cos(yaw)*cos(roll),
sin(yaw)*sin(pitch)*cos(roll)-cos(yaw)*sin(roll);...
-sin(pitch) , cos(pitch)*sin(roll) ,
cos(pitch)*cos(roll) ];
T = rpyt(4:6);
T = T(:);
% find part border in camera frame
pts1 = bsxfun(@plus,R*([xb(1:(end-1)),yb(1:(end-1)),zb(1:(end-1))].'),T);
[xbcam0,ybcam0] =
world2cam(pts1(1,:).',pts1(2,:).',pts1(3,:).',Rmir,Tmir,f,k1,cxcy,dxy);
xbcam = xbcam0-xyoffset(1);
ybcam = ybcam0-xyoffset(2);
% calculate merit function value
X00 = xbcam(:) * ones(1,numel(xbord));
Y00 = ybcam(:) * ones(1,numel(ybord));
x00 = ones(numel(xbcam),1) * xbord(:).';
y00 = ones(numel(ybcam),1) * ybord(:).';
dists = (x00-X00).^2+(y00-Y00).^2;
[D,rowind] = min(dists,[],1);
rowind = [rowind-1;rowind;rowind+1];
rowind(rowind<1) = numel(xbcam);
rowind(rowind>numel(xbcam)) = 1;
colind = repmat(1:numel(xbord),3,1);
ind = sub2ind(size(x00),rowind,colind);
X = X00(ind);
Y = Y00(ind);
x = repmat(xbord(:).',[2,1]);
y = repmat(ybord(:).',[2,1]);
253
% projection
uX = diff(X,1,1);
uY = diff(Y,1,1);
LAMBDA = ((x - X(1:2,:)) .* uX + (y - Y(1:2,:)) .* uY) ./ (uX.^2 + uY.^2);
PX = X(1:2,:) + LAMBDA .* uX;
PY = Y(1:2,:) + LAMBDA .* uY;
% distance to projections points which is inside a segment
PD = NaN(size(x));
b = ((LAMBDA > 0) & (LAMBDA < 1));
PD(b) = sqrt((PX(b) - x(b)).^2 + (PY(b) - y(b)).^2);
% distance
d = min([D; PD]);
% weight distance higher if the point is outside the polygon (to push all points
into polygon area)
b = inpolygon(xbord, ybord, xbcam, ybcam);
d(~b) = 20.*d(~b);
mert = sqrt(sum(d.^2));
end
function [mert,R,T,xbcam,ybcam] = posmert(rpyt)
roll = rpyt(1);
pitch = rpyt(2);
yaw = rpyt(3);
R = [cos(yaw)*cos(pitch), cos(yaw)*sin(pitch)*sin(roll)-sin(yaw)*cos(roll),
cos(yaw)*sin(pitch)*cos(roll)+sin(yaw)*sin(roll);...
sin(yaw)*cos(pitch), sin(yaw)*sin(pitch)*sin(roll)+cos(yaw)*cos(roll),
sin(yaw)*sin(pitch)*cos(roll)-cos(yaw)*sin(roll);...
-sin(pitch) , cos(pitch)*sin(roll) ,
cos(pitch)*cos(roll) ];
T = rpyt(4:6);
T = T(:);
pts1 = bsxfun(@plus,R*([xb,yb,zb].'),T);
[xbcam0,ybcam0] =
world2cam(pts1(1,:).',pts1(2,:).',pts1(3,:).',Rmir,Tmir,f,k1,cxcy,dxy);
xbcam = xbcam0-xyoffset(1);
ybcam = ybcam0-xyoffset(2);
polymask = inpolygon(xlist,ylist,xbcam,ybcam);
ondif = nnz(~polymask & nmask);
offs = nnz(polymask & ~nmask);
% figure(4); imagesc(~polymask & nmask); axis image; title(int2str(ondif));
% figure(5); imagesc(polymask & ~nmask); axis image; title(int2str(offs));
% figure(6); imagesc(nmask); axis image; title('nmask');
% figure(7); imagesc(polymask); axis image; title('polymask');
mert = 5*ondif + 1*offs;
254
% drawpoly(R,T);
end
function [mert,R,T] = posmertsca(rpytsca,rpytoffset,rpytbnd) % posmert wrapper
rpyt = rpytsca.*diff(rpytbnd,1,1)./2+rpytoffset;
[mert,R,T] = posmert(rpyt);
end
function [mert,R,T] = posmert2stage(rpyt) % posmert wrapper
% [~,~,~,polyx,polyy] = posmert(rpyt);
% if abs(polyarea(polyx,polyy)/nnz(nmask)-1) > 0.05
% mert = 5*nnz(nmask);
% R = 0;
% T = 0;
% return;
% end
t0 = rpyt(4:6);
optionst = optimset('TolX',1e-
2,'PlotFcns',@optimplotfval,'UseParallel','always');%,'MaxIter',30);
topt = fminsearch(@(t) posmert([rpyt(1:3),t]),t0,optionst);
[mert,R,T] = posmert([rpyt(1:3),topt]);
drawpoly(R,T);
end
function toggleoverlay(~,~)
if overlayflag == 1
overlayflag = 2;
set(polyg,'visible','off');
set(samplin,'visible','on');
else
overlayflag = 1;
set(polyg,'visible','on');
set(samplin,'visible','off');
end
end
end
function [sx,sy,sz] = cam2ray(Xf,Yf,f,k1,cxcy,dxy)
Xd = (Xf-cxcy(1)).*dxy(1);
Yd = (Yf-cxcy(2)).*dxy(2);
rsq = Xd.^2+Yd.^2;
sx0 = Xd.*(1+k1.*rsq);
sy0 = Yd.*(1+k1.*rsq);
sz0 = f.*ones(size(sx0));
len = sqrt(sx0.^2+sy0.^2+sz0.^2);
sx = sx0./len;
sy = sy0./len;
sz = sz0./len;
end
255
function [Xw2c,Yw2c,xyzw2c] = world2cam(xw,yw,zw,R,T,f,k1,Cxy,dxy)
% INPUT:
% xw,yw,zw are world coordinates (zw(:) = 0 for planar coordinate points)
% R is 3x3 rotation matrix (world to camera)
% T is three element translation vector [Tx;Ty;Tz] (world to camera)
% f is lens focal length
% k1 is r^2 coefficient of distortion
% Cxy is two element vector [x,y] of pixel position of optical center in computer frame
memory
% dxy is two element vector [x,y] of pixel pitch (units of length)
% OUTPUT:
% Xw2c is an array of X pixel coordinates on camera sensor of real world points, the same
size as xw input
% Yw2c is an array of Y pixel coordinates on camera sensor of real world points, the same
size as xw input
% xyzw2c is an array of [x1,y1,z1;x2,y2,z2;...] 3D camera coordinates of world points
camcoordsw2c = R*[xw(:).'; yw(:).'; zw(:).'] + repmat(T(:),1,numel(xw));
xyzw2c = camcoordsw2c.';
xw2c = reshape(camcoordsw2c(1,:),size(xw));
yw2c = reshape(camcoordsw2c(2,:),size(xw));
zw2c = reshape(camcoordsw2c(3,:),size(xw));
Xdw2c0 = f.*xw2c./zw2c;
Ydw2c0 = f.*yw2c./zw2c;
rsqw2c = Xdw2c0.^2 + Ydw2c0.^2;
Xdw2c = Xdw2c0./(1+k1.*rsqw2c);
Ydw2c = Ydw2c0./(1+k1.*rsqw2c);
Xw2c = dxy(1)^(-1).*Xdw2c + Cxy(1);
Yw2c = dxy(2)^(-1).*Ydw2c + Cxy(2);
end
Dependency: DP_SLSurfacePoints.m
Generates sample points based on the ideal surface shape for comparison to
reconstructed data.
function [x,y,z,justborder,lindist,lind1,lind2,lindista,lind1a,lind2a] =
DP_SLSurfacePoints(shapename,samples)
% function [x,y,z,justborder] = SL_Roch5_Mini_SurfacePoints(samples)
%
% INPUT:
% samples = size of sample grid along x (direction of curvature) and y (direction of
extrusion)
% e.g. samples = [10,2] gives 10 samples along the curve and just the 2 end caps in the
extrusion direction
%
% OUTPUT:
% x,y,z = gridded x, y, and z data
% justborder = anonymous function to extract border data from x, y, or z ( x_border =
justborder(x) )
256
% lindist = distance between opposing straight edges
% lind1 and lind2 = vectors of indicies of sample points along the two opposing straight
edges
shapedata = reflectorshapedatabase(shapename);
shape = shapedata.shape;
xbnd = shapedata.xbnd;
length = shapedata.length; % extruded length of part
tilt = shapedata.tilt; % degrees
thik = shapedata.thik; % perpendicular distance from xbnd(1) point on curve to plane
describing the rear face of the part
if tilt~=0
m = tand(90+tilt); % slope of x sample lines
ybnd = polyval(shape,xbnd);
bbnd = ybnd-m.*xbnd;
b = linspace(bbnd(1),bbnd(2),samples(1)).';
lindist = sqrt(diff(xbnd).^2+diff(ybnd).^2);
x0 = zeros(size(b));
for ij = 1:samples(1)
xraw = roots([shape(1:6),shape(7)-m,shape(8)-b(ij)]);
xraw = xraw(imag(xraw)==0);
x0(ij) = xraw(find(real(xraw)>=min(xbnd)-0.000001 &
real(xraw)<=max(xbnd)+0.000001,1));
end
x0 = real(x0);
else
lindist = abs(diff(xbnd));
x0 = linspace(xbnd(1),xbnd(2),samples(1)).';
end
y0 = polyval(shape,x0);
% % find principle curvatures at each sample point
% fx = polyval(polyder(shape),x0);
% fxx = polyval(polyder(polyder(shape)),x0);
% fy = 0;
% fyy = 0;
% fxy = 0;
% K = (fxx.*fyy-fxy.^2)./(1+fx.^2+fy.^2).^2; % gaussian curvature
% H = ((1+fx.^2).*fyy+(1+fy.^2).*fxx-2.*fx.*fy.*fxy)./(2.*(1+fx.^2+fy.^2).^(3/2)); % mean
curvature
% kern = H.^2-K;
% C1 = H+sqrt(kern); % principal curvature 1
% C2 = H-sqrt(kern); % principal curvature 2
R = [cosd(-tilt),sind(-tilt);-sind(-tilt),cosd(-tilt)];
xzrot = [x0,y0]*R;
x = xzrot(:,1);
x = x-max(x);
x = repmat(x,1,samples(2));
257
z = -xzrot(:,2);
z = z-z(1)-thik;
z = repmat(z,1,samples(2));
y = repmat(linspace(0,length,samples(2)),samples(1),1);
x = x.';
y = y.';
z = z.';
lind1 = find(x==min(x(:)));
lind2 = find(x==max(x(:)));
lindista = length;
lind1a = find(y==min(y(:)));
lind2a = find(y==max(y(:)));
justborder = @(x) [x(1:1:end-1,1);x(end,1:1:end-1).';x(end:-1:2,end);x(1,end:-1:1).'];
% surf(x,y,z,'facecolor','b','facealpha',0.3,'edgecolor','none');
% axis equal;
% set(gca,'ydir','reverse','zdir','reverse');
%
line('xdata',justborder(x),'ydata',justborder(y),'zdata',justborder(z),'color','b','linew
idth',2);
end
Dependency: pptfig.m
Initiates graphical user interfaces figure windows.
function fhan = pptfig(fname,fignum,varargin)
% fname is the figure (base) name
% fignum is the figure number, determines figure screen position
% varargin is optional subtitle to figure name
% size is chosen to fit on a standard 4:3 powerpoint slide without resizing
ss = get(0,'ScreenSize');
fpos = [10+40*(fignum-1),60+10*(fignum-1),960,720];
fogm = findobj('-regexp','Name',fname,'type','figure');
if isempty(fogm);
fhan = figure(); % create figure
else
figure(fogm(1));
fhan = clf('reset'); % clear previous figure
end
set(fhan,'Position',fpos,'color','w','units','pixels','numbertitle','off');
if nargin<3
set(fhan,'Name',fname);
258
else
set(fhan,'Name',[fname,': ',varargin{1}]);
end
fs = get(fhan,'outerposition');
set(fhan,'outerposition',[1+40*(fignum-1), ss(4)-fs(4)-30*(fignum-1), fs(3),
fs(4)],'resize','on');
end
Dependency: targetcoorddatabase.m
Contains a callable database to reference object fiducial coordinates, most notably for
the deflectometer’s reference flat mirror.
function target = targetcoorddatabase(targetname)
switch targetname
case 'paper'
% find coords from distances
ptxi = zeros([4,4]);
ptyi = ptxi;
ptxi(5) = 1.429;
ptxi(9) = 2.953;
ptxi(13) = 4.444;
d1 = [1.324 1.949 3.242 4.610;... % linear distance from point "1"
2.554 2.928 3.911 5.094;...
3.562 3.859 4.665 5.676];
d13 = [4.650 3.295 1.987 1.312;... % linear distance from point "13"
5.128 3.945 2.948 2.559;...
5.693 4.671 3.880 3.612];
thet = acos((ptxi(13)^2 + d1.^2 - d13.^2)./(2.*ptxi(13).*d1));
ptxi(2:end,:) = d1.*cos(thet);
ptyi(2:end,:) = -d1.*sin(thet);
% figure(2);
% plot(ptxi(:),ptyi(:),'+');
% axis equal;
target.ptx = ptxi.*25.4; % convert to mm
target.pty = ptyi.*25.4; % convert to mm
target.names = {'1' '5' '9' '13';...
'2' '6' '10' '14';...
'3' '7' '11' '15';...
'4' '8' '12' '16'};
259
case 'test'
ptx0 = linspace(0,100,3);
pty0 = linspace(0,-100,3);
[ptx1,pty1] = meshgrid(ptx0,pty0);
target.ptx = ptx1;
target.pty = pty1;
target.names = cell(size(ptx1));
for ni = 1:numel(target.names);
target.names{ni} = int2str(ni);
end
case 'phonedots'
target.ptx = [0,50.052,100.104;0,50.052,100.104;0,50.052,100.104;];
target.pty = [0,0,0;-50.052,-50.052,-50.052;-100.104,-100.104,-100.104;];
target.names = {'Top Left', 'Top Center', 'Top Right'; 'Middle Left', 'Center',
'Middle Right'; 'Bottom Left', 'Bottom Center', 'Bottom Right'};
case 'mirror'
% from MirrorDotDataInterpreter.m
target.ptx = [3.5469 43.4622 83.7309;...
3.9823 43.9391 84.1066;...
4.2849 44.3064 84.5811];
target.pty = [4.2152 3.6317 3.0414;...
38.7358 38.2271 37.8273;...
73.4263 73.0113 72.7092];
target.names = {'Top Left', 'Top Center', 'Top Right';...
'Middle Left', 'Center', 'Middle Right';...
'Bottom Left', 'Bottom Center', 'Bottom Right'};
otherwise
disp('Target name not found in database');
target.ptx = 0;
target.pty = 0;
target.names = {'error'};
end
Dependency: camerasensordatabase.m
Contains callable database for sensor specifications from various cameras, most notably
the ‘Marlin’ camera used in the final deflectometer apparatus.
function sensor = camerasensordatabase(camname)
sensor = struct('dx',0,'Ncx',0,'dy',0);
switch camname
case 'RazrMaxx'
sensor.dx = 1.35E-3; % x direction pixel pitch in mm
sensor.Ncx = 3264; % number of pixels in x direction on camera sensor
260
sensor.dy = 1.35E-3; % y direction pixel pitch in mm
case 'NikonD90'
sensor.dx = 5.50E-3; % x direction pixel pitch in mm
sensor.Ncx = 4288; % number of pixels in x direction on camera sensor
sensor.dy = 5.55E-3; % y direction pixel pitch in mm
case 'Marlin'
sensor.dx = 4.4E-3; % x direction pixel pitch in mm
sensor.Ncx = 1628; % number of pixels in x direction on camera sensor
sensor.dy = 4.4E-3; % y direction pixel pitch in mm
case 'Webcam'
% pixel spacings are just guesses
sensor.dx = 5.50E-3; % x direction pixel pitch in mm
sensor.Ncx = 640; % number of pixels in x direction on camera sensor
sensor.dy = 5.55E-3; % y direction pixel pitch in mm
end
261
Appendix C. Optimization Routine MATLAB Code
This appendix contains the final versions of the code used to optimize the presented
designs. All novel dependencies are included and all other functions are either included in
MATLAB 2012a or are publically available on the MATLAB Central File Exchange website.
Suspended Louver Optimizer
Optimization routine for the suspended louver design.
% function [optx,mert,solutions,optin] = SL_SingleSegment_Optimizer_PatternSearch()
%Optimization of single segment suspended louver using PatternSearch
% clear all;
close all;
global bestmerit bestvangseffs bestx0
d = 2; % optics periodicity
n = 1.49; % refractive index of material
Rmirror = 0.95; % reflectivity of mirrored surfaces
glen = 300; % guide length (mm)
gthik = 13; % guide thickness (mm)
vangmin = 0;
vangmax = 89;
vangnum = 300;
[lat,hitemps,lotemps] = LocationWeatherDatabase('Rochester'); % retrieve location and
weather information
vangs = linspace(vangmin,vangmax,vangnum); % vertical angles
vangwts = VerticalAngleWeightCalculator(vangs,lat,hitemps,lotemps); % vertical angle
weighting function
h = 0.7658; % injection feature size
endptx = -2.22; % LHS endpoint of reflector [x,y]
shape = [9.4971e-05,0.00022229,0.00147395,-0.00083297,0.0053727,0.193836,0.51152,-
0.57171]; % polynomial coefficients describing reflector shape
x0 = [h,endptx,shape]; % initial optimization point
bestmerit = 0;
bestvangseffs = [vangs(:),zeros(size(vangs(:)))];
bestx0 = x0;
ubnds = [0.5, -1, 0.001, 0.001, 0.01, 0.01, 0.02, 0.5, 1, 0];
lbnds = [0.1, -6,-0.001,-0.001,-0.01,-0.01,-0.01,-0.2, 0, -d];
262
rbnds = ubnds-lbnds; % range of raw bounds
x0sca = (x0-lbnds)./rbnds;
lbndsca = zeros(size(lbnds));
ubndsca = ones(size(ubnds));
psoptdef = psoptimset(@patternsearch);
psoptions =
psoptimset(psoptdef,'CompletePoll','on','UseParallel','always','InitialMeshSize',0.2,'Plo
tFcns',{@psplotbestf,@psplotbestx},'Display','iter',...
'TolMesh',1e-3,'MaxIter',100*numel(x0),'MaxFunEvals',2000*numel(x0));
problem =
createOptimProblem('fmincon','x0',x0sca,'lb',lbndsca,'ub',ubndsca,'options',psoptions,...
'objective',
@(x0sca)SL_SingleSegment_MeritFunction(d,x0sca(1).*rbnds(1)+lbnds(1),x0sca(2).*rbnds(2)+l
bnds(2),x0sca(3:end).*rbnds(3:end)+lbnds(3:end),n,Rmirror,glen,gthik,vangs,vangwts,0));
problem.solver = 'patternsearch';
tic;
[optxsca,fval,exitflag,output] = patternsearch(problem);
optx = optxsca.*rbnds+lbnds;
clear bestmerit bestvangseffs bestx0
% try
% txtmsg = sprintf('Runtime of %3.2f hours', toc/3600);
% send_text_message('402-416-8963','Verizon','Optimization Complete',txtmsg);
% catch txtmsgerr
% disp('Text message error...');
% end
%%
optin = {d,optx(1),optx(2),optx(3:end),n,Rmirror,glen,gthik,vangs,vangwts,1};
[merit,effs,injpos] = SL_SingleSegment_MeritFunction(optin{1}, optin{2}, optin{3},
optin{4}, optin{5}, optin{6}, optin{7}, optin{8}, optin{9}, optin{10}, optin{11});
figure();
coeff = (1-numel(shape)):1:0;
hold on;
plot(coeff,optx(3:end),'marker','.','color','r','linewidth',2);
plot(coeff,lbnds(3:end),'-k');
plot(coeff,ubnds(3:end),'-k');
hold off;
title('eff vs. coeffs');
coeffstr = cell(1,numel(coeff));
for jk = 1:numel(coeff)
coeffstr{jk} = ['x^' num2str(abs(coeff(jk)))];
end
set(gca,'XTick',coeff,'XTickLabel',coeffstr);
grid on;
263
% output cell to paste to Excel
outcel = cell(10,max(numel(x0)+1,9));
outcel(1,1) = {mfilename('fullpath')};
outcel(2,2:4) = [{'h'},{'x0'},{'shape...'}];
outcel(3:6,1) = [{'initialx'};{'optx'};{'ubnds'};{'lbnds'}];
outcel(8,1:9) =
[{'d'},{'n'},{'Rmirror'},{'glen'},{'gthik'},{'vangmin'},{'vangmax'},{'vangnum'},{'lat'}];
outcel(3,2:numel(x0)+1) = num2cell(x0);
outcel(4,2:numel(x0)+1) = num2cell(optx);
outcel(5,2:numel(x0)+1) = num2cell(ubnds);
outcel(6,2:numel(x0)+1) = num2cell(lbnds);
outcel(9,1:9) = [{d},{n},{Rmirror},{glen},{gthik},{vangmin},{vangmax},{vangnum},{lat}];
outcel(10,1) = {'Notes:'};
outcel(10,2) = {'Patternsearch options: CompletePoll on, InitialMeshSize 0.2, scaled all
bounds to be between 0 and 1'};
outcel(12,1:3) = [{'vangs'},{'effs'},{'merit'}];
outcel(13:13+vangnum-1,1:2) = num2cell([vangs(:),effs(:)]);
outcel(13,3) = num2cell(merit);
%%
BuildLT = questdlg('Would you like to build this reflector in LightTools?',...
'Build in LT?','Yes','No','No');
if strcmp(BuildLT,'Yes')
SL_SingleSegment_BuildLT(injpos,optx(3:end),optx(2),d,Rmirror,1);
end
%%
% end
Suspended Louver Merit Function
Merit function evaluated for all parameters passed from the optimization routine.
function [merit,effs,injpos] =
SL_SingleSegment_MeritFunction(d,h,x0,shape,n,Rmirror,glen,gthik,vangs,vangwts,plotyn)
% %input arguments
% d = 2.6; % optics periodicity
% h = 0.78; % injection feature size
% endpt = [-4.8 -2]; % LHS endpoint of reflector [x,y]
% shape = [0.0855 0.5623 -1.2713]; % polynomial coefficients describing reflector shape
% n = 1.49;
% Rmirror = 0.95; % reflectivity of mirrored surfaces
% glen = 300;
% gthik = 13;
% plotyn = 1;
% vangs = linspace(0,89,300);
% vangwts = VerticalAngleWeightCalculator(vangs,43.12);
264
global bestmerit bestvangseffs bestx0
global bestinjpos bestrefl
global topax topplot1 topplot2 topplot3 topplot4 topplot5 topplot6
global botax botplot
firstcall = 0;
if sum(bestvangseffs(:,2))==0
firstcall = 1;
end
%%%%%%%%%start of function code
evalpts = 100;
R = 1-h/d;
critang = asind(1/n);
y0 = polyval(shape,x0);
% calculate RHS endpoint components
x1 = 0;
y1 = shape(end);
% calculate injection feature shape
injpos = zeros(4,2);
minj = (sqrt((n^2-1).*((0-x0).^2+(0-y0).^2))-0+x0)./(0-y0-sqrt((0-x0).^2+(0-y0).^2)); %
slope of injection surface to inject ray from endpt to (0,0) at guide critical angle
mcrit = tand(critang);
injpos(2,1) = 2.*h./(minj-mcrit);
injpos(2,2) = minj.*injpos(2,1);
injpos(3,1) = -h./mcrit;
injpos(3:4,2) = h;
if injpos(2,2)>h
injpos(2:3,1) = h./minj;
injpos(2:3,2) = h;
end
if polyval(shape, injpos(3,1)) < (injpos(3,2)-d)
shapeshft = shape;
shapeshft(end) = shapeshft(end)+d-h;
solsinj = roots(shapeshft);
solsinj = round(solsinj.*1e10)./1e10;
solsinj = solsinj( (solsinj<=x1) & (solsinj>=injpos(3,1)) & (imag(solsinj)==0) );
if any(solsinj)
injpos(3,1) = max(solsinj);
injpos(2,1) = (mcrit.*injpos(3,1)-injpos(3,2))./(mcrit-minj);
injpos(2,2) = minj.*injpos(2,1);
end
end
xs = linspace(x0,x1,20);
if firstcall
bestinjpos = injpos;
bestrefl = [xs(:),polyval(shape,xs(:))];
figure(10);
set(gcf,'position',[1049,107,565,806]);
265
topax = subplot(2,1,1);
topplot4 = plot([bestinjpos(:,1);bestinjpos(:,1)],[bestinjpos(:,2)-
d;bestinjpos(:,2)],'-','LineWidth',2,'color',[.8 .8 .8]);
axis equal;
hold on;
topplot5 = plot(bestrefl(:,1),bestrefl(:,2),'-','LineWidth',2,'color',[.8 .8 .8]);
topplot6 = plot(bestrefl(:,1),bestrefl(:,2)+d,'-','LineWidth',2,'color',[.8 .8 .8]);
topplot1 = plot([injpos(:,1);injpos(:,1)],[injpos(:,2)-d;injpos(:,2)],'-
k','LineWidth',2);
topplot2 = plot(xs,polyval(shape,xs),'-r','LineWidth',2);
topplot3 = plot(xs,polyval(shape,xs)+d,'-r','LineWidth',2);
hold off;
else
set(topplot1,'XData',[injpos(:,1);injpos(:,1)],'YData',[injpos(:,2)-d;injpos(:,2)]);
set(topplot2,'XData',xs,'YData',polyval(shape,xs));
set(topplot3,'XData',xs,'YData',polyval(shape,xs)+d);
end
inputs = {d,h,x0,shape,n,Rmirror,glen,gthik,vangs,vangwts,plotyn};
savb(inputs);
% find weights for each incidence angle
aplo = y0;
aphi = min(-tand(vangs).*(x0-x1)+y1, y0+d);
aphi = min(-tand(vangs).*(x0-injpos(2,1))+injpos(2,2), aphi); % so rays don't pass
through the injector on the way to the reflector
wts = max((aphi-aplo)./d, 0);
wtsl = logical(wts); % for logical indexing of non-zero weight incidence angles
wtsmat0 = repmat(wts(wtsl), evalpts, 1)./evalpts;
angsmat = repmat(vangs(wtsl), evalpts, 1);
slpsmat = -tand(angsmat);
% find start point of rays by equally spreading rays across applicable part of the input
aperture for each incidence angle
rayiny = zeros(size(slpsmat));
aphiap = aphi(wtsl);
for ij = 1:size(slpsmat,2)
rayiny(:,ij) = linspace(aplo,aphiap(ij),evalpts);
end
% find where incoming rays intersect segment
segxint = zeros(size(slpsmat));
nosol = segxint;
for jk = 1:numel(slpsmat)
polyadj = zeros(size(shape));
polyadj(end-1:end) = [slpsmat(jk),rayiny(jk)-slpsmat(jk).*x0];
sols = roots(shape-polyadj);
sols = round(sols.*1e10)./1e10;
solsa = sols( (sols<=x1) & (sols>=x0) & (imag(sols)==0) );
if any(solsa)
segxint(jk) = min(solsa);
266
else
nosol(jk) = 1;
end
polyadj2 = polyadj;
polyadj2(end) = polyadj2(end)-d;
sols2 = roots(shape-polyadj2);
sols2 = round(sols2.*1e10)./1e10;
solsa2 = sols2( (sols2<=x1) & (sols2>=x0) & (imag(sols2)==0) );
if any(solsa2)
nosol(jk) = 1;
end
end
segyint = polyval(shape,segxint);
% find slopes/normals of surface where rays strike it
surfslps = polyval(polyder(shape),segxint);
% find directions of reflected rays
rdirvec = refl([ones(size(slpsmat(:))),slpsmat(:)],[-
surfslps(:),ones(size(surfslps(:)))]);
rdirvecx = reshape(rdirvec(:,1),size(slpsmat)); %reflected ray direction unit vectors, x
component
rdirvecy = reshape(rdirvec(:,2),size(slpsmat)); %reflected ray direction unit vectors, y
component
rslpsmat = rdirvecy./rdirvecx;
wtsmat1 = wtsmat0.*Rmirror;
wtsmat1(logical(nosol)) = 0; % zero weights for rays with no reflector intersection
% find rays that intersect with aim region line segment
aimxint = (rslpsmat.*segxint - segyint) ./ (rslpsmat-minj);
aimyint = minj.*(aimxint);
hitinj = find( (aimxint>=injpos(2,1)) & (aimxint<=0) & ~nosol );
if isempty(hitinj)
effs = zeros(size(vangs));
merit = 0;
return
end
wtsmat2 = wtsmat1;
wtsmat2(setdiff(1:numel(wtsmat2),hitinj)) = 0;
% exclude rays that do not successfully inject into the guide
[rrdirvec,aveT] = refractfres([rdirvecx(hitinj),rdirvecy(hitinj)],[-minj,1],1,n);
wtsmat2(hitinj) = wtsmat2(hitinj).*aveT;
rrslps = rrdirvec(:,2)./rrdirvec(:,1);
cutyint = -rrslps.*aimxint(hitinj) + aimyint(hitinj); % y intercept of rays at guide
surface
ibakxint = (h+rrslps.*aimxint(hitinj)-aimyint(hitinj))./rrslps; % x intercept of rays at
injector back reflective surface
hitinjgid = find( (cutyint>=0) & (cutyint<=2*h) & (ibakxint>=injpos(3,1)) );
if isempty(hitinjgid)
effs = zeros(size(vangs));
267
merit = 0;
return
end
hitinjgiddn = find( (cutyint>h) & (cutyint<=2*h) );
hitind = hitinj(hitinjgid);
hitinddn = hitinj(hitinjgiddn);
wtsmat3 = wtsmat2;
wtsmat3(setdiff(1:numel(wtsmat3),hitind)) = 0;
wtsmat3(hitinddn) = wtsmat3(hitinddn).*Rmirror;
% guide ray tracing
gstrt0 = cutyint; % starting ray positions in guide
gstrt0(hitinjgiddn) = gstrt0(hitinjgiddn)-h; % shift "down rays" to center on origin,
unflipped for calculations
gstrt = gstrt0(hitinjgid)-h/2; % shift center of injector to origin and ignore rays
missing injection feature
gdist = h/2:d:(glen-h/2); % guide sample points (distance from the top edge of the guide)
gdist = gdist + (glen-gdist(end)+h/2)./2; % shift injector positions so they are
symmetric about the center of the guide
loledist = 2.*rrdirvec(hitinjgid+size(rrdirvec,1)).*gthik./rrdirvec(hitinjgid); %
distance rays travel without interacting with lossy guide surface
gideffs = zeros(numel(gstrt),numel(gdist));
for gi = 1:numel(gdist)
dup = gdist(gi); % distance to guide top
gideffs(:,gi) = R.^(floor((dup-gstrt)./loledist));
end
wtsmat4 = wtsmat3;
wtsmat4(hitind) = wtsmat4(hitind).*mean(gideffs,2);
effs = zeros(size(vangs));
effs(wtsl) = sum(wtsmat4,1);
merit = -sum(effs.*vangwts);
bestflag = 0;
if merit < bestmerit
bestmerit = merit;
bestvangseffs = [vangs(:),effs(:)];
bestx0 = [h,x0,shape];
bestflag = 1;
end
if firstcall
figure(10);
subplot(2,1,1);
botax = subplot(2,1,2);
268
botplot =
plot(bestvangseffs(:,1),bestvangseffs(:,2),vangs,vangwts./max(vangwts),vangs,effs);
set(botplot(1),'color',[.8 .8 .8],'linewidth',3);
set(botplot(2),'color',[0 0 1]);
set(botplot(3),'color',[0 .5 0],'linewidth',3);
if bestflag
set(botplot(3),'color',[1 0 0]);
end
title(botax,['Merit Function Value = ' num2str(merit) ' ( best = ' num2str(bestmerit)
' )']);
grid on;
else
set(botplot(3),'YData',effs,'color',[0 .5 0]);
if bestflag
set(topplot4,'xdata',[bestinjpos(:,1);bestinjpos(:,1)],'ydata',[bestinjpos(:,2)-
d;bestinjpos(:,2)]);
set(topplot5,'xdata',bestrefl(:,1),'ydata',bestrefl(:,2));
set(topplot6,'xdata',bestrefl(:,1),'ydata',bestrefl(:,2)+d);
set(botplot(1),'YData',bestvangseffs(:,2));
set(botplot(3),'color',[1 0 0]);
end
title(botax,['Merit Function Value = ' num2str(merit) ' ( best = ' num2str(bestmerit)
' )']);
drawnow expose;
end
%%
if plotyn
pangsmat = angsmat(logical(wtsmat4));
%rays
rayx1 = x0.*ones(1,length(hitind));
rayy1 = transpose(rayiny(hitind));
rayx2 = transpose(segxint(hitind));
rayy2 = transpose(segyint(hitind));
rayx3 = transpose(aimxint(hitind));
rayy3 = minj.*(rayx3-injpos(2,1)) + injpos(2,2);
rayx4 = zeros(size(rayx1));
rayy4 = zeros(size(rayx1));
rayy4(:) = cutyint(hitinjgid);
pangs = unique(pangsmat);
numpangs = numel(pangs);
rgb = zeros(numpangs,3);
rgbind = linspace(0,2,numpangs);
for nw = 1:numpangs
if rgbind(nw)<=1
rgb(nw,2) = rgbind(nw);
rgb(nw,1) = 1-rgbind(nw);
else
269
rgb(nw,3) = rgbind(nw)-1;
rgb(nw,2) = 2-rgbind(nw);
end
rgb(nw,:) = rgb(nw,:)./max(rgb(nw,:));
end
rgb = flipud(rgb);
%segment data
segptsx = linspace(x0,x1,50);
segptsy = polyval(shape,segptsx);
rtfig = findobj('type','figure','name','Raytrace');
if isempty(rtfig)
figure('name','Raytrace');
else
figure(rtfig);
end
clf
plot([x0;x0],[y0;y0+d],'Color',[.7 .7 .7],'LineWidth',3); %plot front aperture
axis equal
hold on
plot(segptsx,segptsy,'-k','LineWidth',3);
plot(segptsx,segptsy+d,'-k','LineWidth',3);
pause on
for pa = 1:numpangs
pangind = find(pangsmat==pangs(pa));
rayx1p = rayx1(pangind);
rayy1p = rayy1(pangind);
rayx2p = rayx2(pangind);
rayy2p = rayy2(pangind);
rayx3p = rayx3(pangind);
rayy3p = rayy3(pangind);
rayx4p = rayx4(pangind);
rayy4p = rayy4(pangind);
plot([rayx1p;rayx2p;rayx3p;rayx4p],[rayy1p;rayy2p;rayy3p;rayy4p],'Color',rgb(pa,:));
% pause(0.00000001);
end
pause off
plot([injpos(:,1);injpos(:,1)],[injpos(:,2)-d;injpos(:,2)],'-k','LineWidth',2); %plot
injector
plot(0,2*h,'dk');
hold off
injeffs = zeros(size(vangs));
injeffs(wtsl) = sum(wtsmat3,1);
sefig = findobj('type','figure','name','Segment Efficiency');
if isempty(sefig)
figure('name','Segment Efficiency');
else
270
figure(sefig);
end
clf
effplot = plot(vangs,vangwts./max(vangwts),vangs,effs,vangs,injeffs);
set(effplot(2),'linewidth',3);
title('Segment Efficiency vs. Incidence Angle');
xlabel('Incidence Angle ( ^o )');
ylabel('Efficiency');
legend('Weighting Function','System FoV','Injection
Efficiency','Location','SouthOutside');
grid on;
end
end
function [] = savb(varargin)
save_to_base(1);
end
Immersed Louver Optimizer
Optimization routine for the immersed louver.
function [outcel] = IL_SingleSegment_Optimizer_PatternSearch_Par(locationname)
%Optimization of single segment immersed louver using PatternSearch
close all;
if ~matlabpool('size') > 0
matlabpool
end
d = 2; % optics periodicity
n = 1.49; % refractive index of material
Rmirror = 0.95; % reflectivity of mirrored surfaces
glen = 200; % guide length (mm)
gthik = 13; % guide thickness (mm)
vangmin = 0;
vangmax = 89;
vangnum = 300;
vangs = linspace(vangmin,vangmax,vangnum); % vertical angles
[lat,hitemps,lotemps] = LocationWeatherDatabase(locationname); % retrieve location and
weather information
vangwts = VerticalAngleWeightCalculator(vangs,lat,hitemps,lotemps); % vertical angle
weighting function
h = .4844; % injection feature size
endptx = -2.8066; % LHS endpoint of reflector [x,y]
shape = [0.00008716,0.0007005,0.001474,0.0002608,.02459,.1938,.6287,-.8217]; % polynomial
coefficients describing reflector shape
271
x0 = [h,endptx,shape]; % initial optimization point
%%
% variables for memorization function
mnum = 8; % number of function iterations to memorize
mx = zeros(mnum,numel(x0));
mmerit = zeros(mnum,1);
meffs = zeros(mnum,numel(vangs));
minjpos = zeros(mnum,6);
% variables for output function and plot initialization
dummy = [0;1];
numplot = 4;
numplot = min(numplot,mnum);
figure(10);
set(gcf,'position',[1049,107,565,806]);
subplot(2,1,1);
injplot = plot(repmat(dummy,1,numplot),repmat(dummy,1,numplot),'-m','LineWidth',2); %
injection features
axis equal;
hold on;
refl1plot = plot(repmat(dummy,1,numplot),repmat(dummy,1,numplot),'-r','LineWidth',2); %
reflectors
refl2plot = plot(repmat(dummy,1,numplot),repmat(dummy,1,numplot),'-r','LineWidth',2); %
shifted reflectors
hold off;
subplot(2,1,1);
botax = subplot(2,1,2);
plot(vangs,vangwts./max(vangwts),'-b'); % vertical angle weights
hold on;
effplot = plot(repmat(dummy,1,numplot),repmat(dummy,1,numplot),'-
','linewidth',3,'color',[0 .5 0]); % efficiency plots
hold off;
title(botax,'Merit Function Value = INITIAL ( best = INITIAL )');
grid on;
greys = linspace(0.9,0.6,numplot-1);
for pj = 1:numplot-1;
set(injplot(pj),'color',greys(pj).*ones(1,3));
set(refl1plot(pj),'color',greys(pj).*ones(1,3));
set(refl2plot(pj),'color',greys(pj).*ones(1,3));
set(effplot(pj),'color',greys(pj).*ones(1,3));
end
%%
% optimization options
ubnds = [1, -1, 0.001, 0.003, 0.01, 0.01, 0.04, 0.5, 1, 0];
lbnds = [0.1, -6,-0.001,-0.001,-0.01,-0.01,-0.01,-0.2, 0, -d];
rbnds = ubnds-lbnds; % range of raw bounds
x0sca = (x0-lbnds)./rbnds;
lbndsca = zeros(size(lbnds));
ubndsca = ones(size(ubnds));
272
psoptions =
psoptimset('CompletePoll','on','UseParallel','never','InitialMeshSize',0.5,'PlotFcns',{@p
splotbestf,@psplotbestx},'Display','iter',...
'TolMesh',1e-
3,'MaxIter',100*numel(x0),'MaxFunEvals',2000*numel(x0));%,'OutputFcns',@IL_SingleSegment_
PSOutputFunction_Par);
% problem =
createOptimProblem('fmincon','x0',x0sca,'lb',lbndsca,'ub',ubndsca,'options',psoptions,...
% 'objective',
@(x0sca)IL_SingleSegment_MeritFunction(d,x0sca(1).*rbnds(1)+lbnds(1),x0sca(2).*rbnds(2)+l
bnds(2),x0sca(3:end).*rbnds(3:end)+lbnds(3:end),n,Rmirror,glen,gthik,vangs,vangwts,0));
% problem.solver = 'patternsearch';
problem =
struct('objective',[],'X0',[],'Aineq',[],'bineq',[],'Aeq',[],'beq',[],'lb',[],'ub',[],'no
nlcon',[],'solver','patternsearch','options',[],'rngstate',[]);
problem.objective =
@(x0sca)IL_SingleSegment_MeritFunction_Par_Memorize(d,x0sca(1).*rbnds(1)+lbnds(1),x0sca(2
).*rbnds(2)+lbnds(2),x0sca(3:end).*rbnds(3:end)+lbnds(3:end),n,Rmirror,glen,gthik,vangs,v
angwts,0);
problem.X0 = x0sca;
problem.lb = lbndsca;
problem.ub = ubndsca;
problem.options = psoptions;
tic;
[optxsca,fval,exitflag,output] = patternsearch(problem);
optx = optxsca.*rbnds+lbnds;
%%
% memorization wrapper function (nested)
function [momerit,moeffs,moinjpos] =
IL_SingleSegment_MeritFunction_Par_Memorize(md,mh,mendptx,mshape,mn,mRmirror,mglen,mgthik
,mvangs,mvangwts,mplotyn)
%record top mnum iterations
% test if input was already calculated
[~,rowloc] = ismember([mh,mendptx,mshape],mx,'rows');
if rowloc==0
% run function
[momerit,moeffs,moinjpos] =
IL_SingleSegment_MeritFunction_Par(md,mh,mendptx,mshape,mn,mRmirror,mglen,mgthik,mvangs,m
vangwts,mplotyn);
% memorize if merit value is good enough
if any(momerit < mmerit)
mmerit(mnum) = momerit;
[mmerit,reind] = sort(mmerit);
mx(mnum,:) = [mh,mendptx,mshape];
mx = mx(reind,:);
273
meffs(mnum,:) = moeffs;
meffs = meffs(reind,:);
minjpos(mnum,:) = moinjpos(:);
minjpos = minjpos(reind,:);
end
else
momerit = mmerit(rowloc);
moeffs = reshape(meffs(rowloc,:),size(vangs));
moinjpos = reshape(minjpos(rowloc,:),size(minjpos,2)./2,[]);
end
% grab data from memorized results
ox = flipud(mx(1:numplot-1,:));
oinjpos = flipud(minjpos(1:numplot-1,:));
oeffs = flipud(meffs(1:numplot-1,:));
for op = 1:numplot-1
otshape = ox(op,3:end);
otxs = linspace(ox(op,2),0,20);
otrefl = polyval(otshape,otxs(:));
otinjpos = reshape(oinjpos(op,:),size(minjpos,2)./2,[]);
set(injplot(op),'XData',[otinjpos(:,1);otinjpos(:,1)],'YData',[otinjpos(:,2)-
d;otinjpos(:,2)]);
set(refl1plot(op),'XData',otxs,'YData',otrefl);
set(refl2plot(op),'XData',otxs,'YData',otrefl+d);
set(effplot(op),'XData',vangs,'YData',oeffs(op,:));
end
moxs = linspace(mendptx,0,20);
morefl = polyval(mshape,moxs(:));
set(injplot(numplot),'XData',[moinjpos(:,1);moinjpos(:,1)],'YData',[moinjpos(:,2)-
d;moinjpos(:,2)]);
set(refl1plot(numplot),'XData',moxs,'YData',morefl);
set(refl2plot(numplot),'XData',moxs,'YData',morefl+d);
set(effplot(numplot),'XData',vangs(:),'YData',moeffs(:));
title(botax,['Merit Function Value = ' num2str(momerit) ' ( Best = '
num2str(mmerit(1)) ' )']);
drawnow expose;
end
%%
% % output function (nested)
% function [stop, optnew, changed] =
IL_SingleSegment_PSOutputFunction_Par(optimValues, prevoptions, flag) % doc psoptimset >
Output Function Options
% stop = false;
% optnew = [];
% changed = false;
%
%
274
% end
%%
optin = {d,optx(1),optx(2),optx(3:end),n,Rmirror,glen,gthik,vangs,vangwts,1};
[merit,effs,injpos] = IL_SingleSegment_MeritFunction_Par(optin{1}, optin{2}, optin{3},
optin{4}, optin{5}, optin{6}, optin{7}, optin{8}, optin{9}, optin{10}, optin{11});
figure();
coeff = (1-numel(shape)):1:0;
hold on;
plot(coeff,optx(3:end),'marker','.','color','r','linewidth',2);
plot(coeff,lbnds(3:end),'-k');
plot(coeff,ubnds(3:end),'-k');
hold off;
title('eff vs. coeffs');
coeffstr = cell(1,numel(coeff));
for jk = 1:numel(coeff)
coeffstr{jk} = ['x^' num2str(abs(coeff(jk)))];
end
set(gca,'XTick',coeff,'XTickLabel',coeffstr);
grid on;
% output cell to paste to Excel
outcel = cell(10,max(numel(x0)+1,9));
outcel(1,1) = {mfilename('fullpath')};
outcel(2,2:4) = [{'h'},{'x0'},{'shape...'}];
outcel(3:6,1) = [{'initialx'};{'optx'};{'ubnds'};{'lbnds'}];
outcel(8,1:9) =
[{'d'},{'n'},{'Rmirror'},{'glen'},{'gthik'},{'vangmin'},{'vangmax'},{'vangnum'},{'lat'}];
outcel(3,2:numel(x0)+1) = num2cell(x0);
outcel(4,2:numel(x0)+1) = num2cell(optx);
outcel(5,2:numel(x0)+1) = num2cell(ubnds);
outcel(6,2:numel(x0)+1) = num2cell(lbnds);
outcel(9,1:9) = [{d},{n},{Rmirror},{glen},{gthik},{vangmin},{vangmax},{vangnum},{lat}];
outcel(10,1) = {'Notes:'};
outcel(10,2) = {'Patternsearch options: CompletePoll on, InitialMeshSize 0.2, scaled all
bounds to be between 0 and 1'};
outcel(12,1:3) = [{'vangs'},{'effs'},{'merit'}];
outcel(13:13+vangnum-1,1:2) = num2cell([vangs(:),effs(:)]);
outcel(13,3) = num2cell(merit);
%%
BuildLT = questdlg('Would you like to build this reflector in LightTools?',...
'Build in LT?','Yes','No','No');
if strcmp(BuildLT,'Yes')
SL_SingleSegment_BuildLT(injpos,optx(3:end),optx(2),d,Rmirror,1);
end
end
275
Immersed Louver Merit Function
Merit function evaluated for all parameters passed from the optimization routine.
function [merit,effs,injpos] =
IL_SingleSegment_MeritFunction_Par(d,h,x0,shape,n,Rmirror,glen,gthik,vangs,vangwts,plotyn
)
% %input arguments
% d = 2.6; % optics periodicity
% h = 0.78; % injection feature size
% endpt = [-4.8 -2]; % LHS endpoint of reflector [x,y]
% shape = [0.0855 0.5623 -1.2713]; % polynomial coefficients describing reflector shape
% n = 1.49;
% Rmirror = 0.95; % reflectivity of mirrored surfaces
% glen = 300;
% gthik = 13;
% plotyn = 1;
% vangs = linspace(0,89,300);
% vangwts = VerticalAngleWeightCalculator(vangs,43.12);
%%%%%%%%%start of function code
evalpts = 100;
R = 1-h/d;
critang = asind(1/n);
vangsn = asind(sind(vangs)./n); % vertical angles after entering material
y0 = polyval(shape,x0);
% calculate RHS endpoint components
x1 = 0;
y1 = shape(end);
% calculate injection feature shape
%%%%%%%%%% changed injpos from size (4,2) to (3,2)
injpos = zeros(3,2);
mcrit = tand(critang);
minj = -mcrit;
injpos(2,1) = h./minj;
injpos(2:3,2) = h;
if shape(end) < (h-d)
effs = zeros(size(vangs));
merit = 0;
return
elseif polyval(shape, injpos(2,1)) < (h-d)
shapeshft = shape;
shapeshft(end) = shapeshft(end)+d-h;
solsinj = roots(shapeshft);
solsinj = round(solsinj.*1e10)./1e10;
solsinj = solsinj( (solsinj<=x1) & (solsinj>=injpos(2,1)) & (imag(solsinj)==0) );
276
if any(solsinj)
injpos(2,1) = max(solsinj);
minj = (injpos(2,2)-injpos(1,2))./(injpos(2,1)-injpos(1,1));
end
end
% find weights for each incidence angle
aplo = y0;
aphi = min(-tand(vangsn).*(x0-x1)+y1, y0+d); % find from where in the aperture the rays
strike the RHS point of the reflector
aphi = min(-tand(vangsn).*(x0-injpos(2,1))+injpos(2,2), aphi); % so rays don't pass
through the injector on the way to the reflector
wts = max((aphi-aplo)./d, 0); % initial weights based on the fraction of the aperature
that produces rays that hit the reflector
wtsl = logical(wts); % for logical indexing of non-zero weight incidence angles
wtsmat0 = repmat(wts(wtsl), evalpts, 1)./evalpts; % expanding wts into ray dimension,
each ray gets fair share of vang wts
angsmat = repmat(vangsn(wtsl), evalpts, 1); % expand vangs into ray dimension
slpsmat = -tand(angsmat);
% find start point of rays by equally spreading rays across applicable part of the input
aperture for each incidence angle
rayiny = zeros(size(slpsmat));
aphiap = aphi(wtsl);
parfor ij = 1:size(slpsmat,2)
rayiny(:,ij) = linspace(aplo,aphiap(ij),evalpts);
end
% find where incoming rays intersect segment
segxint = zeros(size(slpsmat));
nosol = segxint;
parfor jk = 1:numel(slpsmat)
polyadj = zeros(size(shape));
polyadj(end-1:end) = [slpsmat(jk),rayiny(jk)-slpsmat(jk).*x0];
sols = roots(shape-polyadj);
sols = round(sols.*1e10)./1e10;
solsa = sols( (sols<=x1) & (sols>=x0) & (imag(sols)==0) );
if any(solsa)
segxint(jk) = min(solsa);
else
nosol(jk) = 1;
end
polyadj2 = polyadj;
polyadj2(end) = polyadj2(end)-d;
sols2 = roots(shape-polyadj2);
sols2 = round(sols2.*1e10)./1e10;
solsa2 = sols2( (sols2<=x1) & (sols2>=x0) & (imag(sols2)==0) );
if any(solsa2)
nosol(jk) = 1;
end
end
277
segyint = polyval(shape,segxint);
% find slopes/normals of surface where rays strike it
surfslps = polyval(polyder(shape),segxint);
% find directions of reflected rays
rdirvec = refl([ones(size(slpsmat(:))),slpsmat(:)],[-
surfslps(:),ones(size(surfslps(:)))]);
rdirvecx = reshape(rdirvec(:,1),size(slpsmat)); %reflected ray direction unit vectors, x
component
rdirvecy = reshape(rdirvec(:,2),size(slpsmat)); %reflected ray direction unit vectors, y
component
rslpsmat = rdirvecy./rdirvecx;
wtsmat1 = wtsmat0.*Rmirror;
wtsmat1(logical(nosol)) = 0; % zero weights for rays with no reflector intersection
% find rays that intersect with aim region line segment
aimxint = (rslpsmat.*segxint - segyint) ./ (rslpsmat-minj);
aimyint = minj.*(aimxint);
hitinj = find( (aimxint>=injpos(2,1)) & (aimxint<=0) & ~nosol );
if isempty(hitinj)
effs = zeros(size(vangs));
merit = 0;
return
end
wtsmat2 = wtsmat1;
wtsmat2(setdiff(1:numel(wtsmat2),hitinj)) = 0; % zero weights for rays that did not make
it to the aim region
% exclude rays that do not successfully inject into the guide
rrdirvec = [rdirvecx(hitinj),rdirvecy(hitinj)];
rrslps = rslpsmat(hitinj);
cutyint = -rrslps.*aimxint(hitinj) + aimyint(hitinj); % y intercept of rays at guide
surface
ibakxint = (h+rrslps.*aimxint(hitinj)-aimyint(hitinj))./rrslps; % x intercept of rays at
injector back reflective surface
hitinjgid = find( (cutyint>=0) & (cutyint<=2*h) & (ibakxint>=injpos(2,1)) );
if isempty(hitinjgid)
effs = zeros(size(vangs));
merit = 0;
return
end
hitinjgiddn = find( (cutyint>h) & (cutyint<=2*h) );
hitind = hitinj(hitinjgid);
hitinddn = hitinj(hitinjgiddn);
wtsmat3 = wtsmat2;
wtsmat3(setdiff(1:numel(wtsmat3),hitind)) = 0;
wtsmat3(hitinddn) = wtsmat3(hitinddn).*Rmirror;
% guide ray tracing
278
gstrt0 = cutyint; % starting ray positions in guide
gstrt0(hitinjgiddn) = gstrt0(hitinjgiddn)-h; % shift "down rays" to center on origin,
unflipped for calculations
gstrt = gstrt0(hitinjgid)-h/2; % shift center of injector to origin and ignore rays
missing injection feature
gdist = h/2:d:(glen-h/2); % guide sample points (distance from the top edge of the guide)
gdist = gdist + (glen-gdist(end)+h/2)./2; % shift injector positions so they are
symmetric about the center of the guide
loledist = 2.*rrdirvec(hitinjgid+size(rrdirvec,1)).*gthik./rrdirvec(hitinjgid); %
distance rays travel without interacting with lossy guide surface
gideffs = zeros(numel(gstrt),numel(gdist));
parfor gi = 1:numel(gdist)
dup = gdist(gi); % distance to guide top
gideffs(:,gi) = R.^(floor((dup-gstrt)./loledist));
end
wtsmat4 = wtsmat3;
wtsmat4(hitind) = wtsmat4(hitind).*mean(gideffs,2);
effs = zeros(size(vangs));
effs(wtsl) = sum(wtsmat4,1);
merit = -100*sum(effs.*vangwts)/sum(vangwts(vangwts>0)); % normalized to an absolute
minimum of -100
%%
if plotyn
pangsmat = angsmat(logical(wtsmat4));
%rays
rayx1 = x0.*ones(1,length(hitind));
rayy1 = transpose(rayiny(hitind));
rayx2 = transpose(segxint(hitind));
rayy2 = transpose(segyint(hitind));
rayx3 = transpose(aimxint(hitind));
rayy3 = minj.*rayx3;
rayx4 = zeros(size(rayx1));
rayy4 = zeros(size(rayx1));
rayy4(:) = cutyint(hitinjgid);
pangs = unique(pangsmat);
numpangs = numel(pangs);
rgb = zeros(numpangs,3);
rgbind = linspace(0,2,numpangs);
for nw = 1:numpangs
if rgbind(nw)<=1
rgb(nw,2) = rgbind(nw);
rgb(nw,1) = 1-rgbind(nw);
279
else
rgb(nw,3) = rgbind(nw)-1;
rgb(nw,2) = 2-rgbind(nw);
end
rgb(nw,:) = rgb(nw,:)./max(rgb(nw,:));
end
rgb = flipud(rgb);
%segment data
segptsx = linspace(x0,x1,50);
segptsy = polyval(shape,segptsx);
rtfig = findobj('type','figure','name','Raytrace');
if isempty(rtfig)
figure('name','Raytrace');
else
figure(rtfig);
end
clf
plot([x0;x0],[y0;y0+d],'Color',[.7 .7 .7],'LineWidth',3); %plot front aperture
axis equal
hold on
plot(segptsx,segptsy,'-k','LineWidth',3);
plot(segptsx,segptsy+d,'-k','LineWidth',3);
pause on
for pa = 1:numpangs
pangind = find(pangsmat==pangs(pa));
rayx1p = rayx1(pangind);
rayy1p = rayy1(pangind);
rayx2p = rayx2(pangind);
rayy2p = rayy2(pangind);
rayx3p = rayx3(pangind);
rayy3p = rayy3(pangind);
rayx4p = rayx4(pangind);
rayy4p = rayy4(pangind);
plot([rayx1p;rayx2p;rayx3p;rayx4p],[rayy1p;rayy2p;rayy3p;rayy4p],'Color',rgb(pa,:));
% pause(0.00000001);
end
pause off
plot([injpos(:,1);injpos(:,1)],[injpos(:,2)-d;injpos(:,2)],'-k','LineWidth',2); %plot
injector
plot(0,2*h,'dk');
hold off
injeffs = zeros(size(vangs));
injeffs(wtsl) = sum(wtsmat3,1);
sefig = findobj('type','figure','name','Segment Efficiency');
if isempty(sefig)
figure('name','Segment Efficiency');
280
else
figure(sefig);
end
clf
effplot = plot(vangs,vangwts./max(vangwts),vangs,effs,vangs,injeffs);
set(effplot(2),'linewidth',3);
title('Segment Efficiency vs. Incidence Angle');
xlabel('Incidence Angle ( ^o )');
ylabel('Efficiency');
legend('Weighting Function','System FoV','Injection
Efficiency','Location','SouthOutside');
grid on;
end
end
Extruded Segment Lens Optimizer
Optimization routine for the extruded segment lens.
function [outcel,optin,mx,mmerit] =
EL_SingleSegment_Optimizer_PatternSearch_Par(locationname)
%Optimization of single segment immersed louver using PatternSearch
close all;
if ~matlabpool('size') > 0
matlabpool
end
d = 2; % optics periodicity
PMMA = struct('name','PMMA','data',...
[320 407 493 580 667 753 840 927 1013 1100 ; %
wavelengths in nm
1.5136 1.5063 1.4973 1.4922 1.4889 1.4869 1.4852 1.4841 1.4831 1.4831; % index of
refraction
0.134 0.778 1.328 1.333 1.234 1.018 0.898 0.535 0.651 0.278 ]); %
relative weights
Material = PMMA;
Rmirror = 0.95; % reflectivity of mirrored surfaces
glen = 300; % guide length (mm)
gthik = 13; % guide thickness (mm)
vangmin = 0;
vangmax = 89;
vangnum = 200;
vangs = linspace(vangmin,vangmax,vangnum); % vertical angles
ns = Material.data(2,:); % refractive index of material
wavs = Material.data(1,:); % wavelengths for refractive inicies
spectralresponse = Material.data(1,:)./1100;
wavwts = Material.data(3,:).*spectralresponse;
281
[lat,hitemps,lotemps] = LocationWeatherDatabase(locationname); % retrieve location and
weather information
vangwts = VerticalAngleWeightCalculator(vangs,lat,hitemps,lotemps); % vertical angle
weighting function
h = .5; % injection feature size
y0 = -1; % low endpoint of powered surface
shape = [0 0 0 0 0 0 0 -2]; % polynomial coefficients describing lens shape
x0 = [h,y0,shape]; % initial optimization point
initmeshsize = 0.1;
% optimization options
ubnds = [1.3,-.01, .2, 0.3, 1, 1.2, 1.2, 1.5, 2, 0];
lbnds = [0.1, -2,-.4,-0.3,-1,-1.2,-1.2,-1.5, -2, -5];
rbnds = ubnds-lbnds; % range of raw bounds
x0sca = (x0-lbnds)./rbnds;
lbndsca = zeros(size(lbnds));
ubndsca = ones(size(ubnds));
%%
% variables for memorization function
mnum = 8; % number of function iterations to memorize
mx = zeros(mnum,numel(x0));
mmerit = zeros(mnum,1);
meffs = zeros(mnum,numel(vangs));
mlensvert = zeros(mnum,10);
% variables for output function and plot initialization
dummy = [0;1];
numplot = 4;
numplot = min(numplot,mnum);
figure(10);
set(gcf,'position',[1049,107,565,806]);
subplot(2,1,1);
injplot = plot(repmat(dummy,1,numplot),repmat(dummy,1,numplot),'-m','LineWidth',2); %
injection features
axis equal;
subplot(2,1,1);
botax = subplot(2,1,2);
plot(vangs,vangwts./max(vangwts),'-b'); % vertical angle weights
hold on;
effplot = plot(repmat(dummy,1,numplot),repmat(dummy,1,numplot),'-
','linewidth',3,'color',[0 .5 0]); % efficiency plots
hold off;
title(botax,'Merit Function Value = INITIAL ( best = INITIAL )');
grid on;
greys = linspace(0.9,0.6,numplot-1);
for pj = 1:numplot-1;
282
set(injplot(pj),'color',greys(pj).*ones(1,3));
set(effplot(pj),'color',greys(pj).*ones(1,3));
end
%%
psoptions =
psoptimset('CompletePoll','on','UseParallel','never','InitialMeshSize',initmeshsize,'Plot
Fcns',{@psplotbestf,@psplotbestx},'Display','iter',...
'TolMesh',1e-
3,'MaxIter',100*numel(x0),'MaxFunEvals',2000*numel(x0));%,'OutputFcns',@IL_SingleSegment_
PSOutputFunction_Par);
% problem =
createOptimProblem('fmincon','x0',x0sca,'lb',lbndsca,'ub',ubndsca,'options',psoptions,...
% 'objective',
@(x0sca)IL_SingleSegment_MeritFunction(d,x0sca(1).*rbnds(1)+lbnds(1),x0sca(2).*rbnds(2)+l
bnds(2),x0sca(3:end).*rbnds(3:end)+lbnds(3:end),n,Rmirror,glen,gthik,vangs,vangwts,0));
% problem.solver = 'patternsearch';
problem =
struct('objective',[],'X0',[],'Aineq',[],'bineq',[],'Aeq',[],'beq',[],'lb',[],'ub',[],'no
nlcon',[],'solver','patternsearch','options',[],'rngstate',[]);
problem.objective =
@(x0sca)IL_SingleSegment_MeritFunction_Par_Memorize(d,x0sca(1).*rbnds(1)+lbnds(1),x0sca(2
).*rbnds(2)+lbnds(2),x0sca(3:end).*rbnds(3:end)+lbnds(3:end),ns,wavs,wavwts,Rmirror,glen,
gthik,vangs,vangwts,0);
problem.X0 = x0sca;
problem.lb = lbndsca;
problem.ub = ubndsca;
problem.options = psoptions;
tic;
[optxsca,fval,exitflag,output] = patternsearch(problem);
optx = optxsca.*rbnds+lbnds;
%%
% memorization wrapper function (nested)
function [momerit,moeffs,molensvert] =
IL_SingleSegment_MeritFunction_Par_Memorize(md,mh,my0,mshape,mns,mwavs,mwavwts,mRmirror,m
glen,mgthik,mvangs,mvangwts,mplotyn)
%record top mnum iterations
% test if input was already calculated
[~,rowloc] = ismember([mh,my0,mshape],mx,'rows');
if rowloc==0
% run function
[momerit,moeffs,molensvert] =
EL_SingleSegment_MeritFunction(md,mh,my0,mshape,mns,mwavs,mwavwts,mRmirror,mglen,mgthik,m
vangs,mvangwts,mplotyn);
% memorize if merit value is good enough and sort all memorized function calls by
merit value
if any(momerit < mmerit)
283
mmerit(mnum) = momerit;
[mmerit,reind] = sort(mmerit);
mx(mnum,:) = [mh,my0,mshape];
mx = mx(reind,:);
meffs(mnum,:) = moeffs;
meffs = meffs(reind,:);
mlensvert(mnum,:) = molensvert(:);
mlensvert = mlensvert(reind,:);
end
else
momerit = mmerit(rowloc);
moeffs = reshape(meffs(rowloc,:),size(vangs));
molensvert = reshape(mlensvert(rowloc,:),size(mlensvert,2)./2,[]);
end
% grab data from memorized results
ox = flipud(mx(1:numplot-1,:));
olensvert = flipud(mlensvert(1:numplot-1,:));
oeffs = flipud(meffs(1:numplot-1,:));
for op = 1:numplot-1
otshape = ox(op,3:end);
otlensvert = reshape(olensvert(op,:),[],2);
otys = linspace(otlensvert(2,2),otlensvert(3,2),20);
otxs = polyval(otshape,-otys(:));
otxs = [otlensvert(1,1);otxs(:);otlensvert(4:5,1)];
otys = [otlensvert(1,2);otys(:);otlensvert(4:5,2)];
set(injplot(op),'XData',[otxs;otxs],'YData',[otys;otys+d]);
set(effplot(op),'XData',vangs,'YData',oeffs(op,:));
end
moys = linspace(my0,molensvert(3,2),20);
moxs = polyval(mshape,-moys(:));
moxs = [molensvert(1,1);moxs(:);molensvert(4:5,1)];
moys = [molensvert(1,2);moys(:);molensvert(4:5,2)];
set(injplot(numplot),'XData',[moxs;moxs],'YData',[moys;moys+d]);
set(effplot(numplot),'XData',vangs(:),'YData',moeffs(:));
title(botax,['Merit Function Value = ' num2str(momerit) ' ( Best = '
num2str(mmerit(1)) ' )']);
drawnow expose;
end
%%
% % output function (nested)
% function [stop, optnew, changed] =
IL_SingleSegment_PSOutputFunction_Par(optimValues, prevoptions, flag) % doc psoptimset >
Output Function Options
% stop = false;
% optnew = [];
% changed = false;
284
%
%
% end
%%
optin =
{d,optx(1),optx(2),optx(3:end),ns,wavs,wavwts,Rmirror,glen,gthik,vangs,vangwts,1};
[merit,effs,lensvert] = EL_SingleSegment_MeritFunction(optin{1}, optin{2}, optin{3},
optin{4}, optin{5}, optin{6}, optin{7}, optin{8}, optin{9}, optin{10},
optin{11},optin{12},optin{13});
figure();
coeff = (1-numel(shape)):1:0;
hold on;
plot(coeff,optx(3:end),'marker','.','color','r','linewidth',2);
plot(coeff,lbnds(3:end),'-k');
plot(coeff,ubnds(3:end),'-k');
hold off;
title('eff vs. coeffs');
coeffstr = cell(1,numel(coeff));
for jk = 1:numel(coeff)
coeffstr{jk} = ['x^' num2str(abs(coeff(jk)))];
end
set(gca,'XTick',coeff,'XTickLabel',coeffstr);
grid on;
% output cell to paste to Excel
outcel = cell(10,max(numel(x0)+1,9));
outcel(1,1) = {mfilename('fullpath')};
outcel(2,2:4) = [{'h'},{'y0'},{'shape...'}];
outcel(3:6,1) = [{'initialx'};{'optx'};{'ubnds'};{'lbnds'}];
outcel(8,1:9) =
[{'d'},{'Material'},{'Rmirror'},{'glen'},{'gthik'},{'vangmin'},{'vangmax'},{'vangnum'},{'
lat'}];
outcel(3,2:numel(x0)+1) = num2cell(x0);
outcel(4,2:numel(x0)+1) = num2cell(optx);
outcel(5,2:numel(x0)+1) = num2cell(ubnds);
outcel(6,2:numel(x0)+1) = num2cell(lbnds);
outcel(9,1:9) =
[{d},{Material.name},{Rmirror},{glen},{gthik},{vangmin},{vangmax},{vangnum},{lat}];
outcel(10,1) = {'Notes:'};
outcel(10,2) = {['Patternsearch options: CompletePoll on, InitialMeshSize '
num2str(initmeshsize) ', scaled all bounds to be between 0 and 1']};
outcel(12,1:3) = [{'vangs'},{'effs'},{'merit'}];
outcel(13:13+vangnum-1,1:2) = num2cell([vangs(:),effs(:)]);
outcel(13,3) = num2cell(merit);
end
285
Extruded Segment Lens Merit Function
Merit function evaluated for all parameters passed from the optimization routine.
Includes material dispersion and chromatic effects unlike the reflective louver functions.
function [merit,effs,lensvert] =
EL_SingleSegment_MeritFunction(d,h,y0,shaperot,ns,wavs,wavwts,Rmirror,glen,gthik,vangs,va
ngwts,plotyn)
%%%%%%%%%%%%%%%%%%%%%%
%test inputs
% clear all
% d = 2; % optics periodicity
% PMMA = struct('name','PMMA','data',...
% [320 407 493 580 667 753 840 927 1013 1100 ; %
wavelengths in nm
% 1.5136 1.5063 1.4973 1.4922 1.4889 1.4869 1.4852 1.4841 1.4831 1.4831; % index
of refraction
% 0.134 0.778 1.328 1.333 1.234 1.018 0.898 0.535 0.651 0.278 ]); %
relative weights
% Material = PMMA;
% Rmirror = 0.95; % reflectivity of mirrored surfaces
% glen = 300; % guide length (mm)
% gthik = 13; % guide thickness (mm)
% vangmin = 0;
% vangmax = 89;
% vangnum = 200;
% vangs = linspace(vangmin,vangmax,vangnum); % vertical angles
%
% ns = Material.data(2,:); % refractive index of material
% spectralresponse = Material.data(1,:)./1100;
% wavwts = Material.data(3,:).*spectralresponse;
% wavs = Material.data(1,:);
%
% [lat,hitemps,lotemps] = LocationWeatherDatabase('Rochester'); % retrieve location and
weather information
% vangwts = VerticalAngleWeightCalculator(vangs,lat,hitemps,lotemps); % vertical angle
weighting function
%
% h = .46; % injection feature size
% y0 = -0.52; % low endpoint of powered surface
% shaperot = [0 0 -0.7971 -0.9144 0.1431 0.5509 0.4529 -1.7675]; % polynomial
coefficients describing lens shape
% plotyn = 1;
%%%%%%%%%%%%%%%%%%%%%
% y0 < 0
286
evalpts = 100;
critang0(1,1,:) = asind(1./ns);
numwav = numel(ns);
wavwts = wavwts./sum(wavwts(:));
R = 1-h/d;
rnd10 = @(x) round(x.*1e10)./1e10; % round to nearest 1e-10
% set outputs to undesirable values
lensvert = zeros(5,2);
function [] = badmerit()
merit = 0;
effs = zeros(size(vangs));
end
% find missing endpoint component
x0rot = -y0;
y0rot = polyval(shaperot,x0rot);
if y0rot>0 || (y0rot/x0rot)>1 % return if endoint is inside guide layer or primary
reflector is too steep
badmerit;return;
end
x0 = y0rot;
% find opposite endpoint
bndslp = 2*(-x0rot/y0rot)/(1-(-x0rot/y0rot)^2); % slope of ray (rotated) incident on
primary reflector such that it reflects to be parallel to the guide
if bndslp==Inf || bndslp==-Inf || isnan(bndslp)
x1rot = 0;
else
shapeshft1 = shaperot;
shapeshft1(end-1) = shapeshft1(end-1)-bndslp;
sols1 = roots(shapeshft1);
sols1 = rnd10(sols1);
sols1 = sols1( (sols1<=x0rot) & (imag(sols1)==0) );
x1rot = max([sols1(:);x0rot-d]);
end
if x1rot>-h % return if opposite endpoint is not beyond secondary reflector
badmerit;return;
end
y1rot = polyval(shaperot,x1rot);
% check that lens shape is well defined
testxrot0 = linspace(x1rot,x0rot,100);
testxrot1 = linspace(x1rot,-h,100);
testxrot2 = linspace(0,x0rot,100);
if any(polyval(shaperot,testxrot0)>0) ||
any(polyval(shaperot,testxrot1)>testxrot1.*y1rot./x1rot) ||
any(polyval(shaperot,testxrot2)>testxrot1.*y0rot./x0rot)
badmerit;return;
end
287
% map out lens verticies in unrotated space
lensvert(2:3,1:2) = [x0,y0;y1rot,-x1rot];
lensvert(4,1:2) = [(y1rot./x1rot).*(-h),h];
lensvert(5,2) = h;
% create starting ray positions
vslpsrot = 1./tand(vangs);
aphi = x0rot-y0rot./vslpsrot;
aplo = x1rot-y1rot./vslpsrot;
taphi = x0rot.*ones(size(vangs));
parfor vi = setdiff(1:numel(vangs),find(vangs==0));
% find where each ray angle is tangent to the lens surface
tshape = polyder(shaperot);
tshape(end) = tshape(end)-vslpsrot(vi);
tsols = roots(tshape);
tsols = tsols( (tsols<=x0rot) & (tsols>=x1rot) & (imag(tsols)==0) );
tsolap = tsols-polyval(shaperot,tsols)./vslpsrot(vi);
if any(tsolap(:))
taphi(vi) = max(tsolap(:));
end
end
aphi = max(aphi,taphi);
aplo = max(aplo,max(taphi-d,aphi-d));
apwt = max((aphi-aplo)./d, 0);
% find ray starting positions in rotated space
vslpsrotmat0 = repmat(vslpsrot(:).',evalpts,1);
vslpsrotmat = repmat(vslpsrotmat0,[1,1,numwav]);
rayystrtrot = 1.1*min(polyval(shaperot,linspace(x1rot,x0rot,100))); % starting ray y
positions in rotated space
rayxstrtrot0 = repmat(linspace(0+1/evalpts/100,1-
1/evalpts/100,evalpts).',1,numel(vangs));
rayxstrtrot0 = rayxstrtrot0.*repmat(aphi(:).',evalpts,1) + (1-
rayxstrtrot0).*repmat(aplo(:).',evalpts,1); % starting ray x-intercepts in rotated space
rayxstrtrot = rayystrtrot./vslpsrotmat0 + rayxstrtrot0; % starting ray x positions in
rotated space
rayxstrtrot = repmat(rayxstrtrot,[1,1,numwav]);
%separate array for ray x position, y position, x component of direction
%vector, y component of direction vector
%carry these all the way through the trace
init0 = zeros(evalpts,numel(vangs),numwav);
rayx = struct('start',init0,'lens',init0,'refl1',init0,'refl2',init0,'inj',init0);
rayy = rayx;
rdirx = struct('start',init0,'lens',init0,'inj',init0);
rdiry = rdirx;
wts = struct('start',init0,'lens',init0,'inj',init0,'gid',init0);
rayx.start = rayystrtrot.*ones(evalpts,numel(vangs),numwav);
rayy.start = -rayxstrtrot;
288
rdirx.start = repmat(cosd(vangs(:)).',[evalpts,1,numwav]);
rdiry.start = -repmat(sind(vangs(:)).',[evalpts,1,numwav]);
wavwt(1,1,:) = wavwts(:);
wavwt = repmat(wavwt,[evalpts,numel(vangs),1]);
wts.start = repmat(1./evalpts.*apwt(:).',[evalpts,1,numwav]).*wavwt;
% find where rays intersect lens
rayxlensrot = zeros(size(rayxstrtrot));
wtslensmask = ones(size(wts.lens));
parfor ri = 1:numel(rayxstrtrot)
if vslpsrotmat(ri) == Inf || vslpsrotmat(ri) == -Inf
sols = rayxstrtrot(ri);
else
shapeshft = shaperot;
shapeshft(end-1) = shapeshft(end-1) - vslpsrotmat(ri);
shapeshft(end) = shapeshft(end) + vslpsrotmat(ri).*rayxstrtrot(ri) - rayystrtrot;
sols = roots(shapeshft);
end
sols = rnd10(sols);
sols = sols( (sols<=x0rot) & (sols>=x1rot) & (imag(sols)==0) );
if isempty(sols)
wtslensmask(ri) = 0;
else
rayxlensrot(ri) = min(sols); % non-rotated space
end
end
wts.lens = wts.start.*wtslensmask;
rayy.lens = -rayxlensrot;
rayx.lens = polyval(shaperot,-rayy.lens); % non-rotated space
% find surface normal vectors at ray intersection points
lensslpsrot = polyval(polyder(shaperot),rayxlensrot);
normdiry = lensslpsrot./sqrt(1+lensslpsrot.^2); % surface normal unit vector y component
in unrotated space
normdirx = sqrt(1-normdiry.^2); % surface normal unit vector x component in unrotated
space
% refract rays
n0(1,1,:) = ns(:);
n = repmat(n0,[evalpts,numel(vangs),1]);
wtslensmask = logical(wtslensmask);
[refvec,Tlens] =
refractfres([rdirx.start(wtslensmask),rdiry.start(wtslensmask)],[normdirx(wtslensmask),no
rmdiry(wtslensmask)],1,n(wtslensmask));
rdirx.lens(wtslensmask) = refvec(:,1);
rdiry.lens(wtslensmask) = refvec(:,2);
wts.lens(wtslensmask) = wts.lens(wtslensmask).*Tlens;
wts.lens(rdirx.lens<=0) = 0;
% find goal points
289
% function finds point (pt) reflected over a line defined by point on reflector
(ptonrefl) and vector along reflector (vecalongrefl)
ptrefl = @(pt,ptonrefl,vecalongrefl) -pt + 2.*ptonrefl +
2.*vecalongrefl./norm(vecalongrefl).*dot((pt-ptonrefl),vecalongrefl./norm(vecalongrefl));
% finds point (pt) reflected over a line defined by point on reflector (ptonrefl) and
vector along reflector (vecalongrefl)
g = zeros(4,2); % g1 = left end of secondary, g2 = g1 reflected over primary mirror, g3 =
right end of secondary reflected over primary mirror, g4 = origin reflected over line
defined by g2 and g3
g(1,:) = lensvert(4,:);
g(2,:) = ptrefl(lensvert(4,:),lensvert(1,:),lensvert(2,:));
g(3,:) = ptrefl(lensvert(5,:),lensvert(1,:),lensvert(2,:));
g(4,:) = ptrefl(lensvert(1,:),g(2,:),g(3,:)-g(2,:));
% find rays that are successfully injected into the guide
lineintx = @(pt1x,pt1y,m1,pt2x,pt2y,m2) (pt1y-pt2y+m2.*pt2x-m1.*pt1x)./(m2-m1); % returns
x component of intersection between two lines, each defined by a point and a slope
evalliny = @(x,ptx,pty,m) m.*(x-ptx)+pty; % finds y given x, a point, and a slope
A = (rdiry.lens./rdirx.lens.*(g(1,1)-rayx.lens) + rayy.lens)<=g(1,2); % rays that don't
hit inactive face of lens
yat0 = rdiry.lens./rdirx.lens.*(0-rayx.lens) + rayy.lens;
B = yat0>=0 & yat0<=g(1,2); % rays that go directly to injector (assuming A)
C = yat0>=g(1,2) & yat0<=2*g(1,2); % rays that hit secondary first, then go through
injector (assuming A)
xatrgid = lineintx(rayx.lens,rayy.lens,rdiry.lens./rdirx.lens,0,0,g(3,2)/g(3,1)); % x ray
position at guide surface reflected over primary
D = xatrgid>0 & xatrgid<=g(3,1); % rays that hit primary then go through injector
F = xatrgid>g(3,1) & xatrgid<=g(4,1); % rays that hit primary-secondary-injector,
assuming they hit the secondary at all ('E')
xatrs = lineintx(rayx.lens,rayy.lens,rdiry.lens./rdirx.lens,g(2,1),g(2,2),(g(3,2)-
g(2,2))/(g(3,1)-g(2,1))); % x ray position at secondary mirror surface reflected over
primary
E = xatrs>=g(2,1) & xatrs<g(3,1); % rays that hit primary then secondary
hiti = A & B; % straight to injector
hitsi = A & C; % secondary-injector
hitpi = A & D & ~B; % primary-injector
hitpsi = A & E & F & ~B; % primary-secondary-injector
if any( hiti & hitsi & hitpi & hitpsi )
badmerit;return;
end
%%%%%%%%% debug
% y1 = -x1rot;
% lenptsy = linspace(y0,y1,50);
% lenptsx = polyval(shaperot,-lenptsy);
% lenptsx = [lensvert(1,1),lenptsx,lensvert(4,1),lensvert(5,1)];
% lenptsy = [lensvert(1,2),lenptsy,lensvert(4,2),lensvert(5,2)];
% figure(1);
290
% aps =
plot([0,lenptsx,lenptsx,0],[y0,lenptsy,lenptsy+d,y1+d],[0;1],[0;1],[0;1],[0;1],[0;1],[0;1
]); %plot lens outline and adjacent lens above
% hold on;
% raz = plot([zeros(1,evalpts);ones(1,evalpts)],[zeros(1,evalpts);ones(1,evalpts)],'-r');
% hold off;
% axh = gca;
% axis equal;
% xlim([-3,0.5]);
% ylim([-1,4]);
% set(aps(1),'linestyle','-','color','k','LineWidth',2);
% set(aps(2:3),'linestyle','-','color','b');
% set(aps(4),'linestyle','.','color','r');
% pause on;
% for ij = 1:numel(aphi)
% set(aps(2),'xdata',[0,rayystrtrot],'ydata',[-aplo(ij),-
(rayystrtrot/vslpsrot(ij)+aplo(ij))]);
% set(aps(3),'xdata',[0,rayystrtrot],'ydata',[-aphi(ij),-
(rayystrtrot/vslpsrot(ij)+aphi(ij))]);
% set(aps(4),'xdata',rayx.start(:,ij,1),'ydata',rayy.start(:,ij,1));
% razinds = find(wts.lens(:,ij,1));
%
set(raz(:),'xdata',[rayx.start(razinds(1),ij,1);rayx.lens(razinds(1),ij,1);0],'ydata',[ra
yy.start(razinds(1),ij,1);rayy.lens(razinds(1),ij,1);yat0(razinds(1),ij,1)]);
% for jk = 2:numel(razinds)
%
set(raz(jk),'xdata',[rayx.start(razinds(jk),ij,1);rayx.lens(razinds(jk),ij,1);0],'ydata',
[rayy.start(razinds(jk),ij,1);rayy.lens(razinds(jk),ij,1);yat0(razinds(jk),ij,1)]);
% end
% title([num2str(vangs(ij)) '^o']);
% drawnow expose;
% pause(.1);
% end
% pause off;
%%%%%%%%%
rayy.inj(hiti) = yat0(hiti);
rayy.inj(hitsi) = 2.*g(1,2)-yat0(hitsi);
rayy.inj(hitpi) = xatrgid(hitpi)./g(3,1).*g(1,2);
rayy.inj(hitpsi) = (g(4,1)-xatrgid(hitpsi))./(g(4,1)-g(3,1)).*g(1,2);
rhat = -lensvert(2,:)./norm(lensvert(2,:));
rdirxp = -rdirx.lens + 2.*rhat(1).*(rdirx.lens.*rhat(1) + rdiry.lens.*rhat(2)); % same
basic formula as 'ptrefl' anonymous function
rdiryp = -rdiry.lens + 2.*rhat(2).*(rdirx.lens.*rhat(1) + rdiry.lens.*rhat(2)); % ditto
rdirx.inj = rdirx.lens;
rdiry.inj = rdiry.lens;
rdiry.inj(hitsi) = -rdiry.lens(hitsi);
rdirx.inj(hitpi | hitpsi) = rdirxp(hitpi | hitpsi);
rdiry.inj(hitpi) = rdiryp(hitpi);
rdiry.inj(hitpsi) = -rdiryp(hitpsi);
291
critslp = repmat(tand(critang0),[size(init0,1),size(init0,2),1]);
hitcrit = abs(rdiry.inj)./rdirx.inj >= critslp;
injected = (hiti | hitsi | hitpi | hitpsi) & hitcrit;
wts.inj = wts.lens;
% wts.inj(~(hiti | hitsi | hitpi | hitpsi)) = 0;
wts.inj(~injected) = 0;
wts.inj(hitsi & hitpi) = Rmirror.*wts.inj(hitsi & hitpi);
wts.inj(hitpsi) = Rmirror.^2.*wts.inj(hitpsi);
% guide ray tracing
gstrt = rayy.inj(injected)-lensvert(5,2)./2; % starting ray y positions in guide,
centered on origin
gslps = rdiry.inj(injected)./rdirx.inj(injected); % starting ray slopes in guide
gstrt(gslps<0) = -gstrt(gslps<0); % flip position of "down rays" so calculations can be
made in one direction
gdist = h/2:d:(glen-h/2); % guide sample points (distance from the top edge of the guide)
gdist = gdist + (glen-gdist(end)+h/2)./2; % shift injector positions so they are
symmetric about the center of the guide
loledist = abs(gslps).*2.*gthik; % distance rays travel without interacting with lossy
guide surface
gideffs = zeros(numel(gstrt),numel(gdist));
parfor gi = 1:numel(gdist)
dup = gdist(gi); % distance to guide top
gideffs(:,gi) = R.^(floor((dup-gstrt)./loledist));
end
wts.gid(injected) = wts.inj(injected).*mean(gideffs,2);
effs = reshape(sum( sum(wts.gid,3), 1), size(vangs));
merit = -100*sum(effs.*vangwts)/sum(vangwts(vangwts>0)); % normalized to an absolute
minimum of -100
%%
if plotyn
injeffs = sum(sum(wts.inj,3),1);
sefig = findobj('type','figure','name','Efficiency');
if isempty(sefig)
figure('name','Efficiency');
else
figure(sefig);
end
clf
292
effplot = plot(vangs,vangwts./max(vangwts),vangs,effs,vangs,injeffs);
set(effplot(2),'linewidth',3);
title('Efficiency vs. Incidence Angle');
xlabel('Incidence Angle ( ^o )');
ylabel('Efficiency');
legend('Weighting Function','System FoV','Injection
Efficiency','Location','SouthOutside');
grid on;
xatp =
lineintx(rayx.lens,rayy.lens,rdiry.lens./rdirx.lens,0,0,lensvert(2,2)/lensvert(2,1)); %
ray x positions at primary mirror surface
yatp = evalliny(xatp,0,0,lensvert(2,2)/lensvert(2,1)); % ray y positions at primary
mirror surface
xats = lineintx(rayx.lens,rayy.lens,rdiry.lens./rdirx.lens,g(1,1),g(1,2),0); % ray x
positions at secondary mirror surface
rayy.refl2(hiti | hitpi) = rayy.inj(hiti | hitpi);
rayy.refl1(hiti) = rayy.inj(hiti);
rayx.refl2(hitsi) = xats(hitsi);
rayy.refl2(hitsi | hitpsi) = g(1,2);
rayx.refl1(hitsi) = rayx.refl2(hitsi);
rayy.refl1(hitsi) = rayy.refl2(hitsi);
rayx.refl1(hitpi | hitpsi) = xatp(hitpi | hitpsi);
rayy.refl1(hitpi | hitpsi) = yatp(hitpi | hitpsi);
rayx.refl2(hitpsi) = (xatrs(hitpsi)-g(3,1))./(g(2,1)-g(3,1)).*g(1,1);
rayx.refl1(~(hiti | hitsi | hitpi | hitpsi)) = 0;
rayy.refl1(~(hiti | hitsi | hitpi | hitpsi)) = yat0(~(hiti | hitsi | hitpi |
hitpsi));
rayx.refl2(~(hiti | hitsi | hitpi | hitpsi)) = 0;
rayy.refl2(~(hiti | hitsi | hitpi | hitpsi)) = rayy.refl1(~(hiti | hitsi | hitpi |
hitpsi));
rayx.inj(~(hiti | hitsi | hitpi | hitpsi)) = 0;
rayy.inj(~(hiti | hitsi | hitpi | hitpsi)) = rayy.refl1(~(hiti | hitsi | hitpi |
hitpsi));
rayx.gid = init0+h;
rayx.gid(~(hiti | hitsi | hitpi | hitpsi)) = 0;
rayy.gid = init0;
rayy.gid = rayy.inj + rdiry.inj./rdirx.inj.*h;
rayy.gid(~(hiti | hitsi | hitpi | hitpsi)) = rayy.refl1(~(hiti | hitsi | hitpi |
hitpsi));
% q = 10; % number of rays to trace for each wavelength/angle combination
% % pick q rays for every wavelength/angle combination
293
% pickrays = logical(wts.gid); % matrix with ones at all positions that have a
successful ray
% numrayspaw = sum(pickrays,1); % number of successful rays for each wavelength/angle
combination
% rayinds = find(numrayspaw);
% rays2trace = [];
% for jk = 1:numel(rayinds)
% nrays = numrayspaw(rayinds(jk));
% [~,ai,wi] = ind2sub(size(numrayspaw),rayinds(jk));
% posind = find(pickrays(:,ai,wi));
% substruct = ones(size(posind));
% subs = [posind,substruct*ai,substruct*wi];
% inds = sub2ind(size(wts.gid),subs(:,1),subs(:,2),subs(:,3));
% if nrays <= q
% rays2tracetemp = inds(:);
% else
% raysy = rayy.start(inds);
% despts = transpose(linspace(min(raysy),max(raysy),q)); % desired starting
positions of rays
% [DP,RX] = ndgrid(despts,raysy);
% ydiff = abs(DP-RX);
% [~,raysyind] = min(ydiff,[],2);
% rays2tracetemp = inds(raysyind);
% end
% rays2trace = [rays2trace;rays2tracetemp];
% end
%
% [~,pangsind,~] = ind2sub(size(wts.gid),rays2trace);
% pangs = unique(vangs(pangsind));
% numpangs = numel(pangs);
% rgb = zeros(numpangs,3);
% rgbind = (pangs-min(pangs))./(max(pangs)-min(pangs)).*2;
% for nw = 1:numpangs
% if rgbind(nw)<=1
% rgb(nw,2) = rgbind(nw);
% rgb(nw,1) = 1-rgbind(nw);
% else
% rgb(nw,3) = rgbind(nw)-1;
% rgb(nw,2) = 2-rgbind(nw);
% end
% rgb(nw,:) = rgb(nw,:)./max(rgb(nw,:));
% end
% segment data
y1 = -x1rot;
lenptsy = linspace(y0,y1,60);
lenptsx = polyval(shaperot,-lenptsy);
lenptsx = [lensvert(1,1),lenptsx,lensvert(4,1),lensvert(5,1)];
lenptsy = [lensvert(1,2),lenptsy,lensvert(4,2),lensvert(5,2)];
% vangsmat = repmat(vangs(:).',[evalpts,1,numwav]);
294
%
% rtfig = findobj('type','figure','name','Raytrace');
% if isempty(rtfig)
% figure('name','Raytrace');
% else
% figure(rtfig);
% end
% clf
% hold on
% %plot rays
% for pa = 1:numpangs
% traceind = find(vangsmat==pangs(pa));
%
plot([rayx.start(traceind).';rayx.lens(traceind).';rayx.refl1(traceind).';rayx.refl2(trac
eind).';rayx.inj(traceind).';(rayx.inj(traceind)+rdirx.inj(traceind)).'],...
%
[rayy.start(traceind).';rayy.lens(traceind).';rayy.refl1(traceind).';rayy.refl2(traceind)
.';rayy.inj(traceind).';(rayy.inj(traceind)+rdiry.inj(traceind)).'],...
% 'Color',rgb(pa,:));
% end
% plot([0,lenptsx,lenptsx,0],[y0,lenptsy,lenptsy+d,y1+d],'-k','LineWidth',2); %plot
lens outline and adjacent lens above
% hold off
% axis equal
colr = zeros(size(wts.inj));
colg = colr;
colb = colr;
colwts = wts.gid./wts.start;
for vi = 1:numel(vangs)
for wi = 1:numwav
if any(colwts(:,vi,wi)>0)
colwts(find(colwts(:,vi,wi)==0),vi,wi) =
min(colwts(find(colwts(:,vi,wi)>0),vi,wi));
[colr(:,vi,wi),colg(:,vi,wi),colb(:,vi,wi)] = colorfun(colwts(:,vi,wi));
end
end
end
greyval = 0.7;
colr(wts.gid==0) = greyval;
colg(wts.gid==0) = greyval;
colb(wts.gid==0) = greyval;
[mapr,mapg,mapb] = colorfun((1:1:64).');
RaytraceGUI_SingleSegment(d,{lenptsx,lenptsy},vangs,wavs,...
{colr,colg,colb,min(colwts,[],1),max(colwts,[],1),[mapr,mapg,mapb]},...
cat(4,rayx.start,rayx.lens,rayx.refl1,rayx.refl2,rayx.inj,rayx.gid),...
cat(4,rayy.start,rayy.lens,rayy.refl1,rayy.refl2,rayy.inj,rayy.gid));
end
295
end
function [r,g,b] = colorfun(valsorig)
r = zeros(size(valsorig));
g = r;
b = r;
vals = valsorig-min(valsorig);
vals = vals./max(vals).*2; % values range from 0 to 2
b(vals<=1) = 1-vals(vals<=1);
g(vals<=1) = vals(vals<=1);
g(vals>1) = 2-vals(vals>1);
r(vals>1) = vals(vals>1)-1;
end
Tracking Louver Optimizer
Optimization routine for the suspended louver. The position and orientation of the
mobile louver is optimized for each vertical angle for maximum optical efficiency given a
reflector shape. The reflector shape is varied for each call to the louver positioning subroutine.
function [optin,fval,memorizedcalls] = TWB_Optimizer3p1(locationname,varargin)
%PatternSearch Optimization of tracking window blind concentrator
close all;
if ~matlabpool('size') > 0
matlabpool
end
tic;
Material = MaterialDatabase('PMMA');
d = 2; % optics periodicity
vangmin = 0;
vangmax = 89;
vangnum = 100;
vangs = linspace(vangmin,vangmax,vangnum); % vertical angles
[lat,hitemps,lotemps] = LocationWeatherDatabase(locationname); % retrieve location and
weather information
vangwts = VerticalAngleWeightCalculator(vangs,lat,hitemps,lotemps); % vertical angle
weighting function
ns = Material.data(2,:); % refractive index of material
wavs = Material.data(1,:); % wavelengths for refractive inicies
spectralresponse = Material.data(1,:)./1100;
wavwts = Material.data(3,:).*spectralresponse;
296
ndes = ns(4);
extang = linspace(0,.26,5);
extwt = extangwts_posWzero(extang);
glen = 300; % guide length (mm)
gthik = 13; % guide thickness (mm)
Rmirror = 0.95; % reflectivity of mirrored surfaces
ubvang = 90; % vertical angle at which focus lands on the injector in the lowest position
where the incident angle is limited by the critical angle. Should be closer to 90 degrees
than 0 degrees. Sets a base point for where focus is for each reflector position.
% initial conditions
if nargin>1
r = varargin{1};
h = varargin{2};
len = varargin{3};
reflht = varargin{4};
else
r = 0.101; % injection feature radius
h = 0.015; % injection feature size is r+h, h can be negative
len = 3.387; % distance from far endpoint of reflector to focus
reflht = 1.5; % height of reflector measured along the parabola axis
end
x0 = [r,h,len,reflht]; % initial optimization point
lbnds = [0.01, -.1, .5, 0.5];
ubnds = [0.5, .2, 6, 4 ];
rbnds = ubnds-lbnds; % range of raw bounds
x0sca = (x0-lbnds)./rbnds;
lbndsca = zeros(size(lbnds));
ubndsca = ones(size(ubnds));
initmeshsize = 0.5;
tolmesh = 3e-3;
%%
% variables for memorization function
mnum = 8; % number of function iterations to memorize
mx = zeros(mnum,numel(x0));
mmert = zeros(mnum,1);
meffs = zeros(mnum,numel(vangs));
mp = zeros(mnum,1);
mxrng = zeros(mnum,2);
mfocpos = zeros(mnum,numel(vangs)*2);
mzang = zeros(mnum,numel(vangs));
merrcode = cell(mnum,1);
% plot initialization
plotposnum = 5;
297
plotpos = round(linspace(1,numel(vangs),plotposnum));
dummy = [0;1];
numplot = 3;
numplot = min(numplot,mnum);
figure(10);
set(gcf,'position',[1049,107,565,806]);
topax = subplot(2,1,1);
hold on;
reflplot =
plot(repmat(dummy,1,(numplot+1)*plotposnum),repmat(dummy,1,(numplot+1)*plotposnum),'-
m','LineWidth',2); % reflectors
injplot = plot(repmat(dummy,1,numplot),repmat(dummy,1,numplot),'-m','LineWidth',2); %
injection features
hold off;
axis equal;
botax = subplot(2,1,2);
hold on;
plot(vangs,vangwts./max(vangwts),'-b'); % vertical angle weights
effplot = plot(repmat(dummy,1,numplot),repmat(dummy,1,numplot),'-
','linewidth',3,'color',[0 .5 0]); % efficiency plots
hold off;
title(botax,'Merit Function Value = INITIAL ( best = INITIAL )');
grid on;
greys = linspace(0.9,0.6,numplot-1);
for pj = 1:numplot-1;
set(injplot(pj),'color',greys(pj).*ones(1,3));
set(reflplot(plotposnum*(pj-1)+1:plotposnum*pj),'color',greys(pj).*ones(1,3));
set(effplot(pj),'color',greys(pj).*ones(1,3));
end
rotdnx = @(x,y,zenang,xinj,p) x.*cosd(zenang) - (y-p).*sind(zenang) + xinj;
rotdny = @(x,y,zenang,yinj,p) x.*sind(zenang) + (y-p).*cosd(zenang) + yinj;
%%
psoptions =
psoptimset('CompletePoll','on','UseParallel','never','InitialMeshSize',initmeshsize,'Plot
Fcns',{@psplotbestf,@psplotbestx},'Display','iter',...
'TolMesh',tolmesh);
problem =
struct('objective',[],'X0',[],'Aineq',[],'bineq',[],'Aeq',[],'beq',[],'lb',[],'ub',[],'no
nlcon',[],'solver','patternsearch','options',[],'rngstate',[]);
problem.objective = @(x0sca)TWB_MeritFunction3p1_Memorize(d, x0sca(2).*rbnds(2)+lbnds(2),
x0sca(1).*rbnds(1)+lbnds(1),...
x0sca(3).*rbnds(3)+lbnds(3), ubvang,
x0sca(4).*rbnds(4)+lbnds(4),...
ndes, vangs, vangwts, wavs, wavwts, ns, extang, extwt, glen,
gthik, Rmirror);
problem.X0 = x0sca;
problem.lb = lbndsca;
problem.ub = ubndsca;
problem.options = psoptions;
298
[optxsca,fval,exitflag,output] = patternsearch(problem);
optx = optxsca.*rbnds+lbnds;
%%
% memorization wrapper function (nested)
function [momert,moeffs,mop,moxrng,mofocpos,mozang,moerrcode] =
TWB_MeritFunction3p1_Memorize(md,mh,mr,mlen,mubvang,mreflht,mndes,mvangs,mvangwts,mwavs,m
wavwts,mns,mextang,mextwt,mglen,mgthik,mRmirror)
%record top mnum iterations
% test if input was already calculated
[~,rowloc] = ismember([mr,mh,mlen,mreflht],mx,'rows');
if rowloc==0
% run function
[momert,moeffs,mop,moxrng,mofocpos,mozang,moerrcode] =
TWB_MeritFunction3p1(md,mh,mr,mlen,mubvang,mreflht,mndes,mvangs,mvangwts,mwavs,mwavwts,mn
s,mextang,mextwt,mglen,mgthik,mRmirror);
% memorize if merit value is good enough and sort all memorized function calls by
merit value
if any(momert < mmert)
mmert(mnum) = momert;
[mmert,reind] = sort(mmert);
mx(mnum,:) = [mr,mh,mlen,mreflht];
mx = mx(reind,:);
meffs(mnum,:) = moeffs;
meffs = meffs(reind,:);
mp(mnum) = mop;
mp = mp(reind);
mxrng(mnum,:) = moxrng;
mxrng = mxrng(reind,:);
mfocpos(mnum,:) = mofocpos(:).';
mfocpos = mfocpos(reind,:);
mzang(mnum,:) = mozang;
mzang = mzang(reind,:);
merrcode{mnum} = moerrcode;
merrcode = merrcode(reind);
end
else
% memorized output
momert = mmert(rowloc);
moeffs = reshape(meffs(rowloc,:),size(vangs));
mop = mp(rowloc);
moxrng = mxrng(rowloc,:);
mofocpos = reshape(mfocpos(rowloc,:),[],2);
mozang = reshape(mzang(rowloc,:),size(vangs));
moerrcode = merrcode{rowloc};
end
% grab data from memorized results
ox = flipud(mx(1:numplot-1,:));
299
oeffs = flipud(meffs(1:numplot-1,:));
op = flipud(mp(1:numplot-1,:));
oxrng = flipud(mxrng(1:numplot-1,:));
ofocpos = flipud(mfocpos(1:numplot-1,:));
ozang = flipud(mzang(1:numplot-1,:));
rptnum = 20;
for opi = 1:numplot-1
otr = ox(opi,1);
oth = ox(opi,2);
otlen = ox(opi,3);
otp = op(opi);
otxrng = oxrng(opi,:);
otfocpos = reshape(ofocpos(opi,:),[],2);
otzang = ozang(opi,:);
otxr0 = repmat(linspace(otxrng(1),otxrng(2),rptnum),plotposnum,1);
otyr0 = otxr0.^2./(4.*otp);
% savbase(otxr0,otyr0,otzang(plotpos),otfocpos(plotpos,1));
otxr =
rotdnx(otxr0,otyr0,repmat(otzang(plotpos).',1,rptnum),repmat(otfocpos(plotpos,1),1,rptnum
),otp);
otyr =
rotdny(otxr0,otyr0,repmat(otzang(plotpos).',1,rptnum),repmat(otfocpos(plotpos,2),1,rptnum
),otp);
if oth<-otr
otlbinj = 90;
else
otlbinj = min(90,acosd(-oth/otr));
end
otxi0 = otr.*(-sind(linspace(otlbinj,0,20))); %injector x
otyi0 = -sqrt(otr.^2-otxi0.^2); %injector y
if oth>0
otxi0 = [-otr,otxi0];
otyi0 = [oth,otyi0];
end
otxi = [0;0;otxi0(:);0;otxi0(:);0];
otyi = [d-otr;oth;otyi0(:);oth-d;otyi0(:)-d;min(-(otr+otlen),otyi0(end)-d)];
for ri0 = 1:plotposnum
set(reflplot((opi-1)*plotposnum +
ri0),'XData',otxr(ri0,:),'YData',otyr(ri0,:));
end
set(injplot(opi),'XData',otxi,'YData',otyi);
set(effplot(opi),'XData',vangs,'YData',oeffs(opi,:));
end
moxr0 = repmat(linspace(moxrng(1),moxrng(2),rptnum),plotposnum,1);
moyr0 = moxr0.^2./(4.*mop);
300
moxr =
rotdnx(moxr0,moyr0,reshape(repmat(mozang(plotpos),1,rptnum),size(moxr0)),reshape(repmat(m
ofocpos(plotpos,1),1,rptnum),size(moxr0)),mop);
moyr =
rotdny(moxr0,moyr0,reshape(repmat(mozang(plotpos),1,rptnum),size(moxr0)),reshape(repmat(m
ofocpos(plotpos,2),1,rptnum),size(moxr0)),mop);
if mh<-mr
molbinj = 90;
else
molbinj = min(90,acosd(-mh/mr));
end
moxi0 = mr.*(-sind(linspace(molbinj,0,20))); %injector x
moyi0 = -sqrt(mr.^2-moxi0.^2); %injector y
if mh>0
moxi0 = [-mr,moxi0];
moyi0 = [mh,moyi0];
end
moxi = [0;0;moxi0(:);0;moxi0(:);0];
moyi = [d-mr;mh;moyi0(:);mh-d;moyi0(:)-d;min(-(mr+mlen),moyi0(end)-d)];
for ri0 = 1:plotposnum
set(reflplot((numplot-1)*plotposnum +
ri0),'XData',moxr(ri0,:),'YData',moyr(ri0,:));
set(reflplot((numplot )*plotposnum +
ri0),'XData',moxr(ri0,:),'YData',moyr(ri0,:)+d);
end
set(injplot(numplot),'XData',moxi,'YData',moyi);
set(effplot(numplot),'XData',vangs,'YData',moeffs);
title(botax,['Merit Function Value = ' num2str(momert) ' ( Best = ' num2str(mmert(1))
' )']);
drawnow expose;
end
%%
optin = {d, optx(1), optx(2), optx(3), ubvang, optx(4), ndes, vangs, vangwts, wavs,
wavwts, ns, extang, extwt, glen, gthik, Rmirror};
memorizedcalls =
struct('mx','','mmert','','meffs','','mp','','mxrng','','mfocpos','','mzang','','merrcode
','');
memorizedcalls.mx = mx;
memorizedcalls.mmert = mmert;
memorizedcalls.meffs = meffs;
memorizedcalls.mp = mp;
memorizedcalls.mxrng = mxrng;
memorizedcalls.mfocpos = mfocpos;
memorizedcalls.mzang = mzang;
memorizedcalls.merrcode = merrcode;
%%
301
% write summary to excel
try
xlpath = 'C:\Users\Dan\Documents\Thesis\Tracking Window Blind
Concentrator\OptimizationResults_3p1.xlsx';
line1 = {datestr(now),[mfilename('fullpath'),'.m']};
line2 =
{'d','r','h','len','reflht','ubvang','ndes','glen','gthik','Rmirror','function
value','location','material'};
line3p0 = [d,optx(1),optx(2),optx(3),optx(4),ubvang,ndes,glen,gthik,Rmirror,fval];
line3p1 = {locationname,Material.name};
line4t6 = {'lower bounds';'upper bounds';'initial'};
line8 = {'vangs','zang','xfocpos','yfocpos','effs','wavs','wavwts','extang','extwt'};
[~,sheets] = xlsfinfo(xlpath);
shtnam0 = [locationname '_' sprintf('%3.2f',-fval)];
shtnam = shtnam0;
api = 1;
while any(strcmp(shtnam,sheets))
shtnam = [shtnam0 '(' num2str(api) ')'];
api = api + 1;
end
try
xlswrite(xlpath,line1,shtnam,'A1:B1');
catch openspreadsheet
xlpath = 'C:\Users\Dan\Documents\Thesis\Tracking Window Blind
Concentrator\tempoptresults.xlsx';
xlswrite(xlpath,line1,shtnam,'A1:B1');
end
xlswrite(xlpath,line2,shtnam,'A2:M2');
xlswrite(xlpath,line3p0,shtnam,'A3:K3');
xlswrite(xlpath,line3p1,shtnam,'L3:M3');
xlswrite(xlpath,line4t6,shtnam,'A4:A6');
xlswrite(xlpath,[lbnds;ubnds;x0],shtnam,'B4:E6');
xlswrite(xlpath,line8,shtnam,'A8:I8');
optfocpos = reshape(mfocpos(1,:),[],2);
xlswrite(xlpath,[vangs(:),mzang(1,:).',optfocpos(:,1),optfocpos(:,2),meffs(1,:).'],shtnam
,['A9:E' num2str(9+numel(vangs)-1)]);
xlswrite(xlpath,[wavs(:),wavwts(:)],shtnam,['F9:G' num2str(9+numel(wavs)-1)]);
xlswrite(xlpath,[extang(:),extwt(:)],shtnam,['H9:I' num2str(9+numel(extang)-1)]);
catch xlwritefail
warning('Failed to Write Data to Excel');
end
end
302
Tracking Louver Merit Function
Merit function evaluated for all parameters passed from the optimization routine.
function [mert,errcode] =
TWB_MeritFunctionSingleAng3p1(vang,d,r,h,p,x1,x2,zang,x,y,wavs,wavwts,ns,extang,extwt,gle
n,gthik,Rmirror)
% [mert,effs,reflpos,errcode] =
TWB_MeritFunctionSingleAng3p0(vang,d,r,h,p,x1,x2,zang,x,y,ndes,wavs,wavwts,ns,extang,extw
t,glen,gthik,Rmirror)
% Tracking Window Blind 3.0 solar concentrator merit function for single vertical angle
%
% vang = vertical angle
%
% d = spacing between adjacent optics along guide direction
%
% r = injector radius
%
% h = injector extension distance
%
% p = focus distance of parabolic reflector
%
% x1 = x limit of reflector closest to the vertex
%
% x2 = x limit of reflector furthest from vertex
%
% zang = zenith angle of reflector (degrees from vertical optical axis)
%
% x = x focus shift of rotated reflector
%
% y = y focus shift of rotated reflector
%
% wavs = vector of wavelengths to trace
%
% wavwts = weights for wavs input (must sum to 1)
%
% ns = refractive indicies at each given wavlength (wavs)
%
% extang = angles representing extended source (give explicitly, no
% interpretation is used)
%
% extwt = weights for input extang (must sum to 1)
%
% glen = guide length
%
% gthik = guide thickness
%
% Rmirror = reflectivity of primary reflector and injector's reflective surface
%
303
% Output
% mert = merit function value
%
% effs = efficiencies at each vertical angle (reflector position)
%
% p = 'p' in reflector shape equation, y = x^2/(4*p)
%
% focpos = two column matrix with x,y positions of reflector focus
%
% zang = rotation of reflector at each position relative to a vertical optical axis
%
% errcode = error code
%
% Version 3.1 ignores rays that run into back of adjacent reflector while
% heading towards the injection feature.
% close all;
%%%%%%%%%%%%%%%%%%%%%%%%%%% test inputs (from TWB 2.1, Rochester_66.55)
% vang = 34.88442;
% d = 2;
% r = 0.1;
% h = 0.009961;
% p = 1.5187;
% x1 = -1.4952;
% x2 = -3.3687;
% zang = 53.7676;
% x = -0.0444;
% y = -0.0310;
% Material = MaterialDatabase('PMMA');
% ns = Material.data(2,:); % refractive index of material
% wavs = Material.data(1,:); % wavelengths for refractive inicies
% spectralresponse = Material.data(1,:)./1100;
% wavwts = Material.data(3,:).*spectralresponse;
% extang = [0 0.0675 0.135 0.2025 0.27];
% extwt = [0.276625069 0.267537217 0.238138669 0.177976601 0.039722446];
% glen = 300;
% gthik = 13;
% Rmirror = 0.95;
%
% %interpret extang so it is symmetric about 0 and weights sum to unity
% if all(extang>=0) || all(extang<=0)
% extangs = [extang(:);-extang(:)];
% extwts = [extwt(:);extwt(:)];
% [extangs,exti] = unique(extangs);
% extwts = extwts(exti);
% else
% [extangs,exti] = sort(extang(:));
% extwts = reshape(extwt(exti),size(extangs));
% end
% extangs(extangs==0) = 0;
304
% extwts = extwts./sum(extwts(:));
% extang = extangs;
% extwt = extwts;
%
% wavwts = wavwts./sum(wavwts(:));
%%%%%%%%%%%%%%%%%%%%%%%%%%
numray = 100; % number of rays to trace
numwav = numel(wavs);
numext = numel(extang);
y1 = x1^2/(4*p); % y's for reflector endpoints given x's (rotated space)
y2 = x2^2/(4*p);
dang = (90-vang)-zang; % difference in incident vertical zenith angle and actual
reflector zenith rotation due to collision with guide
% transfer functions between vertical optical axis and actual position
rotdnx = @(x,y,zenang,xinj) x.*cosd(zenang) - (y-p).*sind(zenang) + xinj;
rotdny = @(x,y,zenang,yinj) x.*sind(zenang) + (y-p).*cosd(zenang) + yinj;
rotupx = @(x,y,zenang,xinj,yinj) (x-xinj).*cosd(-zenang) - (y-yinj).*sind(-zenang);
rotupy = @(x,y,zenang,xinj,yinj) (x-xinj).*sind(-zenang) + (y-yinj).*cosd(-zenang) + p;
% parabola intersection functions
parpos = @(x0,y0,m) (m + sqrt(m.^2 - (m.*x0-y0)./p)).*(2*p); % x '+' solution
parneg = @(x0,y0,m) (m - sqrt(m.^2 - (m.*x0-y0)./p)).*(2*p); % x '-' solution
pary = @(x) x.^2./(4*p); % y given x
% error out if bottom point of reflector impinges on guide layer
if rotdnx(x1,y1,zang,x) > 0
%error and exit function
mert = 0;
errcode = 'guide-reflector collision';
return;
end
% error out if reflector infringes on adjacent injector or guide surface
if h<0
lbinj = acosd(-h/r);
else
lbinj = 90;
end
injlimx = rotupx(-r.*sind(lbinj),h-d,zang,x,y);
injlimy = rotupy(-r.*sind(lbinj),h-d,zang,x,y);
parinjx = parneg(injlimx,injlimy,cotd(zang));
botx = rotdnx(x1,y1,zang,x);
if any(parinjx<x1 & parinjx>x2 & parinjx<injlimx) || botx>0
%error and exit function
mert = 0;
errcode = 'injector-reflector or guide-reflector collision';
return;
305
end
% initiate ray position, direction, and weight variables
init0 = zeros([numext,numray,numwav]);
rx = struct('start',init0(:,:,1),'refl',init0(:,:,1),'inj',init0(:,:,1),'gid',init0);
ry = struct('start',init0(:,:,1),'refl',init0(:,:,1),'inj',init0(:,:,1),'gid',init0);
rdx = struct('start',init0(:,:,1)+1,'refl',init0(:,:,1)+1,'inj',init0+1,'gid',init0+1);
rdy = struct('start',init0(:,:,1),'refl',init0(:,:,1),'inj',init0,'gid',init0);
wt = struct('start',init0(:,:,1),'refl',init0(:,:,1),'inj',init0,'gid',init0);
Extangs = repmat(extang(:),[1,numray,numwav]);
Incangs = vang + Extangs;
N = repmat(reshape(ns,1,1,[]),[numext,numray,1]);
% find initial weights based on how filled the aperture is with rays that strike the
reflector
% top point of reflector
topx = rotdnx(x2,y2,zang,x);
topy = rotdny(x2,y2,zang,y);
% bottom point of reflector
boty = rotdny(x1,y1,zang,y);
% find points where incident rays (vang,extang) are tangent to the reflector
tanrx0 = x2 .* ones(size(init0(:,1,1)));
tanrinc = 90 + dang - Extangs(:,1,1);
tanrx0(tanrinc~=Inf) = 2.*p.*tand(tanrinc(tanrinc~=Inf));
tanrx0(tanrx0<x2 | tanrx0>0) = x2;
tanrx0(tanrx0<=0 & tanrx0>x1) = x1;
tanry0 = pary(tanrx0);
tanrx = rotdnx(tanrx0,tanry0,zang,x);
tanry = rotdny(tanrx0,tanry0,zang,y);
% find points where incident rays are tangent to injector
tanix = -r.*sind(Incangs(:,1,1));
taniy = -r.*cosd(Incangs(:,1,1));
% project points back to aperture
apboty = -tand(Incangs(:,1,1)).*(topx-botx)+boty;
aptanry = d-tand(Incangs(:,1,1)).*(topx-tanrx)+tanry;
aptaniy = -tand(Incangs(:,1,1)).*(topx-tanix)+taniy;
% fraction of aperture filled (wt.start) and starting ray positions/directions
aphi = min( topy+d, min(cat(2,apboty,aptanry,aptaniy),[],2) );
aprng = aphi-topy;
wt.start = repmat(max(0,aprng)./d./numray,[1,numray]);
rx.start = topx.*ones(size(wt.start));
rx.start(wt.start==0) = 0;
ystrtseed = repmat(linspace(0+(1/numray/100),1-(1/numray/100),numray),[numext,1]);
ry.start = ystrtseed.*repmat(aprng,[1,numray]) + topy;
ry.start(wt.start==0) = 0;
rdx.start = cosd(Incangs(:,:,1));
rdx.start(wt.start==0) = 1;
rdy.start = -sind(Incangs(:,:,1));
rdy.start(wt.start==0) = 0;
306
% find ray starting positions and slopes in rotated space
rprx = rotupx(rx.start,ry.start,zang,x,y); % Ray Position in Rotated space, X component
rpry = rotupy(rx.start,ry.start,zang,x,y); % Ray Position in Rotated space, Y component
mr = tand(90+dang-Extangs(:,:,1)); % ray slopes in rotated space
% find where rays intersect reflector
pixi = zeros(size(init0(:,:,1))); % ray-Parabola Intersection, X component
pixi(sign(mr)>0) = parneg(rprx(sign(mr)>0),rpry(sign(mr)>0),mr(sign(mr)>0));
pixi(sign(mr)<0) = parpos(rprx(sign(mr)<0),rpry(sign(mr)<0),mr(sign(mr)<0));
pixi(abs(mr)==Inf) = rprx(abs(mr)==Inf);
pix = real(pixi);
piy = pary(pix); % ray-Parabola Intersection, Y component
wt.refl = Rmirror.*wt.start;
wt.refl(pix<x2 | pix>x1 | imag(pixi)~=0) = 0;
rx.refl = rotdnx(pix,piy,zang,x);
ry.refl = rotdny(pix,piy,zang,y);
% find normal vectors at reflector intersection points
nvrx = -sqrt(1./(1+1./(pix./(2.*p)).^2)); % Normal Vector in Rotated space, X component
nvry = -sqrt(1-nvrx.^2);
nvx = nvrx.*cosd(zang) - nvry.*sind(zang); % Normal Vector, X component
nvy = nvrx.*sind(zang) + nvry.*cosd(zang);
% find reflected vectors
rvtemp =
refl([rdx.start(logical(wt.refl)),rdy.start(logical(wt.refl))],[nvx(logical(wt.refl)),nvy
(logical(wt.refl))]);
rdx.refl = rdx.start;
rdy.refl = rdy.start;
rdx.refl(logical(wt.refl)) = rvtemp(:,1);
rdy.refl(logical(wt.refl)) = rvtemp(:,2);
% find if and where rays intersect injection feature
mext = rdy.refl./rdx.refl; % ray slopes
bext = ry.refl - mext.*rx.refl; % ray y-intercepts
aquad = 1+mext.^2; % "a" of quadratic formula
bquad = 2.*mext.*bext; % "b" of quadratic formula
cquad = bext.^2-r.^2; % "c" of quadratic formula
disext = bquad.^2 - 4.*aquad.*cquad; % quadratic formula discriminant
xinj = real((-bquad - sign(rdx.refl).*sqrt(disext))./(2.*aquad));
xinj(abs(mext)==Inf) = rx.refl(abs(mext)==Inf);
yinj = mext.*xinj+bext;
% find rays that strike rear of adjacent reflector
x12ap = rotdnx([x1,x2],[y1,y2],zang,x);
y12ap = rotdny([x1,x2],[y1,y2],zang,y)+d;
% x12a = rotupx(x12ap,y12ap+d,zang,0,0); % x component of adjacent reflector endpoints in
rotated space
% y12a = rotupy(x12ap,y12ap+d,zang,0,0); % y component of adjacent reflector endpoints in
rotated space
ma = diff(y12ap)./diff(x12ap); % slope between reflector endpoints
mdif0 = ma-mext;
307
mdif = mdif0;
mdif(mdif0==0) = 1;
xinta = (ma.*x12ap(1)-y12ap(1)+bext)./mdif;
yinta = ma.*(xinta-x12ap(1))+y12ap(1);
bakrefl = xinta>x12ap(2) & xinta<x12ap(1);
bakrefl(mdif0==0) = false;
bakrefl(yinta>h) = false;
% flag rays that strike the injection feature
hitcyl = xinj<0 & xinj>=-sind(lbinj) & yinj<=0 & disext>=0 & ~bakrefl;
rx.inj(hitcyl) = xinj(hitcyl);
ry.inj(hitcyl) = yinj(hitcyl);
wrep = @(in) repmat(in,[1,1,numwav]);
wt.inj = wrep(wt.refl);
wt.inj(~wrep(hitcyl)) = 0;
% figure();
% plot(x12ap(:),y12ap(:),'linewidth',3,'color','r');
% if any(any(logical(wt.inj(:,:,1))))
%
line([rx.refl(logical(wt.inj(:,:,1))).';rx.inj(logical(wt.inj(:,:,1))).'],[ry.refl(logica
l(wt.inj(:,:,1))).';ry.inj(logical(wt.inj(:,:,1))).']);
% end
% if any(bakrefl(:));
% line([rx.refl(bakrefl).';xinta(bakrefl).'],[ry.refl(bakrefl).';yinta(bakrefl).']);
% end
% title(num2str(vang));
% refract rays
goon = logical(wt.inj);
wrdxrefl = wrep(rdx.refl);
wrdyrefl = wrep(rdy.refl);
wrxinj = wrep(rx.inj);
wryinj = wrep(ry.inj);
[refrtemp,refrT] = refractfres([wrdxrefl(goon),wrdyrefl(goon)],[-wrxinj(goon),-
wryinj(goon)],1,N(goon));
rdx.inj(goon) = refrtemp(:,1);
rdy.inj(goon) = refrtemp(:,2);
wt.inj(goon) = wt.inj(goon).*refrT;
% trace rays to guide surface
ry.gid = wrep(ry.inj)-rdy.inj./rdx.inj.*wrep(rx.inj);
wt.gid = wt.inj;
wt.gid( ry.gid<-r | ry.gid>2*h+r ) = 0;
wt.gid(ry.gid>h) = wt.gid(ry.gid>h).*Rmirror;
rdx.gid = rdx.inj;
rdy.gid = rdy.inj;
rdy.gid(ry.gid>h) = -rdy.gid(ry.gid>h);
ry.gid(ry.gid>h) = 2*h - ry.gid(ry.gid>h);
wt.gidc = wt.gid;
wt.gidc(abs(rdy.gid./rdx.gid)<1./sqrt(N.^2-1)) = 0; % zero weight for rays above guide
critical angle
308
% trace through guide
gR = 1-(r+h)/d; % meta-Reflectance of lossy guide surface
loledist0 = abs(2.*rdy.gid.*gthik./rdx.gid); % distance rays travel without interacting
with lossy guide surface
grays = logical(wt.gidc) & loledist0<=glen;
loledist = loledist0(grays);
gN = floor(glen./loledist); % number of interactions with lossy guide surface while
traversing full guide length
gf = glen./loledist - gN; % remainder of guide length / lossless distance after last
interaction (gN)
wt.end = wt.gidc;
wt.end(grays) = wt.end(grays) .* ((1-gR.^gN)./(1-gR) + gf.*gR.^gN) ./ (gN+gf); % ray
weights averaged over guide length (geometric series
http://en.wikipedia.org/wiki/Summation#Some_summations_involving_exponential_terms)
% find efficiency and function output
eff2 = sum(repmat(reshape(wavwts,1,1,[]),[numext,numray,1]).*wt.end,3); % weighted
average over wavelengths
eff1 = sum(eff2,2); % sum over rays
eff = sum(extwt(:).*eff1); % weighted average over extended angles
mert = -eff; % merit value = negative efficiency
errcode = '';
%
% end
Dependency: VerticalAngleWeightCalculator.m
Calculates vertical angle weighting function for a given location.
function wtdt = VerticalAngleWeightCalculator(vangs,lat,hitemps,lotemps)
% vang = 20; %vertical angle
% lat = 43.12; %latitude
snum = 1000; %number of samples
%create sample points
sang = linspace(0,90,snum);
vang = vangs(:);
[Sang,Vang] = meshgrid(sang,vang);
Ls = sind(Vang-(90-lat)).*cosd(Sang);
%find the two corresponding days of the year (np,nn) for each sample point
np = 365.25./360.*acosd(Ls./(-sind(23.45))) - 10;
np(abs(Ls)>sind(23.45)) = 400;
np = mod(floor(np),365);
np(abs(Ls)>sind(23.45)) = 400;
nn = mod(-(np+10),365)-10;
nn = mod(nn,365);
309
nn(abs(Ls)>sind(23.45)) = 400;
%find temperature for each day
hitemp = [hitemps(end),hitemps,hitemps(1)]; % average monthly highs (farenheit) from
Dec,00 to Jan,02
lotemp = [lotemps(end),lotemps,lotemps(1)]; % average monthly lows (farenheit)
avtemp = (hitemp+lotemp)./2;
ntemp = [-17 15 46 74 105 135 166 196 227 258 288 319 349 380]; % day number for
temperature data points
tp = interp1(ntemp,avtemp,np,'pchip'); %interpolate temperature for each sample point
(np)
tn = interp1(ntemp,avtemp,nn,'pchip');
toutF = (tp+tn)./2; % average temp for both days corresponding to each sample point
toutC = (toutF-32).*5./9; % convert to celcius
% dtC = max(0,20-toutC);
dtC = 20-toutC; % differential temp in celcius/kelvin
dtC(abs(Ls)>sind(23.45)) = 0;
%find projected area for each sample point
pA = cosd(Vang).*cosd(Sang);
%weighted differential temperature output
wtdt = mean(dtC.*pA,2);
wtdt = reshape(wtdt,size(vangs));
save_to_base(1);
end
Dependency: SL_SingleSegment_BuildLT.m
Automates process of creating optimized louver geometry in LightTools (Synopsys)
optical design software.
function [] = SL_SingleSegment_BuildLT(injpos,shape,endptx,d,Rmirror,backrefl)
thickness = 0.02; % thickness of reflector
wid = 100; % extruded length of reflector
gleni = d; % default half length of guide
h = injpos(4,2); % injector height
gthiki = h; % default guide thickness
zpos = endptx./2; % z position of segment
ypos = shape(end); % y position of segment
LTconame = cell(size(shape(1:end-1)));
LTconum = length(shape)-1:-1:1;
for cn = 1:length(shape)-1
LTconame{cn} = ['Y' num2str(length(shape)-cn)];
end
310
% set up activexservers
lt = actxserver('LightTools.LTAPI3');
ltml = actxserver('ltcom64.LTAPI2');
try
%start LightTools interop
retcod = ltml.LTBegin(lt);
%delete old copy of injection feature if it exists
einjLK = ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','SOLID');
ename = 'InjectionFeature_1';
[einjDK, s_einjdk] = ltml.LTListByName(lt, einjLK, ename);
if ~strcmp(s_einjdk, 'LTReturnCodeEnum_ltStatusInvalidDataAccessString')
en = ltml.LTDbKeyStr(lt,einjDK);
ltml.LTCmd(lt, ['\O' en ' ']);
ltml.LTCmd(lt, 'Delete= ');
ltml.LTCmd(lt, '\Q ');
end
ltml.LTListDelete(lt, einjLK);
clear einjLK einjDK
%build extruded injection feature
ipts = [injpos(1,:)+[0.01,0];injpos(1:3,:);injpos(4,:)+[0.01,0]];
ltcmdstr = 'ExtrudedPrism';
for nm = 1:size(ipts,1);
ltcmdstr = [ltcmdstr ' XYZ ' num2str(-wid/2) ',' num2str(ipts(nm,2)) ','
num2str(ipts(nm,1))];
end
for doubleclick = 1:2
ltcmdstr = [ltcmdstr ' XYZ ' num2str(wid/2) ',' num2str(ipts(end,2)) ','
num2str(ipts(end,1))];
end
ltml.LTCmd(lt, ltcmdstr);
%name injection feature
extruLK = ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','SOLID');
extruDK = ltml.LTListLast(lt, extruLK);
ltml.LTDbSet(lt, extruDK, 'Name', 'InjectionFeature_1');
ltml.LTDbSet(lt, extruDK, 'Material', 'PMMA_USER');
%add optical properties if need be
opropLK = ltml.LTDbList(lt,'LENS_MANAGER[1].PROPERTY_MANAGER[Optical Properties
Manager]','PROPERTY');
[fresDK, s_splitdk] = ltml.LTListByName(lt,opropLK,'FresLoss');
[reflDK, s_refldk] = ltml.LTListByName(lt,opropLK,'ReflPart');
if strcmp(s_splitdk, 'LTReturnCodeEnum_ltStatusInvalidDataAccessString')
ltml.LTDbSet(lt, 'LENS_MANAGER[1].PROPERTY_MANAGER[Optical Properties Manager]',
'AddNew', 'FresLoss');
end
if strcmp(s_refldk, 'LTReturnCodeEnum_ltStatusInvalidDataAccessString')
311
ltml.LTDbSet(lt, 'LENS_MANAGER[1].PROPERTY_MANAGER[Optical Properties Manager]',
'AddNew', 'ReflPart');
end
if strcmp(s_splitdk, 'LTReturnCodeEnum_ltStatusInvalidDataAccessString') ||
strcmp(s_refldk, 'LTReturnCodeEnum_ltStatusInvalidDataAccessString')
ltml.LTListDelete(lt, opropLK);
opropLK = ltml.LTDbList(lt,'LENS_MANAGER[1].PROPERTY_MANAGER[Optical Properties
Manager]','PROPERTY');
[fresDK, s_splitdk] = ltml.LTListByName(lt,opropLK,'FresLoss');
[reflDK, s_refldk] = ltml.LTListByName(lt,opropLK,'ReflPart');
end
FresLossFN = 'C:\Users\Dan\Documents\Thesis\Suspended Louver\SL_FresLoss.1.opr';
ReflPartFN = 'C:\Users\Dan\Documents\Thesis\Suspended Louver\SL_ReflPart.1.opr';
ltml.LTDbSet(lt, fresDK, 'Load_Properties', FresLossFN);
ltml.LTDbSet(lt, reflDK, 'Load_Properties', ReflPartFN);
ltml.LTDbSet(lt, reflDK, 'Reflectance_Percent', 100*Rmirror);
%get injection feature zone data keys
zoneLK = ltml.LTDbList(lt,extruDK,'ZONE');
zonenum = ltml.LTListSize(lt,zoneLK);
if ischar(zonenum)
zonenum = LTisStupid(zonenum);
end
zoneDK = cell(zonenum,1);
for ki = 1:zonenum
zoneDK{ki} = ltml.LTListNext(lt, zoneLK);
end
% apply optical properties to surfaces
ltml.LTSetOption(lt, 'DBUPDATE', 0);
for sn = 1:numel(zoneDK)
ltml.LTDbSet(lt, zoneDK{sn}, 'PropertyName', 'FresLoss');
end
ltml.LTDbSet(lt, zoneDK{4}, 'PropertyName', 'ReflPart');
ltml.LTSetOption(lt, 'DBUPDATE', 1);
%%
%delete old copy of guide if it exists
egidLK = ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','SOLID');
gname = 'Guide_1';
[egidDK, s_egiddk] = ltml.LTListByName(lt, egidLK, gname);
if ~strcmp(s_egiddk, 'LTReturnCodeEnum_ltStatusInvalidDataAccessString')
gn = ltml.LTDbKeyStr(lt,egidDK);
ltml.LTCmd(lt, ['\O' gn ' ']);
ltml.LTCmd(lt, 'Delete= ');
ltml.LTCmd(lt, '\Q ');
end
ltml.LTListDelete(lt, egidLK);
clear egidLK egidDK
%build guide
312
gpts = [0,h/2; 0,h/2+gleni; gthiki,h/2];
ltcmdstrgid = 'Block3pt';
for mn = 1:size(gpts,1);
ltcmdstrgid = [ltcmdstrgid ' XYZ 0,' num2str(gpts(mn,2)) ','
num2str(gpts(mn,1))];
end
ltml.LTCmd(lt, ltcmdstrgid);
%name guide and assign material
gidLK = ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','SOLID');
gidDK = ltml.LTListLast(lt, gidLK);
ltml.LTDbSet(lt, gidDK, 'Name', 'Guide_1');
ltml.LTDbSet(lt, gidDK, 'Material', 'PMMA_USER');
%set guide width
[gprimLK, s_gprimlk] =
ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','CUBE_PRIMITIVE');
gprimDK = ltml.LTListLast(lt, gprimLK);
ltml.LTDbSet(lt, gprimDK, 'Width', wid);
ltml.LTListDelete(lt,gprimLK);
clear gprimLK s_gprimlk gprimDK;
%get injection feature zone data keys
gzoneLK = ltml.LTDbList(lt,gidDK,'ZONE');
gzonenum = ltml.LTListSize(lt,gzoneLK);
if ischar(gzonenum)
gzonenum = LTisStupid(gzonenum);
end
gzoneDK = cell(gzonenum,1); % {LeftSurface; BackSurface; TopSurface; FrontSurface;
BottomSurface; RightSurface}
for gi = 1:gzonenum
gzoneDK{gi} = ltml.LTListNext(lt, gzoneLK);
end
% apply optical properties to surfaces
ltml.LTSetOption(lt, 'DBUPDATE', 0);
for gz = 1:numel(gzoneDK)
ltml.LTDbSet(lt, gzoneDK{gz}, 'PropertyName', 'FresLoss');
end
ltml.LTDbSet(lt, gzoneDK{3}, 'PropertyName', 'Optical Absorber');
ltml.LTDbSet(lt, gzoneDK{5}, 'PropertyName', 'Optical Absorber');
ltml.LTSetOption(lt, 'DBUPDATE', 1);
%%
%delete currently existing blades if they exist
esolidLK = ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','SOLID');
bname = {'Blade_1';'Blade_2'};
for bd = 1:2
[ebladedk, s_ebladedk] = ltml.LTListByName(lt, esolidLK, bname{bd});
if ~strcmp(s_ebladedk, 'LTReturnCodeEnum_ltStatusInvalidDataAccessString')
313
bn = ltml.LTDbKeyStr(lt,ebladedk);
ltml.LTCmd(lt, ['\O' bn ' ']);
ltml.LTCmd(lt, 'Delete= ');
ltml.LTCmd(lt, '\Q ');
end
end
ltml.LTListDelete(lt, esolidLK);
%create base lens with the correct width and xyz position
pt1 = ltml.LTCoord3(lt, 0, ypos, zpos);
pt2 = ltml.LTCoord3(lt, 0, ypos+abs(endptx)./2, zpos);
pt3 = ltml.LTCoord3(lt, 0, ypos+abs(endptx)./2, zpos+thickness);
pt4 = ltml.LTCoord3(lt, 0, ypos-thickness, zpos);
ltml.LTCmd(lt, ['Sketch3PtLens ' pt1 ' ' pt2 ' ' pt3 ' ' pt4]);
[solidLK, s_solidlk] =
ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','SOLID');
solidDK = ltml.LTListLast(lt, solidLK);
%get datakey of newly created lens
%LK suffix stands for 'listkey'
%DK suffix stands for 'datakey'
[solidLK, s_solidlk] =
ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','SOLID');
solidDK = ltml.LTListLast(lt, solidLK);
[primLK, s_primlk] =
ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','CIRC_LENS_PRIMITIVE');
primDK = ltml.LTListLast(lt, primLK);
[surfLK, s_surflk] =
ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','SPHERICAL_LENS_SURFACE');
[numsurf, s_numsurf] = ltml.LTListSize(lt, surfLK);
if ischar(numsurf)
numsurf = LTisStupid(numsurf);
end
if ischar(numsurf)
ltml.LTCmd(lt, 'Undo');
retcod = ltml.LTEnd(lt);
error('craps')
end
rc_setpos = ltml.LTListSetPos(lt, surfLK, numsurf-1);
surf1DK = ltml.LTListNext(lt, surfLK); % LensFrontSurface
surf2DK = ltml.LTListNext(lt, surfLK); % LensRearSurface
%create reflector optical property if need be
[OpropLK, s_oproplk] = ltml.LTDbList(lt,'LENS_MANAGER[1].PROPERTY_MANAGER[Optical
Properties Manager]','PROPERTY');
[wbreflDK, s_wbrefldk] = ltml.LTListByName(lt,OpropLK,'WBreflector');
if strcmp(s_wbrefldk, 'LTReturnCodeEnum_ltStatusInvalidDataAccessString')
314
ltml.LTDbSet(lt, 'LENS_MANAGER[1].PROPERTY_MANAGER[Optical Properties Manager]',
'AddNew', 'WBreflector');
ltml.LTListDelete(lt, OpropLK);
[OpropLK, s_oproplk] = ltml.LTDbList(lt,'LENS_MANAGER[1].PROPERTY_MANAGER[Optical
Properties Manager]','PROPERTY');
[wbreflDK, s_wbrefldk] = ltml.LTListByName(lt,OpropLK,'WBreflector');
end
WBreflectorFN = 'C:\Documents and Settings\Dan\My Documents\Rambus Ideas\High FoV
Lightguide\Windowblind Reflector\WBreflector.1.opr';
ltml.LTDbSet(lt, wbreflDK, 'Load_Properties', WBreflectorFN);
ltml.LTListDelete(lt, OpropLK);
clear OpropLK OpropDK
%delete zones and apply correct angle and surface shape to each segment
ltml.LTSetOption(lt, 'DBUPDATE', 0);
%delete zones
znf = ltml.LTDbKeyStr(lt, surf1DK);
znb = ltml.LTDbKeyStr(lt, surf2DK);
ltml.LTCmd(lt, ['\O' znf '.ZONE[zone_1] ']);
ltml.LTCmd(lt, '"Delete Zone"= ');
ltml.LTCmd(lt, '\Q ');
ltml.LTCmd(lt, ['\O' znb '.ZONE[zone_1] ']);
ltml.LTCmd(lt, '"Delete Zone"= ');
ltml.LTCmd(lt, '\Q ');
%set element shape
ltml.LTDbSet(lt, primDK, 'Element_Shape', 'Rectangular');
ltml.LTDbSet(lt, primDK, 'Width', wid);
%front and rear surface modifications
ltml.LTDbSet(lt, surf1DK, 'Surface_Shape', 'XYPolynomial');
ltml.LTDbSet(lt, surf1DK, 'Concave', 'CC');
ltml.LTDbSet(lt, surf2DK, 'Surface_Shape', 'XYPolynomial');
ltml.LTDbSet(lt, surf2DK, 'Concave', 'CX');
for co = 1:length(LTconame)
ltml.LTDbSet(lt, surf1DK, LTconame{co}, (-1).^LTconum(co).*shape(co));
ltml.LTDbSet(lt, surf2DK, LTconame{co}, shape(co));
end
ltml.LTSetOption(lt, 'DBUPDATE', 1);
ltml.LTSetOption(lt, 'DBUPDATE', 0);
ltml.LTDbSet(lt, surf1DK, 'Y_Decenter', -zpos);
ltml.LTDbSet(lt, surf2DK, 'Y_Decenter', -zpos);
ltml.LTSetOption(lt, 'DBUPDATE', 1);
%get zone data keys and apply optical properties
zoneDK = cell(1,6); %LensFrontSurface:bare, LensRearSurface:bare, TopSurface:bare,
BackSurface:bare, FrontSurface:bare, BottomSurface:bare
segsolid = ltml.LTDbKeyStr(lt, solidDK);
[zoneLK, s_zonelk] = ltml.LTDbList(lt,segsolid,'ZONE'); %List Key for segment using
"ZONE" filter
zoneDK{1} = ltml.LTListNext(lt, zoneLK); %LensFrontSurface
zoneDK{2} = ltml.LTListNext(lt, zoneLK); %LensRearSurface
315
zoneDK{3} = ltml.LTListNext(lt, zoneLK); %TopSurface
zoneDK{4} = ltml.LTListNext(lt, zoneLK); %BackSurface
zoneDK{5} = ltml.LTListNext(lt, zoneLK); %FrontSurface
zoneDK{6} = ltml.LTListNext(lt, zoneLK); %BottomSurface
ltml.LTSetOption(lt, 'DBUPDATE', 0);
ltml.LTDbSet(lt, zoneDK{1}, 'PropertyName', 'ReflPart');
ltml.LTDbSet(lt, zoneDK{2}, 'PropertyName', 'Optical Absorber');
if backrefl
ltml.LTDbSet(lt, zoneDK{2}, 'PropertyName', 'ReflPart');
end
ltml.LTSetOption(lt, 'DBUPDATE', 1);
% select new lens
sntemp = ltml.LTDbKeyStr(lt, solidDK);
snpos = strfind(sntemp, '[');
solidname = sntemp(max(snpos)+1:end-1);
ltml.LTListDelete(lt, solidLK);
clear solidLK solidDK
ltml.LTCmd(lt, ['DefaultSelect "' solidname '.tag_0" ']);
ltml.LTCmd(lt, ['CopyVector XYZ 0,0,0 XYZ 0,' num2str(d) ',0 ']);
[solidLK, s_solidlk] =
ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','SOLID');
[numsolid, s_numsolid] = ltml.LTListSize(lt, solidLK);
if ischar(numsolid)
numsolid = LTisStupid(numsolid);
end
rc_setpos1 = ltml.LTListSetPos(lt, solidLK, numsolid-1);
solidDK1 = ltml.LTListNext(lt, solidLK);
solidDK2 = ltml.LTListNext(lt, solidLK);
ltml.LTDbSet(lt, solidDK1, 'Name', 'Blade_1');
ltml.LTDbSet(lt, solidDK2, 'Name', 'Blade_2');
% put parameters into LT variable: 'SLscript'
paramname = 'SLscript';
paramvals = 0;
paramdesc = [sprintf('%s.m, %s, endptx=%.6g, d=%.6g, Rmirror=%.6g, shape=%.6g',
mfilename, datestr(now), endptx, d, Rmirror, shape(1)), sprintf('%.6g,',shape(2:end))];
%find if parameter exists
[paramLK, s_paramlk] =
ltml.LTDbList(lt,'LENS_MANAGER[1].PARAMETRIC_CONTROLS[Parametric_Controls]','NUMERIC_PARA
METER');
[paramDK, s_paramdk] = ltml.LTListByName(lt, paramLK, paramname);
if strcmp(s_paramdk, 'LTReturnCodeEnum_ltStatusInvalidDataAccessString')
ltml.LTListDelete(lt, paramLK);
ltml.LTCmd(lt, ['AddParameter "' paramname '" 1 ""']);
[paramLK, s_paramlk] =
ltml.LTDbList(lt,'LENS_MANAGER[1].PARAMETRIC_CONTROLS[Parametric_Controls]','NUMERIC_PARA
METER');
316
[paramDK, s_paramdk] = ltml.LTListByName(lt, paramLK, paramname);
end
ltml.LTDbSet(lt, paramDK, 'Value', paramvals);
ltml.LTDbSet(lt, paramDK, 'Description', paramdesc);
%%
%delete old copy of source if it exists
esrcLK =
ltml.LTDbList(lt,'LENS_MANAGER[1].ILLUM_MANAGER[Illumination_Manager]','SOURCES');
sname = 'Source_1';
[esrcDK, s_esrcdk] = ltml.LTListByName(lt, esrcLK, sname);
if ~strcmp(s_esrcdk, 'LTReturnCodeEnum_ltStatusInvalidDataAccessString')
sn = ltml.LTDbKeyStr(lt,esrcDK);
ltml.LTCmd(lt, ['\O' sn ' ']);
ltml.LTCmd(lt, 'Delete= ');
ltml.LTCmd(lt, '\Q ');
end
ltml.LTListDelete(lt, esrcLK);
clear esrcLK esrcDK
%build source
y0 = polyval(shape,endptx);
spts = [endptx-0.1,y0+d/2; endptx-0.1,y0+d; endptx,y0+d/2];
ltcmdstrsrc = 'CubeSource';
for sm = 1:size(spts,1);
ltcmdstrsrc = [ltcmdstrsrc ' XYZ 0,' num2str(spts(sm,2)) ','
num2str(spts(sm,1))];
end
ltml.LTCmd(lt, ltcmdstrsrc);
%name guide and assign material
srcLK =
ltml.LTDbList(lt,'LENS_MANAGER[1].ILLUM_MANAGER[Illumination_Manager]','CUBE_SURFACE_SOUR
CE');
srcDK = ltml.LTListLast(lt, srcLK);
ltml.LTDbSet(lt, srcDK, 'Name', 'Source_1');
ltml.LTDbSet(lt, srcDK, 'Power Extent', 'Aim Region');
ltml.LTDbSet(lt, srcDK, 'Width', wid);
for jk = 1:5
ltml.LTDbSet(lt, srcDK, 'EmittingAt', 'No', jk);
end
srcKS = ltml.LTDbKeyStr(lt,srcDK);
srcasLK = ltml.LTDbList(lt,srcKS,'AIM_SPHERE');
srcasDK = ltml.LTListLast(lt, srcasLK);
ltml.LTDbSet(lt, srcasDK, 'Lower Angle', 0);
ltml.LTDbSet(lt, srcasDK, 'Alpha', -20);
%set guide width
[gprimLK, s_gprimlk] =
ltml.LTDbList(lt,'LENS_MANAGER[1].COMPONENTS[Components]','CUBE_PRIMITIVE');
gprimDK = ltml.LTListLast(lt, gprimLK);
317
ltml.LTDbSet(lt, gprimDK, 'Width', wid);
ltml.LTListDelete(lt,gprimLK);
clear gprimLK s_gprimlk gprimDK;
%get injection feature zone data keys
gzoneLK = ltml.LTDbList(lt,gidDK,'ZONE');
gzonenum = ltml.LTListSize(lt,gzoneLK);
if ischar(gzonenum)
gzonenum = LTisStupid(gzonenum);
end
gzoneDK = cell(gzonenum,1); % {LeftSurface; BackSurface; TopSurface; FrontSurface;
BottomSurface; RightSurface}
for gi = 1:gzonenum
gzoneDK{gi} = ltml.LTListNext(lt, gzoneLK);
end
% apply optical properties to surfaces
ltml.LTSetOption(lt, 'DBUPDATE', 0);
for gz = 1:numel(gzoneDK)
ltml.LTDbSet(lt, gzoneDK{gz}, 'PropertyName', 'FresLoss');
end
ltml.LTDbSet(lt, gzoneDK{3}, 'PropertyName', 'Optical Absorber');
ltml.LTDbSet(lt, gzoneDK{5}, 'PropertyName', 'Optical Absorber');
ltml.LTSetOption(lt, 'DBUPDATE', 1);
%%
retcod = ltml.LTEnd(lt);
save_to_base(1);
disp('done');
catch LTerror
retcod = ltml.LTEnd(lt);
error('error in LT portion of matlab code');
end
end
Dependency: LocationWeatherDatabase.m
Database of weather data for given location: Rochester, El Paso, and Fairbanks.
function [lat,hitemps,lotemps,epwfn,synDHIconst,cleardayDNI,lon,tmz] =
LocationWeatherDatabase(locstr)
% [lat,hitemps,lotemps,epwfn] = locationweatherdatabase(locstr)
% Accepts location name and returns latitude, average monthly high temperatures,
% average monthly low temperatures (www.weather.com), and a string containing
% the file path to the .epw weather data file
% (http://apps1.eere.energy.gov/buildings/energyplus/weatherdata_about.cfm)
%
% Acceptable locations include 'Rochester', 'El Paso', 'Fairbanks'
318
switch locstr
case 'Rochester'
lat = 43.12; % latitude
hitemps = [32 34 43 56 68 77 81 79 72 60 48 37]; % average monthly highs
(farenheit) www.weather.com
lotemps = [18 19 26 37 46 56 61 60 52 42 33 24]; % average monthly lows
(farenheit) www.weather.com
epwfn = 'C:\Users\Dan\Documents\Thesis\Weather Data\USA_NY_Rochester-
Greater.Rochester.Intl.AP.725290_TMY.epw';
synDHIconst = 200; % synthetic sunny case DHI (W/m2) judged by average sunny day
from TMY data
cleardayDNI = 893;
lon = -77.67;
tmz = -5;
case 'El Paso'
lat = 31.77; % latitude
hitemps = [58 63 70 79 88 96 95 93 88 78 66 57]; % average monthly highs
(farenheit) www.weather.com
lotemps = [33 37 43 51 60 68 71 70 63 52 40 33]; % average monthly lows
(farenheit) www.weather.com
epwfn = 'C:\Users\Dan\Documents\Thesis\Weather
Data\USA_TX_El.Paso.Intl.AP.722700_TMY3.epw';
synDHIconst = 200;
cleardayDNI = 1000;
lon = -106.50;
tmz = -7;
case 'Fairbanks'
lat = 64.82; % latitude
hitemps = [ 3 11 25 44 61 71 72 66 54 32 12 07]; % average monthly highs
(farenheit) www.weather.com
lotemps = [-11 -7 2 21 36 48 51 45 34 16 -2 -8]; % average monthly lows
(farenheit) www.weather.com
epwfn = 'C:\Users\Dan\Documents\Thesis\Weather
Data\USA_AK_Fairbanks.Intl.AP.702610_TMY3.epw';
synDHIconst = 200; % re-evaluate for Fairbanks !!!!!!!!!!!!!!!!!!!!!!!!!!
cleardayDNI = 893; % re-evaluate for Fairbanks !!!!!!!!!!!!!!!!!!!!!!!!!!
lon = -147.85;
tmz = -9;
otherwise
error('Location (locstr) not recognized. Note: string is case sensitive.');
end
Dependency: MaterialDatabase.m
Callable database of dispersive dielectric material information.
function [Material] = MaterialDatabase(materialname)
if ~any(strcmp(materialname,{'PMMA','S-BSL7','SBSL7'}))
319
error('Requested material not found in database.')
end
switch materialname
case 'PMMA'
Material = struct('name','PMMA','data',...
[320 407 493 580 667 753 840 927 1013 1100 ; %
wavelengths in nm
1.5136 1.5063 1.4973 1.4922 1.4889 1.4869 1.4852 1.4841 1.4831 1.4831; %
index of refraction
0.134 0.778 1.328 1.333 1.234 1.018 0.898 0.535 0.651 0.278 ]); %
relative weights
case {'S-BSL7','SBSL7'} % Ohara equivalent of N-BK7
Material = struct('name','S-BSL7','data',...
[365 440 516 591 666 742 817 892 968 1043 1118; % wavelengths in nm
1.535787392 1.525798128 1.519927707 1.516187475 1.513557949
1.511557671 1.509987589 1.508672819 1.507509303 1.506469274
1.505497831; % index of refraction
0.418 1.099 1.351 1.317 1.286 1.108 0.790 0.847 0.613 0.628 0.208 ]); %
relative weights
End
Dependency: extangwts_posWzero.m
Creates sample angles and appropriate weights for an extended disc-shaped light
source, simulating sunlight in angular extent.
function extwt = extangwts_posWzero(extang)
sunrad = 0.267;
if ~ismember(0,extang)
error('0 is not a member of the input "extang"');
elseif any(extang<0)
error('some elements of the input "extang" are negative');
end
ahalf = @(h,r) 0.5.*h.*sqrt(r.^2-h.^2) + asin(h./r).*r.^2./2;
[extangsort,sortind] = sort(extang);
[~,revsortind] = sort(sortind);
padext = [-extangsort(2),extangsort,extangsort(end)+(extangsort(end)-extangsort(end-
1))/2];
hhi = mean([extangsort;padext(3:end)],1);
hlo = mean([extangsort;padext(1:end-2)],1);
hhi = max(min(hhi,sunrad),-sunrad);
320
hlo = max(min(hlo,sunrad),-sunrad);
extwt = ahalf(hhi,sunrad)-ahalf(hlo,sunrad);
extwt = extwt(revsortind);
extwt = extwt./sum(extwt);