Functions vectorized
This commit is contained in:
parent
86e47b356a
commit
ef36ab908d
@ -108,11 +108,15 @@ class Imager(ASensor):
|
|||||||
"""
|
"""
|
||||||
# Calculate the electron currents
|
# Calculate the electron currents
|
||||||
signal_current, background_current, read_noise, dark_current = self.__exposePixels()
|
signal_current, background_current, read_noise, dark_current = self.__exposePixels()
|
||||||
# Calculate the number of collected electrons
|
# Calculate the SNR using the CCD-equation
|
||||||
signal = signal_current * exp_time
|
snr = signal_current.sum() * exp_time / np.sqrt(
|
||||||
background = background_current * exp_time
|
(signal_current + background_current + dark_current).sum() * exp_time + (read_noise ** 2).sum())
|
||||||
dark = dark_current * exp_time
|
for exp_time_ in exp_time:
|
||||||
return self.__calcSNR(signal, background, read_noise, dark)
|
# Print information
|
||||||
|
self.__printDetails(signal_current * exp_time_, background_current * exp_time_, read_noise,
|
||||||
|
dark_current * exp_time_, "t_exp=%.2f s: " % exp_time_.value)
|
||||||
|
# Return the value of the SNR, ignoring the physical units (electrons^0.5)
|
||||||
|
return snr.value * u.dimensionless_unscaled
|
||||||
|
|
||||||
@u.quantity_input(snr=u.dimensionless_unscaled)
|
@u.quantity_input(snr=u.dimensionless_unscaled)
|
||||||
def getExpTime(self, snr: u.Quantity) -> u.s:
|
def getExpTime(self, snr: u.Quantity) -> u.s:
|
||||||
@ -137,16 +141,18 @@ class Imager(ASensor):
|
|||||||
read_noise_tot = read_noise.sum()
|
read_noise_tot = read_noise.sum()
|
||||||
dark_current_tot = dark_current.sum()
|
dark_current_tot = dark_current.sum()
|
||||||
# Fix the physical units of the SNR
|
# Fix the physical units of the SNR
|
||||||
snr = snr * u.electron**0.5
|
snr = snr * u.electron ** 0.5
|
||||||
|
|
||||||
# Calculate the ratio of the background- and dark-current to the signal current as auxiliary variable
|
# Calculate the ratio of the background- and dark-current to the signal current as auxiliary variable
|
||||||
current_ratio = (background_current_tot + dark_current_tot) / signal_current_tot
|
current_ratio = (background_current_tot + dark_current_tot) / signal_current_tot
|
||||||
# Calculate the necessary exposure time as inverse of the CCD-equation
|
# Calculate the necessary exposure time as inverse of the CCD-equation
|
||||||
exp_time = snr ** 2 * (
|
exp_time = snr ** 2 * (
|
||||||
1 + current_ratio + np.sqrt((1 + current_ratio) ** 2 + 4 * read_noise_tot ** 2 / snr ** 2)) / (
|
1 + current_ratio + np.sqrt((1 + current_ratio) ** 2 + 4 * read_noise_tot ** 2 / snr ** 2)) / (
|
||||||
2 * signal_current_tot)
|
2 * signal_current_tot)
|
||||||
# Calculate the SNR in order to check for overexposed pixels
|
for snr_, exp_time_ in zip(snr, exp_time):
|
||||||
self.__calcSNR(signal_current * exp_time, background_current * exp_time, read_noise, dark_current * exp_time)
|
# Print information
|
||||||
|
self.__printDetails(signal_current * exp_time_, background_current * exp_time_, read_noise,
|
||||||
|
dark_current * exp_time_, "SNR=%.2f: " % snr_.value)
|
||||||
return exp_time
|
return exp_time
|
||||||
|
|
||||||
@u.quantity_input(exp_time="time", snr=u.dimensionless_unscaled, target_brightness=u.mag)
|
@u.quantity_input(exp_time="time", snr=u.dimensionless_unscaled, target_brightness=u.mag)
|
||||||
@ -173,15 +179,18 @@ class Imager(ASensor):
|
|||||||
# Fix the physical units of the SNR
|
# Fix the physical units of the SNR
|
||||||
snr = snr * u.electron ** 0.5
|
snr = snr * u.electron ** 0.5
|
||||||
signal_current_lim = snr * (snr + np.sqrt(
|
signal_current_lim = snr * (snr + np.sqrt(
|
||||||
snr ** 2 + 4 * (exp_time * (background_current.sum() + dark_current.sum()) + (read_noise ** 2).sum()))) / (
|
snr ** 2 + 4 * (exp_time * (background_current.sum() + dark_current.sum()) +
|
||||||
2 * exp_time)
|
(read_noise ** 2).sum()))) / (2 * exp_time)
|
||||||
self.__calcSNR(signal_current_lim * exp_time, background_current * exp_time, read_noise,
|
for snr_, exp_time_, signal_current_lim_ in zip(snr, exp_time, signal_current_lim):
|
||||||
dark_current * exp_time)
|
# Print information
|
||||||
|
self.__printDetails(signal_current_lim_ * exp_time_, background_current * exp_time_, read_noise,
|
||||||
|
dark_current * exp_time_,
|
||||||
|
"SNR=%.2f t_exp=%.2f s: " % (snr_.value, exp_time_.value))
|
||||||
return target_brightness - 2.5 * np.log10(signal_current_lim / signal_current.sum()) * u.mag
|
return target_brightness - 2.5 * np.log10(signal_current_lim / signal_current.sum()) * u.mag
|
||||||
|
|
||||||
@u.quantity_input(signal=u.electron, background=u.electron, read_noise=u.electron ** 0.5, dark=u.electron)
|
@u.quantity_input(signal=u.electron, background=u.electron, read_noise=u.electron ** 0.5, dark=u.electron)
|
||||||
def __calcSNR(self, signal: u.Quantity, background: u.Quantity, read_noise: u.Quantity,
|
def __printDetails(self, signal: u.Quantity, background: u.Quantity, read_noise: u.Quantity,
|
||||||
dark: u.Quantity) -> u.dimensionless_unscaled:
|
dark: u.Quantity, prefix: str = ""):
|
||||||
"""
|
"""
|
||||||
Calculate the signal to noise ratio (SNR) of the given electron counts.
|
Calculate the signal to noise ratio (SNR) of the given electron counts.
|
||||||
|
|
||||||
@ -198,8 +207,6 @@ class Imager(ASensor):
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
snr : Quantity
|
|
||||||
The signal to noise ration as dimensionless quantity
|
|
||||||
"""
|
"""
|
||||||
# Calculate the total collected electrons per pixel
|
# Calculate the total collected electrons per pixel
|
||||||
total = signal + background + dark
|
total = signal + background + dark
|
||||||
@ -207,16 +214,12 @@ class Imager(ASensor):
|
|||||||
overexposed = total > self.__well_capacity
|
overexposed = total > self.__well_capacity
|
||||||
if np.any(overexposed):
|
if np.any(overexposed):
|
||||||
# Show a warning for the overexposed pixels
|
# Show a warning for the overexposed pixels
|
||||||
warning(str(np.count_nonzero(overexposed)) + " pixels are overexposed.")
|
warning(prefix + str(np.count_nonzero(overexposed)) + " pixels are overexposed.")
|
||||||
info("Collected electrons from target: %1.2e electrons" % signal.sum().value)
|
info(prefix + "Collected electrons from target: %1.2e electrons" % signal.sum().value)
|
||||||
info("Collected electrons from background: %1.2e electrons" % background.sum().value)
|
info(prefix + "Collected electrons from background: %1.2e electrons" % background.sum().value)
|
||||||
info("Electrons from dark current: %1.2e electrons" % dark.sum().value)
|
info(prefix + "Electrons from dark current: %1.2e electrons" % dark.sum().value)
|
||||||
info("Read noise: %1.2e electrons" % (read_noise ** 2).sum().value)
|
info(prefix + "Read noise: %1.2e electrons" % (read_noise ** 2).sum().value)
|
||||||
info("Total collected electrons: %1.2e electrons" % total.sum().value)
|
info(prefix + "Total collected electrons: %1.2e electrons" % total.sum().value)
|
||||||
# Calculate the SNR using the CCD-equation
|
|
||||||
snr = signal.sum() / np.sqrt(total.sum() + (read_noise ** 2).sum())
|
|
||||||
# Return the value of the SNR, ignoring the physical units (electrons^0.5)
|
|
||||||
return snr.value * u.dimensionless_unscaled
|
|
||||||
|
|
||||||
def __exposePixels(self) -> Tuple[u.Quantity, u.Quantity, u.Quantity, u.Quantity]:
|
def __exposePixels(self) -> Tuple[u.Quantity, u.Quantity, u.Quantity, u.Quantity]:
|
||||||
"""
|
"""
|
||||||
|
@ -2,6 +2,7 @@ import esbo_etc as eetc
|
|||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(prog="esbo_etc/esbo-etc.py", description='Exposure time calculator for ESBO-DS')
|
parser = argparse.ArgumentParser(prog="esbo_etc/esbo-etc.py", description='Exposure time calculator for ESBO-DS')
|
||||||
@ -26,10 +27,10 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
if hasattr(conf.common, "exposure_time") and hasattr(conf.common, "snr"):
|
if hasattr(conf.common, "exposure_time") and hasattr(conf.common, "snr"):
|
||||||
sensitivity = imager.getSensitivity(conf.common.exposure_time(), conf.common.snr(), conf.astroscene.target.mag)
|
sensitivity = imager.getSensitivity(conf.common.exposure_time(), conf.common.snr(), conf.astroscene.target.mag)
|
||||||
print("The limiting apparent magnitude is: %.2f mag." % sensitivity.value)
|
print("The limiting apparent magnitude is: " + str(np.array2string(sensitivity.value, precision=2)) + " mag.")
|
||||||
elif hasattr(conf.common, "exposure_time"):
|
elif hasattr(conf.common, "exposure_time"):
|
||||||
snr = imager.getSNR(conf.common.exposure_time())
|
snr = imager.getSNR(conf.common.exposure_time())
|
||||||
print("The SNR is: %.2f." % snr.value)
|
print("The SNR is: " + str(np.array2string(snr.value, precision=2)) + ".")
|
||||||
elif hasattr(conf.common, "snr"):
|
elif hasattr(conf.common, "snr"):
|
||||||
exp_time = imager.getExpTime(conf.common.snr())
|
exp_time = imager.getExpTime(conf.common.snr())
|
||||||
print("The necessary exposure time is: %.2f s." % exp_time.value)
|
print("The necessary exposure time is: " + str(np.array2string(exp_time.value, precision=2)) + " s.")
|
||||||
|
Loading…
Reference in New Issue
Block a user