Bugfix: calculate extended target signal using spectral radiance values
This commit is contained in:
parent
1043a559b8
commit
e5b6e3b700
@ -9,7 +9,7 @@ class IRadiant(ABC):
|
|||||||
in the beam.
|
in the beam.
|
||||||
"""
|
"""
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def calcSignal(self) -> Tuple[SpectralQty, str, float]:
|
def calcSignal(self) -> Tuple[SpectralQty, float]:
|
||||||
"""
|
"""
|
||||||
Calculate the signal coming from the component
|
Calculate the signal coming from the component
|
||||||
|
|
||||||
@ -17,8 +17,6 @@ class IRadiant(ABC):
|
|||||||
-------
|
-------
|
||||||
signal : SpectralQty
|
signal : SpectralQty
|
||||||
The emitted, reflected or transmitted signal
|
The emitted, reflected or transmitted signal
|
||||||
size : str
|
|
||||||
The size of the target.
|
|
||||||
obstruction : float
|
obstruction : float
|
||||||
The obstruction factor as A_ob / A_ap.
|
The obstruction factor as A_ob / A_ap.
|
||||||
"""
|
"""
|
||||||
|
@ -51,7 +51,7 @@ class AOpticalComponent(IRadiant):
|
|||||||
self.__obstructor_temp = obstructor_temp
|
self.__obstructor_temp = obstructor_temp
|
||||||
self.__obstructor_emissivity = obstructor_emissivity
|
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
|
Calculate the spectral flux density of the target's signal
|
||||||
|
|
||||||
@ -59,17 +59,15 @@ class AOpticalComponent(IRadiant):
|
|||||||
-------
|
-------
|
||||||
signal : SpectralQty
|
signal : SpectralQty
|
||||||
The spectral flux density of the target's signal
|
The spectral flux density of the target's signal
|
||||||
size : str
|
|
||||||
The size of the target.
|
|
||||||
obstruction : float
|
obstruction : float
|
||||||
The obstruction factor as A_ob / A_ap.
|
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__ + "'.")
|
logger.info("Calculating signal for class '" + self.__class__.__name__ + "'.")
|
||||||
signal = self._propagate(signal) * (1 - self.__obstruction)
|
signal = self._propagate(signal) * (1 - self.__obstruction)
|
||||||
obstruction = obstruction + self.__obstruction
|
obstruction = obstruction + self.__obstruction
|
||||||
logger.debug(signal)
|
logger.debug(signal)
|
||||||
return signal, size, obstruction
|
return signal, obstruction
|
||||||
|
|
||||||
def calcBackground(self) -> SpectralQty:
|
def calcBackground(self) -> SpectralQty:
|
||||||
"""
|
"""
|
||||||
|
@ -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)
|
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
|
# Calculate the incoming photon current of the target
|
||||||
logger.info("Calculating the signal photon current.")
|
logger.info("Calculating the signal photon current.")
|
||||||
signal, size, obstruction = self._parent.calcSignal()
|
signal, obstruction = self._parent.calcSignal()
|
||||||
signal_photon_current = signal * np.pi * (self.__common_conf.d_aperture() / 2) ** 2
|
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
|
# Calculate the electron current of the background and thereby handling the photon energy as lambda-function
|
||||||
background_current = (
|
background_current = (
|
||||||
background_photon_current / (lambda wl: (const.h * const.c / wl).to(u.W * u.s) / u.photon) *
|
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
|
return "pixel -> well_capacity: " + mes
|
||||||
|
|
||||||
# Check photometric aperture
|
# Check photometric aperture
|
||||||
if conf.astroscene.target.size == "point":
|
if not hasattr(sensor, "photometric_aperture"):
|
||||||
if not hasattr(sensor, "photometric_aperture"):
|
setattr(sensor, "photometric_aperture", Entry(shape=Entry(val="circle"),
|
||||||
setattr(sensor, "photometric_aperture", Entry(shape=Entry(val="circle"),
|
contained_energy=Entry(val="FWHM")))
|
||||||
contained_energy=Entry(val="FWHM")))
|
if hasattr(sensor.photometric_aperture, "contained_pixels"):
|
||||||
if hasattr(sensor.photometric_aperture, "contained_pixels"):
|
mes = sensor.photometric_aperture.contained_pixels.check_quantity("val", u.pix)
|
||||||
mes = sensor.photometric_aperture.contained_pixels.check_quantity("val", u.pix)
|
if mes is not None:
|
||||||
if mes is not None:
|
return "photometric_aperture -> contained_pixels: " + mes
|
||||||
return "photometric_aperture -> contained_pixels: " + mes
|
else:
|
||||||
else:
|
if not hasattr(sensor.photometric_aperture, "shape"):
|
||||||
if not hasattr(sensor.photometric_aperture, "shape"):
|
return "Missing container 'shape'."
|
||||||
return "Missing container 'shape'."
|
mes = sensor.photometric_aperture.shape.check_selection("val", ["square", "circle"])
|
||||||
mes = sensor.photometric_aperture.shape.check_selection("val", ["square", "circle"])
|
if mes is not None:
|
||||||
if mes is not None:
|
return "photometric_aperture -> shape: " + mes
|
||||||
return "photometric_aperture -> shape: " + mes
|
if not hasattr(sensor.photometric_aperture, "contained_energy"):
|
||||||
if not hasattr(sensor.photometric_aperture, "contained_energy"):
|
return "Missing container 'contained_energy'."
|
||||||
return "Missing container 'contained_energy'."
|
mes = sensor.photometric_aperture.contained_energy.check_float("val")
|
||||||
mes = sensor.photometric_aperture.contained_energy.check_float("val")
|
if mes is not None:
|
||||||
if mes is not None:
|
if conf.common.psf().lower() == "airy":
|
||||||
if conf.common.psf().lower() == "airy":
|
mes = sensor.photometric_aperture.contained_energy.check_selection("val",
|
||||||
mes = sensor.photometric_aperture.contained_energy.check_selection("val",
|
["peak", "FWHM", "fwhm",
|
||||||
["peak", "FWHM", "fwhm",
|
"min"])
|
||||||
"min"])
|
if mes is not None:
|
||||||
if mes is not None:
|
return "photometric_aperture -> contained_energy: " + mes
|
||||||
return "photometric_aperture -> contained_energy: " + mes
|
else:
|
||||||
else:
|
mes = sensor.photometric_aperture.contained_energy.check_selection("val", ["FWHM", "fwhm"])
|
||||||
mes = sensor.photometric_aperture.contained_energy.check_selection("val", ["FWHM", "fwhm"])
|
if mes is not None:
|
||||||
if mes is not None:
|
return "photometric_aperture -> contained_energy: " + mes
|
||||||
return "photometric_aperture -> contained_energy: " + mes
|
|
||||||
|
@ -15,7 +15,7 @@ class ATarget(IRadiant):
|
|||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@u.quantity_input(wl_bins="length")
|
@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
|
Initialize a new target
|
||||||
|
|
||||||
@ -25,12 +25,9 @@ class ATarget(IRadiant):
|
|||||||
The spectral flux density of the target
|
The spectral flux density of the target
|
||||||
wl_bins : length-Quantity
|
wl_bins : length-Quantity
|
||||||
The bins to be used for evaluating spectral quantities.
|
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.__sfd = sfd
|
||||||
self.__wl_bins = wl_bins
|
self.__wl_bins = wl_bins
|
||||||
self.__size = size
|
|
||||||
|
|
||||||
def calcBackground(self) -> SpectralQty:
|
def calcBackground(self) -> SpectralQty:
|
||||||
"""
|
"""
|
||||||
@ -46,7 +43,7 @@ class ATarget(IRadiant):
|
|||||||
logger.debug(background)
|
logger.debug(background)
|
||||||
return 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
|
Calculate the spectral flux density of the target's signal
|
||||||
|
|
||||||
@ -54,14 +51,12 @@ class ATarget(IRadiant):
|
|||||||
-------
|
-------
|
||||||
signal : SpectralQty
|
signal : SpectralQty
|
||||||
The spectral flux density of the target's signal
|
The spectral flux density of the target's signal
|
||||||
size : str
|
|
||||||
The size of the target.
|
|
||||||
obstruction : float
|
obstruction : float
|
||||||
The obstruction factor as A_ob / A_ap.
|
The obstruction factor as A_ob / A_ap.
|
||||||
"""
|
"""
|
||||||
logger.info("Calculating signal for class '" + self.__class__.__name__ + "'.")
|
logger.info("Calculating signal for class '" + self.__class__.__name__ + "'.")
|
||||||
logger.debug(self.__sfd)
|
logger.debug(self.__sfd)
|
||||||
return self.__sfd, self.__size, 0.0
|
return self.__sfd, 0.0
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
@ -24,9 +24,9 @@ class BlackBodyTarget(ATarget):
|
|||||||
M=dict(wl=4800 * u.nm, sfd=2.07e-14 * u.W / (u.m ** 2 * u.nm)),
|
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)))
|
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)
|
@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,
|
def __init__(self, wl_bins: u.Quantity, temp: u.Quantity = 5778 * u.K, mag: u.Quantity = 0 * u.mag,
|
||||||
mag: u.Quantity = 0 * u.mag, band: str = "V", size: str = "Point"):
|
band: str = "V"):
|
||||||
"""
|
"""
|
||||||
Initialize a new black body point source
|
Initialize a new black body point source
|
||||||
|
|
||||||
@ -36,12 +36,11 @@ class BlackBodyTarget(ATarget):
|
|||||||
Wavelengths used for binning
|
Wavelengths used for binning
|
||||||
temp : Quantity in Kelvin / Celsius
|
temp : Quantity in Kelvin / Celsius
|
||||||
Temperature of the black body
|
Temperature of the black body
|
||||||
mag : Quantity in mag
|
mag : Quantity in mag or mag / sr
|
||||||
Desired apparent magnitude of the point source
|
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 : 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].
|
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
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -53,12 +52,18 @@ class BlackBodyTarget(ATarget):
|
|||||||
|
|
||||||
# Calculate the correction factor for a star of 0th magnitude using the spectral flux density
|
# Calculate the correction factor for a star of 0th magnitude using the spectral flux density
|
||||||
# for the central wavelength of the given band
|
# 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
|
# 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
|
sfd = bb(wl_bins) * factor * 10 ** (- 2 / 5 * mag / u.mag) # / 1.195 * 1.16 # scaling for AETC validation
|
||||||
|
|
||||||
# Initialize super class
|
# Initialize super class
|
||||||
super().__init__(SpectralQty(wl_bins, sfd), wl_bins, size)
|
super().__init__(SpectralQty(wl_bins, sfd), wl_bins)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_config(conf: Entry) -> Union[None, str]:
|
def check_config(conf: Entry) -> Union[None, str]:
|
||||||
@ -80,10 +85,9 @@ class BlackBodyTarget(ATarget):
|
|||||||
return mes
|
return mes
|
||||||
mes = conf.check_quantity("mag", u.mag)
|
mes = conf.check_quantity("mag", u.mag)
|
||||||
if mes is not None:
|
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"])
|
mes = conf.check_selection("band", ["U", "B", "V", "R", "I", "J", "H", "K", "L", "M", "N"])
|
||||||
if mes is not None:
|
if mes is not None:
|
||||||
return mes
|
return mes
|
||||||
mes = conf.check_selection("size", ["point", "extended"])
|
|
||||||
if mes is not None:
|
|
||||||
return mes
|
|
||||||
|
@ -11,7 +11,7 @@ class FileTarget(ATarget):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@u.quantity_input(wl_bins="length")
|
@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
|
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*.
|
will be read from the column headers or otherwise assumed to be *nm* and *W / m^2 / nm*.
|
||||||
wl_bins : length-Quantity
|
wl_bins : length-Quantity
|
||||||
Wavelengths used for binning
|
Wavelengths used for binning
|
||||||
size : str
|
|
||||||
The size of the target. Can be either point or extended.
|
|
||||||
"""
|
"""
|
||||||
# Create spectral quantity from file
|
# Create spectral quantity from file
|
||||||
sfd = SpectralQty.fromFile(file, u.nm, u.W / (u.m ** 2 * u.nm))
|
sfd = SpectralQty.fromFile(file, u.nm, u.W / (u.m ** 2 * u.nm))
|
||||||
# Initialize the super class
|
# Initialize the super class
|
||||||
super().__init__(sfd, wl_bins, size)
|
super().__init__(sfd, wl_bins)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_config(conf: Entry) -> Union[None, str]:
|
def check_config(conf: Entry) -> Union[None, str]:
|
||||||
@ -50,6 +48,3 @@ class FileTarget(ATarget):
|
|||||||
mes = conf.check_file("file")
|
mes = conf.check_file("file")
|
||||||
if mes is not None:
|
if mes is not None:
|
||||||
return mes
|
return mes
|
||||||
mes = conf.check_selection("size", ["point", "extended"])
|
|
||||||
if mes is not None:
|
|
||||||
return mes
|
|
||||||
|
Loading…
Reference in New Issue
Block a user