Example #1
0
def set_laser(dvc = 0, laser_on = True, laser_intensity = 1000, Errors = {}, verbosity = _VERBOSITY):
    """
    Turn laser ON (3 modulation types: 7Hz (1), 28 Hz (2) and 255 Hz (3)) or OFF (0) and set laser intensity.
    
    Args:
        :dvc:
            | Device handle.
        :laser_on:
            | 0: OFF, >0: ON -> 1: PWM 7Hz, 2: PWM 28 Hz, 3: 255 Hz, optional
            | True (>0): turn laser on to select measurement area; False (0): turn off. 
            | (Can only be ON when "spd" is not in out.split(","))
        :laser_intensity: 
            | 1000.0, optional
            | Laser intensity in ‰ (pro-mille).
        :Errors:
            | Dict with error messages.
        :verbosity:
            | 1, optional
            | 0: no printed error message output.
    
    Returns:
        :Errors:
            | Dict with error messages.
    """
    try:
        Errors["SetLaserIntensity"] = None
        
        # Open device if not already opened!
        if not _check_dvc_open(dvc):
            dvc_was_open = False
            dvc, Errors = dvc_open(dvc = dvc, Errors = Errors, out = "dvc,Errors", verbosity = verbosity)    
        else:
            dvc_was_open = True
            
        # Set laser intensity and modulation:   
        if laser_intensity > 1000:
            laser_intensity = 1000
        if np.int(laser_on) not in [0,1,2,3]:
            laser_on = 3
        if (bool(laser_on) == True) & (_check_dvc_open(dvc)):
            dwError = jtc.JETI_SetLaserIntensity(dvc, DWORD(laser_intensity), DWORD(np.int(laser_on)))
            if dwError != 0:    
                if (verbosity == 1):
                    print("Could not set pilot laser intensity and/or modulation. Error code = {}".format(dwError))
            Errors["SetLaserIntensity"] = dwError
        elif (bool(laser_on) == False) & (_check_dvc_open(dvc)):
            dwError = jtc.JETI_SetLaserIntensity(dvc, DWORD(np.int(laser_intensity)), DWORD(0))
            if dwError != 0:    
                if (verbosity == 1):
                    print("Could not turn OFF pilot laser. Error code = {}".format(dwError))
            Errors["SetLaserIntensity"] = dwError
        
        # Toggle laser status:  
        Errors = set_laser_status(dvc, status = bool(laser_on), out = "Errors", Errors = Errors, verbosity = verbosity)

    except:
        Errors["SetLaserIntensity"] = "set_laser() fails."
    finally:
        dvc, Errors = dvc_close(dvc, Errors = Errors, close_device = (dvc_was_open == False), out = "dvc,Errors", verbosity = verbosity)
        return Errors
Example #2
0
def read_spectral_radiance(dvc, wlstart = 360, wlend = 830, wlstep = 1, out = "spd,Errors", Errors = {}, verbosity = _VERBOSITY):
    """
    Read measured spectral radiance (W/m².sr.nm) from device.
    
    Args:
        :dvc:
            | Device handle (of class ctypes).
        :wlstart:
            | 360 or Int, optional
            | Start wavelength in nm. (min = 350 nm)
        :wlend:
            | 830 or Int, optional
            | Start wavelength in nm. (max = 1000 nm)
        :out:
            | "status,Errors", optional
            | Requested return.
        :Errors:
            | Dict with error messages.
        :verbosity:
            | 1, optional
            | 0: no printed error message output.
    
    Returns:
        :spd:
            | ndarray with wavelengths (1st row) and spectral radiance (2nd row; nan's if error).
        :Errors:
            | Dict with error messages.

    """
    out = out.replace(' ','')
    
    # Get wavelength range:
    wls = np.arange(np.int(wlstart), np.int(wlend)+np.int(wlstep), np.int(wlstep), dtype=np.float32)
    
    # Initialize spd filled with nan's:
    spd = np.vstack((wls, np.nan*np.ones(wls.shape)))
    
#    try:
    Errors["SpecRadEx"] = None
    
    # Convert measurement parameters to ctypes:
    dwBeg = DWORD(np.int(wlstart)) # wavelength start in nm
    dwEnd = DWORD(np.int(wlend)) # wavelength end in nm
    
    # create buffer for spectral radiance data:
    fSprad = (FLOAT * wls.shape[0])() 
    
    # get pointer to start of spectral radiance 
    dwError = jtre.JETI_SpecRadEx(dvc, dwBeg, dwEnd, ctypes.byref(fSprad)) 
    Errors["SpecRadEx"] = dwError
    if (dwError != 0):
        if (verbosity == 1):
            print("Could not read spectral radiance data from device. Error code = {}".format(dwError))
    else:
        # Read spectral radiance from buffer:
        Sprad= np.frombuffer(fSprad, np.float32)
            
        # Overwrite 2nd row of spd array with measured spectral radiance values:
        spd[1,:] = Sprad  
#    except:
#        Errors["SpecRadEx"] = "read_spectral_radiance() fails."
#    finally:
    # Generate requested return:
    if out == "spd,Errors":
        return spd, Errors
    elif out == "spd":
        return spd
    elif out == "Errors":
        return Errors
    else:
        raise Exception("Requested output error.")
Example #3
0
def start_meas(dvc, Tint = 0.0, autoTint_max = _TINT_MAX, Nscans = 1, wlstep = 1, Errors = {}, out = "Tint,Errors", verbosity = _VERBOSITY):
    """
    Start measurement on already opened device.
    
    Args:
        :dvc:
            | Device handle (of class ctypes).
        :Tint:
            | 0 or Float, optional
            | Integration time in seconds. (if 0: find best integration time).
        :autoTint_max:
            | Limit Tint to this value when Tint = 0.
        :Nscans:
            | 1 or Int, optional
            | Number of scans to average.
        :wlstep: 
            | 1 or Int, optional
            | Wavelength step size in nm.
        :out:
            | "Tint,Errors", optional
            | Requested return.
        :Errors:
            | Dict with error messages.
        :verbosity:
            | 1, optional
            | 0: no printed error message output.
    
    Returns:
        :Tint:
            | Integration time (limited to max possible time allowed by device)
        :Errors:
            | Dict with error messages.
    """
    out = out.replace(' ','')
    try:
        Errors["MeasureEx"] = None
        
        # Find minimum integration time for connected device and re-set global variable _TINT_MIN (to avoid having to call the function a second time for this device):
        global _TINT_MIN
        if _TINT_MIN is None:
            _TINT_MIN, Errors = get_min_integration_time(dvc, out = "MinTint,Errors", Errors = Errors, verbosity = verbosity)
         
        if autoTint_max is None:
            autoTint_max = _TINT_MAX
  
        # Limit integration time to max value:
        Tint = _limit_Tint(Tint, Tint_min = _TINT_MIN, Tint_max = _TINT_MAX)
        autoTint_max = _limit_Tint(autoTint_max, Tint_min = _TINT_MIN, Tint_max = _TINT_MAX)

        # For automated Tint:
        if Tint == 0:
            MaxTint,Errors = get_max_auto_integration_time(dvc, out = "MaxTint,Errors", Errors = Errors, verbosity = verbosity)
            Errors = set_max_auto_integration_time(dvc, MaxTint = autoTint_max, out = "Errors", Errors = Errors, verbosity = verbosity)
          
        
        # Convert measurement parameters to ctypes:
        fTint = FLOAT(Tint*1000) # integration time (seconds -> milliseconds)
        wAver = WORD(np.int(Nscans)) # number of scans to average
        dwStep = DWORD(np.int(wlstep)) # wavelength step in nm
                            
        # Start measurement:
        dwError = jtre.JETI_MeasureEx(dvc, fTint, wAver, dwStep)
        Errors["MeasureEx"] = dwError
        if (dwError != 0):
            if (verbosity == 1):
                print("Could not start measurement. Error code = {}".format(dwError))
    except:
        Errors["MeasureEx"] = "start_meas() fails."
    finally:
        if out == "Tint,Errors":
            return Tint, Errors
        elif out == "Errors":
            return Errors
        elif out == "Tint":
            return Tint
        else:
            raise Exception("Requested output error.")
Example #4
0
def get_spd(dvc = 0, Tint = 0.0, autoTint_max = _TINT_MAX, Nscans = 1, wlstep = 1, 
            wlstart = 360, wlend = 830, 
            twait = _TWAIT_STATUS, out = "spd", close_device = True, 
            laser_on = 0, laser_intensity = 1000, verbosity = _VERBOSITY):
    """
    Measure spectral radiance (W/nm.sr.m²).
    
    Args:
        :dvc:
            | 0 or Int or ctypes.wintypes.LP_c_ulong, optional
            | Number of the spectrometer device to load (0 = 1st) or handle (ctypes) to pre_initialized device.
        :Tint:
            | 0 or Float, optional
            | Integration time in seconds. (if 0: find best integration time, but < autoTint_max).
        :autoTint_max:
            | Limit Tint to this value when Tint = 0.
        :Nscans:
            | 1 or Int, optional
            | Number of scans to average.
        :wlstep: 
            | 1 or Int, optional
            | Wavelength step size in nm.
        :wlstart:
            | 360 or Int, optional
            | Start wavelength in nm. (min = 350 nm)
        :wlend:
            | 830 or Int, optional
            | Start wavelength in nm. (max = 1000 nm)
        :twait:
            | 0.1 or Float, optional
            | Time in seconds to wait before checking status of device. 
            | (If 0: wait :Tint: seconds, unless :Tint: == 0, then wait _TWAIT_STATUS seconds)
        :out:
            | "spd" [",dvc, Errors"], optional
            | Requested return. If "spd" in out.split(","):do spectral measurement, else: initialize dvc handle [and turn laser ON or OFF].
        :close_device:
            | True or False, optional
            | Close device at the end of the measurement.
            | If 'dvc' not in out.split(','): always close!!!
        :laser_on:
            | 0: OFF, >0: ON -> 1: PWM 7Hz, 2: PWM 28 Hz, 3: 255 Hz, optional
            | True (>0): turn laser on to select measurement area; False (0): turn off. 
            | (Can only be ON when "spd" is not in out.split(",") | if Tint is None)
        :laser_intensity: 
            | 1000.0, optional
            | Laser intensity in ‰ (pro-mille).
        :verbosity:
            | 1, optional
            | 0: no printed error message output.
    Returns:
        :returns: 
            | spd [,dvc, Errors] (as specified in :out:)
            | - "spd": ndarray with wavelengths (1st row) and spectral radiance (2nd row).
            | - "dvc": ctypes handle to device (if open) or nan (if closed).
            | - "Errors": dict with error message returned by device during various steps of the spectral measurement process.
    """
    # Initialize dict with errors messages for each of the different measurement steps:
    Errors = {} 
    Errors["get_spd"] = None
    out = out.replace(' ','')
    
    # Get wavelength range:
    wls = np.arange(np.int(wlstart), np.int(wlend)+np.int(wlstep), np.int(wlstep), dtype=np.float32)
    
    # Initialize spd filled with nan's:
    spd = np.vstack((wls, np.nan*np.ones(wls.shape)))

    try:
        # Initialize device :
        dvc, Errors = dvc_open(dvc = dvc, Errors = Errors, out = "dvc,Errors", verbosity = verbosity)    
        
        if (_check_dvc_open(dvc)) & (("spd" in out.split(",")) & (Tint is not None)):
            
            # Turn off laser before starting measurement:
            Errors = set_laser(dvc = dvc, laser_on = False, laser_intensity = laser_intensity, Errors = Errors, verbosity = verbosity)
                    
                            
            # Start measurement:
            Tint, Errors = start_meas(dvc, Tint = Tint, autoTint_max = autoTint_max, Nscans = Nscans, wlstep = wlstep, Errors = Errors, out = "Tint, Errors", verbosity = verbosity)
            
            # wait until measurement is finished (check intermediate status every twait seconds):
            status, Errors = wait_until_meas_is_finished(dvc, Tint = Tint, twait = twait, out = "status,Errors", Errors = Errors, verbosity = verbosity)
            
            if status == False:
                # Read measured spectral radiance from device:
                spd, Errors = read_spectral_radiance(dvc, wlstart = wlstart, wlend = wlend, wlstep = wlstep, out = "spd,Errors", Errors = Errors, verbosity = verbosity)    
            
        elif (("spd" not in out.split(",")) | (Tint is None)): # only dvc handle was requested or to turn laser ON.
            Errors = set_laser(dvc = dvc, laser_on = laser_on, laser_intensity = laser_intensity, Errors = Errors, verbosity = verbosity)
        
        # Close device:
        dvc, Errors = dvc_close(dvc, Errors = Errors, close_device = (close_device) | ('dvc' not in out.split(',')), out = "dvc,Errors", verbosity = verbosity)
    
        
        Errors["get_spd"] = int(np.sum([int(bool(x)) for x in Errors.values() if (x is not None)]) > 0)
        
    except:
        Errors["get_spd"] = "get_spd fails."
        
    finally:
        # Generate requested return:
        if out == "spd":
            return spd
        elif out == "dvc":
            return dvc
        elif out == "Errors":
            return Errors
        elif out == "spd,Errors":
            return spd, Errors
        elif out == "spd,dvc":
            return spd, dvc
        elif out == "spd,Errors,dvc":
            return spd, Errors, dvc
        elif out == "spd,dvc,Errors":
            return spd, dvc, Errors
        else:
            raise Exception("Requested output error.")
Example #5
0
def get_pixel_coordinates(jab,
                          jab_ranges=None,
                          jab_deltas=None,
                          limit_grid_radius=0):
    """
    Get pixel coordinates corresponding to array of jab color coordinates.
    
    Args:
        :jab: 
            | ndarray of color coordinates
        :jab_ranges:
            | None or ndarray, optional
            | Specifies the pixelization of color space.
            |    (ndarray.shape = (3,3), with  first axis: J,a,b, and second 
                 axis: min, max, delta)
        :jab_deltas:
            | float or ndarray, optional
            | Specifies the sampling range. 
            | A float uses jab_deltas as the maximum Euclidean distance to select
              samples around each pixel center. A ndarray of 3 deltas, uses
              a city block sampling around each pixel center.
        :limit_grid_radius: 
            | 0, optional
            | A value of zeros keeps grid as specified by axr,bxr.
            | A value > 0 only keeps (a,b) coordinates within :limit_grid_radius: 
    
    Returns:
        :returns:
            | gridp, idxp, jabp, samplenrs, samplesIDs
            |   - :gridp: ndarray with coordinates of all pixel centers.
            |   - :idxp: list[int] with pixel index for each non-empty pixel
            |   - :jabp: ndarray with center color coordinates of non-empty pixels
            |   - :samplenrs: list[list[int]] with sample numbers belong to each 
            |                 non-empty pixel
            |   - :sampleIDs: summarizing list, 
            |                 with column order: 'idxp, jabp, samplenrs'
    """
    if jab_deltas is None:
        jab_deltas = np.array([_VF_DELTAR, _VF_DELTAR, _VF_DELTAR])
    if jab_ranges is None:
        jab_ranges = np.vstack(
            ([0, 100, jab_deltas[0]
              ], [-_VF_MAXR, _VF_MAXR + jab_deltas[1], jab_deltas[1]],
             [-_VF_MAXR, _VF_MAXR + jab_deltas[2], jab_deltas[2]]))

    # Get pixel grid:
    gridp = generate_grid(jab_ranges=jab_ranges,
                          limit_grid_radius=limit_grid_radius)

    # determine pixel coordinates of each sample in jab:
    samplesIDs = []
    for idx in range(gridp.shape[0]):

        # get pixel coordinates:
        jp = gridp[idx, 0]
        ap = gridp[idx, 1]
        bp = gridp[idx, 2]
        #Cp = np.sqrt(ap**2+bp**2)

        if type(jab_deltas) == np.ndarray:
            sampleID = np.where(
                ((np.abs(jab[..., 0] - jp) <= jab_deltas[0] / 2) &
                 (np.abs(jab[..., 1] - ap) <= jab_deltas[1] / 2) &
                 (np.abs(jab[..., 2] - bp) <= jab_deltas[2] / 2)))
        else:
            sampleID = np.where(
                (np.sqrt((jab[..., 0] - jp)**2 + (jab[..., 1] - ap)**2 +
                         (jab[..., 2] - bp)**2) <= jab_deltas / 2))

        if (sampleID[0].shape[0] > 0):
            samplesIDs.append(
                np.hstack((idx, np.array([jp, ap, bp]), sampleID[0])))

    idxp = [np.int(samplesIDs[i][0]) for i in range(len(samplesIDs))]
    jabp = np.vstack([samplesIDs[i][1:4] for i in range(len(samplesIDs))])
    samplenrs = [
        np.array(samplesIDs[i][4:], dtype=int).tolist()
        for i in range(len(samplesIDs))
    ]

    return gridp, idxp, jabp, samplenrs, samplesIDs
Example #6
0
jabt, jabr = out
# jabt,jabr = data['bjabt'],data['bjabr']
_jab_test, _jab_ref = jabt.copy(), jabr.copy()
close_gamut = True

# make 3d for easy looping:
_test_original_shape = _jab_test.shape

if len(_test_original_shape) < 3:
    _jab_test = _jab_test[:, None]
    _jab_ref = _jab_ref[:, None]

#initialize Jabt, Jabr, binnr, DEi;
_test_shape = list(_jab_test.shape)
if nhbins is not None:
    _nhbins = np.int(nhbins)
    _test_shape[0] = _nhbins + close_gamut * 1
else:
    _nhbins = nhbins
    _test_shape[0] = _test_shape[0] + close_gamut * 1
_jabt = np.zeros(_test_shape)
_jabr = _jabt.copy()
_binnr = _jab_test[..., 0].copy()
_DEi = _jabt[..., 0].copy()

# Store all samples (for output of potentially scaled coordinates):
# if ('jabti' in out) | ('jabri' in out):
_jabti = _jab_test.copy()
_jabri = _jab_ref.copy()

# Loop over axis 1:
Example #7
0
def read_ldt_lamp_data(filename, multiplier=1.0, normalize='I0'):
    """
    Read in LDT files.
    
    Args:
        :filename:
            | Filename of LDT file.
        :multiplier:
            | 1.0, optional
            | Scaler for candela values.
        :verbosity:
            | 0, optional
            | Display messages while reading file.
        :normalize:
            | 'I0', optional
            | If 'I0': normalize LID to intensity at (theta,phi) = (0,0)
            | If 'max': normalize to max = 1.
            
    Returns:
        :LDT: dict with LDT file data.
            |
            | dict_keys(
            | ['filename', 'version', 'manufacturer', 'Ityp','Isym',
            | 'Mc', 'Dc', 'Ng', 'name', Dg', 'cct/cri', 'tflux', 'lumens_per_lamp',
            | 'candela_mult', 'tilt', lamps_num',
            | 'cangles', 'tangles','candela_values', 'candela_2d',
            | 'intensity', 'theta', 'values', 'phi', 'map', 'Iv0']
            | )
    """
    LDT = {'filename': filename}
    LDT['version'] = None
    with open(filename) as file:
        c = 0
        cangles = []
        tangles = []
        candela_values = []
        for line in file:
            if c == 0:  # manufacturer
                LDT['manufacturer'] = line.rstrip()
            elif c == 1:  # type indicator: 1: point with symm. around vert. axis, 2: line luminaire, 3: point with other symm.
                if np.float(line) == 1.0:
                    LDT['Ityp'] = 'point source with symm. around vert. axis'
                elif np.float(line) == 2.0:
                    LDT['Ityp'] = 'line luminaire'
                elif np.float(line) == 3.0:
                    LDT['Ityp'] = 'point source with other symm.'
            elif c == 2:  # symm. indicator
                if np.float(line) == 0.0:
                    LDT['Isym'] = (0, 'no symmetry')
                elif np.float(line) == 1.0:
                    LDT['Isym'] = (1, 'symmetry about the vertical axis')
                elif np.float(line) == 2.0:
                    LDT['Isym'] = (2, 'symmetry to plane C0-C180')
                elif np.float(line) == 3.0:
                    LDT['Isym'] = (3, 'symmetry to plane C90-C270')
                elif np.float(line) == 4.0:
                    LDT['Isym'] = (
                        4, 'symmetry to plane C0-C180 and to plane C90-C270')
            elif c == 3:  # Number Mc of C-planes between 0 and 360 degrees
                LDT['Mc'] = np.float(line)
            elif c == 4:  # Distance Dc between C-planes (Dc = 0 for non-equidistantly available C-planes)
                LDT['Dc'] = np.float(line)
            elif c == 5:  # Number Ng of luminous intensities in each C-plane
                LDT['Ng'] = np.float(line)
            elif c == 6:  # Distance Dg between luminous intensities per C-plane (Dg = 0 for non-equidistantly available luminous intensities in C-planes)
                LDT['Dg'] = np.float(line)
            elif c == 8:  # luminaire name
                LDT['name'] = line.rstrip()
            elif c == 23:  # conversion factor
                LDT['candela_mult'] = np.float(line)
            elif c == 24:  # Tilt angle
                LDT['tilt'] = np.float(line)
            elif c == 26:  # number of lamps
                LDT['lamps_num'] = np.float(line)
            elif c == 28:  # total luminous flux
                LDT['tflux'] = np.float(line)
                LDT['lumens_per_lamp'] = LDT['tflux']
            elif c == 29:  # cct/cri
                LDT['cct/cri'] = line.rstrip()
            elif (c >= 42) & (c <= (42 + LDT['Mc'] - 1)):  # start of C-angles
                cangles.append(np.float(line))
            elif (c >= 42 + LDT['Mc']) & (
                    c <=
                (42 + LDT['Mc'] + LDT['Ng'] - 1)):  # start of t-angles
                tangles.append(np.float(line))
            elif (c >= (42 + LDT['Mc'] + LDT['Ng'])) & (
                    c <=
                (42 + LDT['Mc'] + LDT['Ng'] + LDT['Mc'] * LDT['Ng'] - 1)):
                candela_values.append(np.float(line))
            c += 1

        candela_values = np.array(candela_values)
        LDT['candela_values'] = np.array(candela_values)
        candela_2d = np.array(candela_values).reshape((-1, np.int(LDT['Ng'])))
        LDT['h_angs'] = np.array(cangles)[:candela_2d.shape[0]]
        LDT['v_angs'] = np.array(tangles)
        LDT['candela_2d'] = np.array(candela_2d)

        # normalize candela values to max = 1 or I0 = 1:
        LDT = _normalize_candela_2d(LDT,
                                    normalize=normalize,
                                    multiplier=multiplier)

        # complete lid to full theta[0-180] and phi [0-360]
        LDT = _complete_ldt_lid(LDT, Isym=LDT['Isym'][0])

        LDT['Iv0'] = LDT['intensity'] / 1000 * LDT['tflux']  #lid in cd/klm
        return LDT