Example #1
0
def arc_model_to_rgb(thickness, porosity, aoi=8):
    # Wavelength axis
    wavelength = np.arange(360, 801, 5).astype('float')

    # Choice of illuminant makes a very small change to the calculated RGB color.
    illuminant = 'LED-B3'

    # # Scan thickness and porosity.
    # thickness = np.arange(0, 196, 5).astype('float')
    # porosity = np.arange(0, 0.51, 0.1).astype('float')

    # col = np.zeros((3, len(thickness), len(porosity)))
    # col_hex = np.empty((len(thickness), len(porosity)), dtype='object')
    # xyY = np.zeros((3, len(thickness), len(porosity)))

    index_film = refractive_index_porous_silica(wavelength, porosity)
    index_substrate = refractive_index_glass(wavelength)

    # Calculate reflectance
    reflectance = thin_film_reflectance(index_film=index_film,
                                        index_substrate=index_substrate,
                                        film_thickness=thickness,
                                        aoi=aoi,
                                        wavelength=wavelength)
    reflectance_ref = thin_film_reflectance(index_film=index_film,
                                            index_substrate=index_substrate,
                                            film_thickness=0,
                                            aoi=aoi,
                                            wavelength=wavelength)

    rgb = spectrum_to_rgb(wavelength, reflectance, illuminant=illuminant)
    rgb_ref = spectrum_to_rgb(wavelength,
                              reflectance_ref,
                              illuminant=illuminant)

    # White balance
    rgb_wb = rgb / rgb_ref

    # Clamp
    rgb_wb[rgb_wb >= 1] = 1
    rgb_wb[rgb_wb < 0] = 0

    return rgb_wb
Example #2
0
    def arc_model_c(wavelength, thickness, fraction_abraded, fraction_dust,
                    porosity):
        index_film = refractive_index_porous_silica(wavelength=wavelength,
                                         porosity=porosity)

        index_substrate = refractive_index_glass(wavelength=wavelength)
        thin_film_R = thin_film_reflectance(
            index_film=index_film,
            index_substrate=index_substrate,
            film_thickness=thickness,
            wavelength=wavelength,
            aoi=aoi
        )
        #
        # thin_film_R = thin_film_reflection_fast(
        #     wavelength=wavelength,
        #     thickness=thickness,
        #     aoi=aoi,
        #     porosity=porosity)

        #
        # index_film = index_porous_silica(wavelength=wavelength,
        #                                  porosity=porosity)
        # thin_film_reflectance = thin_film_reflection(
        #     polarization='mixed',
        #     wavelength=wavelength,
        #     d_list=[np.inf, thickness, np.inf],
        #     index_film=index_film,
        #     index_substrate=index_glass,
        #     aoi=aoi)

        glass_reflectance = np.interp(wavelength, wavelength_calc,
                                      glass_reflectance_calc)

        reflectance = (1 - fraction_dust) * (
                fraction_abraded * glass_reflectance + (
                1 - fraction_abraded) * thin_film_R) + fraction_dust

        return 100 * reflectance
Example #3
0
"""Example test comparing fast explicit method and tmm method for thin film
reflectance.

toddkarin
09/10/2020
"""

import numpy as np
from time import time

from pvarc.materials import refractive_index_glass, refractive_index_porous_silica
from pvarc.tmm import thin_film_reflectance_tmm
from pvarc import thin_film_reflectance

wavelength = np.linspace(200, 1250, 2000)
index_substrate = refractive_index_glass(wavelength)
index_film = refractive_index_porous_silica(wavelength)
aoi = 8
film_thickness = 120
polarization = 'mixed'

start_time = time()
R_tmm = thin_film_reflectance_tmm(index_film=index_film,
                                  index_substrate=index_substrate,
                                  film_thickness=film_thickness,
                                  aoi=aoi,
                                  wavelength=wavelength,
                                  polarization=polarization)
time_tmm = time() - start_time
print('Elapsed time for TMM method: {:.5f} s'.format(time_tmm))
start_time = time()
Example #4
0
def arc_reflection_model(wavelength,
                         thickness=125,
                         fraction_abraded=0,
                         porosity=0.3,
                         fraction_dust=0,
                         aoi=8,
                         n0=1.0003):
    """
    Return the reflection values for a model of an aged ARC. The reflection
    is a linear combination of reflection from a thin film of a variable
    thickness and the reflection from BK7 glass.

    Parameters
    ----------
    wavelength : ndarray

        wavelength in nm

    thickness

        thickness of ARC in nm.

    fraction_abraded

        fraction of coating loss. 1 corresponds to 100% of the coating area
        removed and only underlying glass is present, 0 corresponds to the
        coating covering the entire sample.

    fraction_dust

        fraction of module area covered by dust with reflectivity of 1. A
        value of 0 corresponds to no dust (clean sample), 1 to full dust
        coverage (reflectivity of 1).

    aoi

        angle of incidence in degrees.

    Returns
    -------

    reflectance : ndarray

        Reflectance of sample at the values of wavelength specified.

    """

    index_substrate = refractive_index_glass(wavelength)
    index_film = refractive_index_porous_silica(wavelength, porosity=porosity)
    glass_reflectance = single_interface_reflectance(
        n0=n0,
        n1=index_substrate,
        polarization='mixed',
        aoi=aoi)

    thin_film_R = thin_film_reflectance(index_film=index_film,
                                        index_substrate=index_substrate,
                                        film_thickness=thickness,
                                        aoi=aoi,
                                        wavelength=wavelength)

    reflectance = (1 - fraction_dust) * (
            fraction_abraded * glass_reflectance + (
            1 - fraction_abraded) * thin_film_R) + fraction_dust

    return reflectance
Example #5
0
def fit_arc_reflection_spectrum(wavelength,
                                reflectance,
                                x0=None,
                                aoi=8,
                                model='d',
                                fixed=None,
                                verbose=False,
                                method='basinhopping',
                                niter=20,
                                wavelength_min=450,
                                wavelength_max=1000):
    """
    This function fits an ARC model to the reflection spectrum. The ARC model
    is described in the function arc_reflection_model.

    Parameters
    ----------
    wavelength : ndarray

        Wavelength in nm

    reflectance : ndarray

        Fractional reflection between 0 and 1, unitless.

    x0 : dict

        Startpoint for fitting algorithm.

    aoi : float

        Angle of incidence of light

    model : str

        Different variation of the same model are available. The model is
        described under the function `arc_reflection_model`. The fixed values
        are specified in the input 'fixed'.

        'TP' - thickness and poristy are fit, fraction_abraded and fraction_dust
        set to fixed values.

        'TPA' - thickness, porosity and fraction_abraded are fit,
        fraction_dust is fixed.

        'TPAD' - thickness, porosity, fraction_abraded and fraction_dust are
        fit.

        'TAD' - thickness, fraction_abraded, fraction_dust are fit, porosity
        is a fixed value.

    fixed : dict

        Dictionary of parameters to be fixed. Default is:
           fixed = {'thickness': 125, 'fraction_abraded': 0, 'fraction_dust': 0,
             'porosity': 0.3}

     verbose : bool

        Whether to print output at each iteration.

    method : str

        Optimization method, can be 'minimize' or 'basinhopping'

    niter : int

        Number of basinhopping steps if method == 'basinhopping'

    wavelength_min : float

        Lower bound for wavelength values used in fit.

    wavelength_max : float

        Upper bound for wavelength values used in fit.

    Returns
    -------

    result : dict

        Dictionary of best fit values.

    ret

        Output of optimizer.

    """

    if np.mean(reflectance) > 1:
        print(
            'Warning: check that reflectance is a fractional value between 0 and 1.')

    if x0 == None:
        x0 = estimate_arc_reflection_model_params(wavelength, reflectance)

    fixed_default = {'thickness': 125,
                     'fraction_abraded': 0,
                     'fraction_dust': 0,
                     'porosity': 0.3}
    if fixed == None:
        fixed = fixed_default
    else:
        for p in fixed_default:
            if p not in fixed:
                fixed[p] = fixed_default[p]

    # print('x0: ', x0)

    scale = {'thickness': 0.01,
             'fraction_abraded': 1,
             'fraction_dust': 1000,
             'porosity': 1}

    if model == 'TPA':
        x0_list = [x0['thickness'] * scale['thickness'],
                   x0['fraction_abraded'] * scale['fraction_abraded'],
                   x0['porosity'] * scale['porosity']
                   ]
    elif model == 'TAD':
        x0_list = [x0['thickness'] * scale['thickness'],
                   x0['fraction_abraded'] * scale['fraction_abraded'],
                   x0['fraction_dust'] * scale['fraction_dust']
                   ]
    elif model == 'TPAD':
        x0_list = [x0['thickness'] * scale['thickness'],
                   x0['fraction_abraded'] * scale['fraction_abraded'],
                   x0['fraction_dust'] * scale['fraction_dust'],
                   x0['porosity'] * scale['porosity'],
                   ]
    elif model == 'TP':
        x0_list = [x0['thickness'] * scale['thickness'],
                   x0['porosity'] * scale['porosity'],
                   ]
    else:
        raise Exception('model options are "TP", "TPA", "TPAD" or "TAD"')

    # Increase by a factor of 100 to improve numeric accuracy.
    reflectance = reflectance * 100

    reflectance[reflectance < 0] = 0
    reflectance[reflectance > 100] = 100

    cax = np.logical_and(wavelength > wavelength_min,
                         wavelength < wavelength_max)

    wavelength_calc = wavelength.copy()

    index_substrate = refractive_index_glass(wavelength)

    glass_reflectance_calc = single_interface_reflectance(n0=1.0003,
                                                          n1=index_substrate,
                                                          aoi=aoi,
                                                          polarization='mixed',
                                                          )

    # # Get interpolator for correct
    # if not aoi == 8:
    #     raise Exception('aoi must be 8 degrees.')

    thickness_min = 50
    thickness_max = 200
    porosity_max = 0.499

    if model == 'TPA':
        bounds = [(thickness_min * scale['thickness'],
                   thickness_max * scale['thickness']),
                  (0, 1 * scale['fraction_abraded']),
                  (0, porosity_max * scale['porosity']),
                  ]
    elif model == 'TAD':
        bounds = [(thickness_min * scale['thickness'],
                   thickness_max * scale['thickness']),
                  (0, 1 * scale['fraction_abraded']),
                  (0, 1 * scale['fraction_dust']),
                  ]
    elif model == 'TPAD':
        bounds = [(thickness_min * scale['thickness'],
                   thickness_max * scale['thickness']),
                  (0, 1 * scale['fraction_abraded']),
                  (0, 1 * scale['fraction_dust']),
                  (0, porosity_max * scale['porosity']),
                  ]
    elif model == 'TP':
        bounds = [(thickness_min * scale['thickness'],
                   thickness_max * scale['thickness']),
                  (0, porosity_max * scale['porosity']),
                  ]

    def arc_model_c(wavelength, thickness, fraction_abraded, fraction_dust,
                    porosity):
        index_film = refractive_index_porous_silica(wavelength=wavelength,
                                         porosity=porosity)

        index_substrate = refractive_index_glass(wavelength=wavelength)
        thin_film_R = thin_film_reflectance(
            index_film=index_film,
            index_substrate=index_substrate,
            film_thickness=thickness,
            wavelength=wavelength,
            aoi=aoi
        )
        #
        # thin_film_R = thin_film_reflection_fast(
        #     wavelength=wavelength,
        #     thickness=thickness,
        #     aoi=aoi,
        #     porosity=porosity)

        #
        # index_film = index_porous_silica(wavelength=wavelength,
        #                                  porosity=porosity)
        # thin_film_reflectance = thin_film_reflection(
        #     polarization='mixed',
        #     wavelength=wavelength,
        #     d_list=[np.inf, thickness, np.inf],
        #     index_film=index_film,
        #     index_substrate=index_glass,
        #     aoi=aoi)

        glass_reflectance = np.interp(wavelength, wavelength_calc,
                                      glass_reflectance_calc)

        reflectance = (1 - fraction_dust) * (
                fraction_abraded * glass_reflectance + (
                1 - fraction_abraded) * thin_film_R) + fraction_dust

        return 100 * reflectance

    def arc_coating_error_function(x):

        # print('x: ',x)

        if model == 'TPA':
            thickness = x[0] / scale['thickness']
            fraction_abraded = x[1] / scale['fraction_abraded']
            porosity = x[2] / scale['porosity']
            reflectance_model = arc_model_c(wavelength, thickness,
                                            fraction_abraded=fraction_abraded,
                                            fraction_dust=fixed[
                                                'fraction_dust'],
                                            porosity=porosity)
        elif model == 'TAD':
            thickness = x[0] / scale['thickness']
            fraction_abraded = x[1] / scale['fraction_abraded']
            fraction_dust = x[2] / scale['fraction_dust']
            reflectance_model = arc_model_c(wavelength, thickness,
                                            fraction_abraded, fraction_dust,
                                            porosity=fixed['porosity'])
            # if verbose:
            #     print(
            #         'Thickness: {:03.2f}, Fraction Abraded: {:.1%}, Fraction dust: {:.1%}'.format(
            #             thickness,
            #             fraction_abraded,
            #             fraction_dust))
        elif model == 'TPAD':

            thickness = x[0] / scale['thickness']
            fraction_abraded = x[1] / scale['fraction_abraded']
            fraction_dust = x[2] / scale['fraction_dust']
            porosity = x[3] / scale['porosity']
            reflectance_model = arc_model_c(wavelength, thickness,
                                            fraction_abraded, fraction_dust,
                                            porosity)
        elif model == 'TP':

            thickness = x[0] / scale['thickness']
            porosity = x[1] / scale['porosity']
            reflectance_model = arc_model_c(wavelength, thickness,
                                            fraction_abraded=fixed[
                                                'fraction_abraded'],
                                            fraction_dust=fixed[
                                                'fraction_dust'],
                                            porosity=porosity)

        else:
            raise Exception('model type unknown')

        residual = np.mean(
            np.sqrt(np.abs(reflectance_model - reflectance) ** 2))

        return residual

    if method == 'minimize':
        res = minimize(arc_coating_error_function,
                       x0=x0_list,
                       options=dict(
                           # maxiter=100,
                           disp=verbose
                       ),
                       bounds=bounds
                       )
    elif method == 'basinhopping':

        def basinhopping_callback(x, f, accept):
            if model == 'TPA' and verbose:
                # print('x:', x)
                print(
                    '--\nThickness: {:03.2f}, Fraction Abraded: {:.1%}, Porosity: {:.1%}'.format(
                        x[0] / scale['thickness'],
                        x[1] / scale['fraction_abraded'],
                        x[2] / scale['porosity']
                    )
                )

        res = basinhopping(arc_coating_error_function,
                           x0=x0_list,
                           niter=niter,
                           minimizer_kwargs={'bounds': bounds},
                           disp=verbose,
                           callback=basinhopping_callback
                           )

    if model == 'TPA':
        result = {'thickness': res['x'][0] / scale['thickness'],
                  'fraction_abraded': res['x'][1] / scale['fraction_abraded'],
                  'fraction_dust': fixed['fraction_dust'],
                  'porosity': res['x'][2] / scale['porosity']}
    elif model == 'TAD':
        result = {'thickness': res['x'][0] / scale['thickness'],
                  'fraction_abraded': res['x'][1] / scale['fraction_abraded'],
                  'fraction_dust': res['x'][2] / scale['fraction_dust'],
                  'porosity': fixed['porosity']}
    elif model == 'TPAD':
        result = {'thickness': res['x'][0] / scale['thickness'],
                  'fraction_abraded': res['x'][1] / scale['fraction_abraded'],
                  'fraction_dust': res['x'][2] / scale['fraction_dust'],
                  'porosity': res['x'][3] / scale['porosity'],
                  }
    elif model == 'TP':
        result = {'thickness': res['x'][0] / scale['thickness'],
                  'fraction_abraded': fixed['fraction_abraded'],
                  'fraction_dust': fixed['fraction_dust'],
                  'porosity': res['x'][1] / scale['porosity'],
                  }

    return result, res
Example #6
0
x, ret = fit_arc_reflection_spectrum(wavelength,
                                     reflection,
                                     model='TPA',
                                     aoi=8,
                                     wavelength_min=450,
                                     wavelength_max=1000,
                                     method='basinhopping',
                                     verbose=True)
wavelength_extend = np.linspace(300, 1250, 1000)
reflection_fit = arc_reflection_model(wavelength_extend, **x)

# Calculate solar weighted photon reflection (SWPR) using fit
swpr = solar_weighted_photon_reflectance(wavelength_extend, reflection_fit)

# Calculate SWPR for glass reference
index_glass = refractive_index_glass(wavelength_extend)
reflection_BK7 = single_interface_reflectance(n0=1.0003,
                                       n1=index_glass,
                                       aoi=8)
swpr_bk7 = solar_weighted_photon_reflectance(wavelength_extend, reflection_BK7)

# Calculate power enhancement due to coating.
power_enchancement = swpr_bk7 - swpr

# Compare fit vs simulated value.
print('--\nComparison of true values vs. best fit')
for p in ['thickness', 'porosity', 'fraction_abraded']:
    print('{}.\t True: {:.2f}, Fit: {:.2f}, '.format(p, param_true[p], x[p]))

# Plot theory.
plt.plot(wavelength_extend,
Example #7
0
def calculate_rgb_vs_thickness_porosity(
        camera='Ximea-MC050cg_combined_labeled.csv',
        light_source='LEDW7E_A01_intensity.csv',
        optical_system='MVL23M23.csv',
        thickness_max=186,
        thickness_step=0.4,
        porosity_max=0.5,
        porosity_step=0.01,
        aoi=0):
    # Wavelength axis
    wavelength = np.arange(300, 755, 5).astype('float')
    dwavelength = wavelength[1] - wavelength[0]

    # Scan thickness and porosity.
    thickness = np.arange(0, thickness_max, thickness_step).astype('float')
    porosity = np.arange(0, porosity_max, porosity_step).astype('float')

    # Initialize arrays.
    swpr = np.zeros((len(thickness), len(porosity)))
    rgb_wb = np.zeros((len(thickness), len(porosity), 3))

    # Load Camera QE
    qe_fpath = os.path.join(os.path.dirname(__file__), 'cameras',
                            camera)
    df = pd.read_csv(qe_fpath, skiprows=2)
    dfi = pd.DataFrame({'Wavelength': wavelength})
    for k in ['Red', 'Green', 'Blue']:
        dfi[k] = np.interp(wavelength, df['Wavelength'], df[k],
                           left=0, right=0)

    # Load Illuminant spectrum
    illum_fpath = os.path.join(os.path.dirname(__file__), 'sources',
                               light_source)
    df_illum = pd.read_csv(illum_fpath, skiprows=2)
    # illuminant_sd = ILLUMINANTS_SDS[sources[s]]
    # illuminant_conv = ILLUMINANTS['CIE 1931 2 Degree Standard Observer'][illuminant_name]

    illuminant_spectrum = np.interp(wavelength, df_illum['Wavelength'],
                                    df_illum['Intensity'], left=0, right=0)

    illuminant_spectrum_photon = illuminant_spectrum * wavelength

    # Load optical system
    optical_system_fpath = os.path.join(os.path.dirname(__file__), 'cameras',
                                        optical_system)
    df_optical_system = pd.read_csv(optical_system_fpath, skiprows=2)
    optical_system_transmission = 0.01 * np.interp(
        wavelength,
        df_optical_system['Wavelength'],
        df_optical_system['Transmission'],
        left=0, right=0)

    # Calculate RGB colors
    for k in tqdm(range(len(porosity))):

        index_film = refractive_index_porous_silica(wavelength, porosity[k])
        index_substrate = refractive_index_glass(wavelength)

        for j in range(len(thickness)):

            # Calculate reflectance
            reflectance = thin_film_reflectance(index_film=index_film,
                                                index_substrate=index_substrate,
                                                film_thickness=thickness[j],
                                                aoi=aoi,
                                                wavelength=wavelength)
            # for c in ['Blue', 'Green', 'Red']:
            #     np.sum(reflectance * illuminant_spectrum_photon * dfi[c] / 100) * dwavelength

            rgb = np.sum(
                reflectance[:, np.newaxis] * \
                optical_system_transmission[:, np.newaxis] * \
                illuminant_spectrum_photon[:, np.newaxis] * \
                np.array(dfi.iloc[:, 1:]) / 100,
                axis=0) * dwavelength

            swpr[j, k] = solar_weighted_photon_reflectance(wavelength,
                                                           reflectance)

            # Use first run through, with 0 nm thickness, (i.e. low-iron glass)
            # as a reference for white balance.
            if thickness[j] == 0:
                rgb_ref = rgb.copy()

            # White balance
            rgb_wb[j, k, :] = rgb / rgb_ref

    # x = rgb_wb[0, :, :] / np.sum(rgb_wb, axis=0)
    # y = rgb_wb[1, :, :] / np.sum(rgb_wb, axis=0)
    # z = rgb_wb[2, :, :] / np.sum(rgb_wb, axis=0)

    # t_grid, P_grid = np.meshgrid(thickness, porosity, indexing='ij')

    return thickness, porosity, rgb_wb, swpr
Example #8
0
"""Example for printing a list of the refractive index of BK7 glass, useful
for performing a light reference in the spectrometer software.

"""

import numpy as np
from pvarc.materials import refractive_index_glass
from pvarc import single_interface_reflectance
wavelength = np.arange(190, 1125, 10)
index_glass = refractive_index_glass(wavelength, type='BK7')

reflectance = single_interface_reflectance(n0=1.0003,
                                           n1=index_glass,
                                           aoi=8.0,
                                           polarization='mixed')

print('Glass reflectance')
for k in range(len(wavelength)):
    print('{}\t{:.5f}'.format(wavelength[k], reflectance[k]))
# aoi_scan = np.arange(70,-1,-10)
# aoi_scan = np.array([0,10,20,30,40,50,60,70])

for porosity in [0.15, 0.3]:

    plt.figure(0, figsize=(3.7, 3))
    plt.clf()
    ax = plt.axes()
    rect = ax.patch
    rect.set_facecolor('k')

    Rmat = np.zeros((len(wavelength), len(thickness_scan)))
    index_film = refractive_index_porous_silica(wavelength, porosity)
    index_film_smooth = refractive_index_porous_silica(wavelength_smooth,
                                                       porosity)
    index_substrate = refractive_index_glass(wavelength)
    index_substrate_smooth = refractive_index_glass(wavelength_smooth)

    def smoothit(y, N=10):
        return np.convolve(y, np.ones((N, )) / N, mode='valid')

    plt.plot(smoothit(source['wavelength'][1:-200]),
             smoothit(source['value'][1:-200]) / source['value'][1:-5].max() *
             5,
             'w--',
             label='LED')

    for j in range(len(thickness_scan)):
        # Calculate reflectance at rough.
        Rmat[:, j] = thin_film_reflectance(index_film=index_film,
                                           index_substrate=index_substrate,