Bugfix: calculate extended target signal using spectral radiance values

This commit is contained in:
Lukas Klass 2020-06-26 19:15:43 +02:00
parent 1043a559b8
commit e5b6e3b700
6 changed files with 61 additions and 66 deletions

View File

@ -9,7 +9,7 @@ class IRadiant(ABC):
in the beam.
"""
@abstractmethod
def calcSignal(self) -> Tuple[SpectralQty, str, float]:
def calcSignal(self) -> Tuple[SpectralQty, float]:
"""
Calculate the signal coming from the component
@ -17,8 +17,6 @@ class IRadiant(ABC):
-------
signal : SpectralQty
The emitted, reflected or transmitted signal
size : str
The size of the target.
obstruction : float
The obstruction factor as A_ob / A_ap.
"""

View File

@ -51,7 +51,7 @@ class AOpticalComponent(IRadiant):
self.__obstructor_temp = obstructor_temp
self.__obstructor_emissivity = obstructor_emissivity
def calcSignal(self) -> Tuple[SpectralQty, str, float]:
def calcSignal(self) -> Tuple[SpectralQty, float]:
"""
Calculate the spectral flux density of the target's signal
@ -59,17 +59,15 @@ class AOpticalComponent(IRadiant):
-------
signal : SpectralQty
The spectral flux density of the target's signal
size : str
The size of the target.
obstruction : float
The obstruction factor as A_ob / A_ap.
"""
signal, size, obstruction = self.__parent.calcSignal()
signal, obstruction = self.__parent.calcSignal()
logger.info("Calculating signal for class '" + self.__class__.__name__ + "'.")
signal = self._propagate(signal) * (1 - self.__obstruction)
obstruction = obstruction + self.__obstruction
logger.debug(signal)
return signal, size, obstruction
return signal, obstruction
def calcBackground(self) -> SpectralQty:
"""

View File

@ -420,8 +420,14 @@ class Imager(ASensor):
self.__pixel_size.to(u.m) ** 2 / u.pix) / (4 * self.__f_number ** 2 + 1) * (1 * u.sr)
# Calculate the incoming photon current of the target
logger.info("Calculating the signal photon current.")
signal, size, obstruction = self._parent.calcSignal()
signal_photon_current = signal * np.pi * (self.__common_conf.d_aperture() / 2) ** 2
signal, obstruction = self._parent.calcSignal()
size = "extended" if signal.qty.unit.is_equivalent(u.W / (u.m ** 2 * u.nm * u.sr)) else "point"
if size == "point":
signal_photon_current = signal * np.pi * (self.__common_conf.d_aperture() / 2) ** 2
else:
signal_photon_current = signal * np.pi * self.__pixel_size.to(u.m) ** 2 / (
4 * self.__f_number ** 2 + 1) * (1 * u.sr)
print(signal_photon_current)
# Calculate the electron current of the background and thereby handling the photon energy as lambda-function
background_current = (
background_photon_current / (lambda wl: (const.h * const.c / wl).to(u.W * u.s) / u.photon) *
@ -499,31 +505,30 @@ class Imager(ASensor):
return "pixel -> well_capacity: " + mes
# Check photometric aperture
if conf.astroscene.target.size == "point":
if not hasattr(sensor, "photometric_aperture"):
setattr(sensor, "photometric_aperture", Entry(shape=Entry(val="circle"),
contained_energy=Entry(val="FWHM")))
if hasattr(sensor.photometric_aperture, "contained_pixels"):
mes = sensor.photometric_aperture.contained_pixels.check_quantity("val", u.pix)
if mes is not None:
return "photometric_aperture -> contained_pixels: " + mes
else:
if not hasattr(sensor.photometric_aperture, "shape"):
return "Missing container 'shape'."
mes = sensor.photometric_aperture.shape.check_selection("val", ["square", "circle"])
if mes is not None:
return "photometric_aperture -> shape: " + mes
if not hasattr(sensor.photometric_aperture, "contained_energy"):
return "Missing container 'contained_energy'."
mes = sensor.photometric_aperture.contained_energy.check_float("val")
if mes is not None:
if conf.common.psf().lower() == "airy":
mes = sensor.photometric_aperture.contained_energy.check_selection("val",
["peak", "FWHM", "fwhm",
"min"])
if mes is not None:
return "photometric_aperture -> contained_energy: " + mes
else:
mes = sensor.photometric_aperture.contained_energy.check_selection("val", ["FWHM", "fwhm"])
if mes is not None:
return "photometric_aperture -> contained_energy: " + mes
if not hasattr(sensor, "photometric_aperture"):
setattr(sensor, "photometric_aperture", Entry(shape=Entry(val="circle"),
contained_energy=Entry(val="FWHM")))
if hasattr(sensor.photometric_aperture, "contained_pixels"):
mes = sensor.photometric_aperture.contained_pixels.check_quantity("val", u.pix)
if mes is not None:
return "photometric_aperture -> contained_pixels: " + mes
else:
if not hasattr(sensor.photometric_aperture, "shape"):
return "Missing container 'shape'."
mes = sensor.photometric_aperture.shape.check_selection("val", ["square", "circle"])
if mes is not None:
return "photometric_aperture -> shape: " + mes
if not hasattr(sensor.photometric_aperture, "contained_energy"):
return "Missing container 'contained_energy'."
mes = sensor.photometric_aperture.contained_energy.check_float("val")
if mes is not None:
if conf.common.psf().lower() == "airy":
mes = sensor.photometric_aperture.contained_energy.check_selection("val",
["peak", "FWHM", "fwhm",
"min"])
if mes is not None:
return "photometric_aperture -> contained_energy: " + mes
else:
mes = sensor.photometric_aperture.contained_energy.check_selection("val", ["FWHM", "fwhm"])
if mes is not None:
return "photometric_aperture -> contained_energy: " + mes

View File

@ -15,7 +15,7 @@ class ATarget(IRadiant):
@abstractmethod
@u.quantity_input(wl_bins="length")
def __init__(self, sfd: SpectralQty, wl_bins: u.Quantity, size: str = "Point"):
def __init__(self, sfd: SpectralQty, wl_bins: u.Quantity):
"""
Initialize a new target
@ -25,12 +25,9 @@ class ATarget(IRadiant):
The spectral flux density of the target
wl_bins : length-Quantity
The bins to be used for evaluating spectral quantities.
size : str
The size of the target. Can be either point or extended.
"""
self.__sfd = sfd
self.__wl_bins = wl_bins
self.__size = size
def calcBackground(self) -> SpectralQty:
"""
@ -46,7 +43,7 @@ class ATarget(IRadiant):
logger.debug(background)
return background
def calcSignal(self) -> Tuple[SpectralQty, str, float]:
def calcSignal(self) -> Tuple[SpectralQty, float]:
"""
Calculate the spectral flux density of the target's signal
@ -54,14 +51,12 @@ class ATarget(IRadiant):
-------
signal : SpectralQty
The spectral flux density of the target's signal
size : str
The size of the target.
obstruction : float
The obstruction factor as A_ob / A_ap.
"""
logger.info("Calculating signal for class '" + self.__class__.__name__ + "'.")
logger.debug(self.__sfd)
return self.__sfd, self.__size, 0.0
return self.__sfd, 0.0
@staticmethod
@abstractmethod

View File

@ -24,9 +24,9 @@ class BlackBodyTarget(ATarget):
M=dict(wl=4800 * u.nm, sfd=2.07e-14 * u.W / (u.m ** 2 * u.nm)),
N=dict(wl=10200 * u.nm, sfd=1.23e-15 * u.W / (u.m ** 2 * u.nm)))
@u.quantity_input(wl_bins='length', temp=[u.Kelvin, u.Celsius], mag=u.mag)
def __init__(self, wl_bins: u.Quantity, temp: u.Quantity = 5778 * u.K,
mag: u.Quantity = 0 * u.mag, band: str = "V", size: str = "Point"):
@u.quantity_input(wl_bins='length', temp=[u.Kelvin, u.Celsius], mag=[u.mag, u.mag / u.sr])
def __init__(self, wl_bins: u.Quantity, temp: u.Quantity = 5778 * u.K, mag: u.Quantity = 0 * u.mag,
band: str = "V"):
"""
Initialize a new black body point source
@ -36,12 +36,11 @@ class BlackBodyTarget(ATarget):
Wavelengths used for binning
temp : Quantity in Kelvin / Celsius
Temperature of the black body
mag : Quantity in mag
Desired apparent magnitude of the point source
mag : Quantity in mag or mag / sr
Desired apparent magnitude of the black body source. If the magnitude is given in mag / sr or an equivalent
unit, an extended source will be assumed.
band : str
Band used for fitting the planck curve to a star of 0th magnitude. Can be one of [U, B, V, R, I, J, H, K].
size : str
The size of the target. Can be either point or extended
Returns
-------
@ -53,12 +52,18 @@ class BlackBodyTarget(ATarget):
# Calculate the correction factor for a star of 0th magnitude using the spectral flux density
# for the central wavelength of the given band
factor = self._band[band.upper()]["sfd"] / (bb(self._band[band.upper()]["wl"]) * u.sr) * u.sr
if mag.unit.is_equivalent(u.mag / u.sr):
solid_angle_unit = (u.mag / mag.unit)
mag = mag * solid_angle_unit
factor = self._band[band.upper()]["sfd"] / (bb(self._band[band.upper()]["wl"]) * (
solid_angle_unit.to(u.sr) * u.sr))
else:
factor = self._band[band.upper()]["sfd"] / (bb(self._band[band.upper()]["wl"]) * u.sr) * u.sr
# Calculate spectral flux density for the given wavelengths and scale it for a star of the given magnitude
sfd = bb(wl_bins) * factor * 10 ** (- 2 / 5 * mag / u.mag) # / 1.195 * 1.16 # scaling for AETC validation
# Initialize super class
super().__init__(SpectralQty(wl_bins, sfd), wl_bins, size)
super().__init__(SpectralQty(wl_bins, sfd), wl_bins)
@staticmethod
def check_config(conf: Entry) -> Union[None, str]:
@ -80,10 +85,9 @@ class BlackBodyTarget(ATarget):
return mes
mes = conf.check_quantity("mag", u.mag)
if mes is not None:
return mes
mes = conf.check_quantity("mag", u.mag / u.sr)
if mes is not None:
return mes
mes = conf.check_selection("band", ["U", "B", "V", "R", "I", "J", "H", "K", "L", "M", "N"])
if mes is not None:
return mes
mes = conf.check_selection("size", ["point", "extended"])
if mes is not None:
return mes

View File

@ -11,7 +11,7 @@ class FileTarget(ATarget):
"""
@u.quantity_input(wl_bins="length")
def __init__(self, file: str, wl_bins: u.Quantity, size: str = "Point"):
def __init__(self, file: str, wl_bins: u.Quantity):
"""
Initialize a new target from a file containing the spectral flux density values
@ -24,13 +24,11 @@ class FileTarget(ATarget):
will be read from the column headers or otherwise assumed to be *nm* and *W / m^2 / nm*.
wl_bins : length-Quantity
Wavelengths used for binning
size : str
The size of the target. Can be either point or extended.
"""
# Create spectral quantity from file
sfd = SpectralQty.fromFile(file, u.nm, u.W / (u.m ** 2 * u.nm))
# Initialize the super class
super().__init__(sfd, wl_bins, size)
super().__init__(sfd, wl_bins)
@staticmethod
def check_config(conf: Entry) -> Union[None, str]:
@ -50,6 +48,3 @@ class FileTarget(ATarget):
mes = conf.check_file("file")
if mes is not None:
return mes
mes = conf.check_selection("size", ["point", "extended"])
if mes is not None:
return mes