Compare commits
12 Commits
b7750ee029
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ca66cd142 | |||
| 8a783405bb | |||
| 66c10e2f31 | |||
|
|
cd49a9044f | ||
|
|
9d4c41dc05 | ||
|
|
b61261f11c | ||
|
|
75b1a5376d | ||
|
|
5c9bce4b3f | ||
|
|
2a48df15c9 | ||
|
|
47659dc918 | ||
|
|
65f11e6764 | ||
| ce817b64a1 |
@@ -52,4 +52,7 @@ if __name__ == "__main__":
|
|||||||
if args.verbose:
|
if args.verbose:
|
||||||
print("\nALL DONE")
|
print("\nALL DONE")
|
||||||
|
|
||||||
|
if not args.verbose:
|
||||||
|
print("best focus value is {:g}".format(result["focus_value"]))
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|||||||
35
focus_app.py
35
focus_app.py
@@ -125,6 +125,10 @@ def focussing_app(parser, init_seq_func, set_focus_func, get_image_func):
|
|||||||
pt.with_stem(pt.stem + "_rough")
|
pt.with_stem(pt.stem + "_rough")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# rough estimation: be sure that only a single
|
||||||
|
# acquisition per focus value
|
||||||
|
seq_rough_kwds["acq_per_value"] = 1
|
||||||
|
|
||||||
result = obsutil.focussingSequence(
|
result = obsutil.focussingSequence(
|
||||||
[focus_start, focus_stop],
|
[focus_start, focus_stop],
|
||||||
init_seq_func,
|
init_seq_func,
|
||||||
@@ -141,13 +145,14 @@ def focussing_app(parser, init_seq_func, set_focus_func, get_image_func):
|
|||||||
return result["ret_code"]
|
return result["ret_code"]
|
||||||
|
|
||||||
# compute precise range start and stop values
|
# compute precise range start and stop values
|
||||||
r = args.num * focus_step / 2.0
|
r = (args.num - 1) * focus_step / 2.0
|
||||||
focus_start = result["focus_value"] - r
|
focus_start = result["focus_value"] - r
|
||||||
focus_stop = result["focus_value"] + r
|
focus_stop = result["focus_value"] + r
|
||||||
|
|
||||||
if args.verbose:
|
if args.verbose:
|
||||||
|
print("\n\t\t rough focus position: {:g}".format(result["focus_value"]))
|
||||||
print(
|
print(
|
||||||
"\testimate guess focus position in range of [{:g},{:g}]".format(
|
"\t\testimate guess focus position in range of [{:g},{:g}]".format(
|
||||||
focus_start, focus_stop
|
focus_start, focus_stop
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -173,16 +178,36 @@ def focussing_app(parser, init_seq_func, set_focus_func, get_image_func):
|
|||||||
**seq_kwds
|
**seq_kwds
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if result["ret_code"]:
|
||||||
if args.verbose:
|
if args.verbose:
|
||||||
print("\tThe best focus value: {:g}".format(result["focus_value"]))
|
print(
|
||||||
|
"\tFocussing sequence returned error code: {:g}".format(
|
||||||
|
result["ret_code"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
print("\tCannot set best focus value!")
|
||||||
|
|
||||||
|
return result["ret_code"]
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
print("\n\tThe best focus value: {:g}".format(result["focus_value"]))
|
||||||
|
|
||||||
|
ret_code = 0
|
||||||
|
|
||||||
if not args.do_not_set:
|
if not args.do_not_set:
|
||||||
if args.verbose:
|
if args.verbose:
|
||||||
print("\n\tSet focus to the best value ...", end="")
|
print("\n\tSet focus to the best value ...", end="")
|
||||||
set_focus_func(result["focus_value"])
|
|
||||||
|
ret_code = set_focus_func(result["focus_value"])
|
||||||
|
|
||||||
|
if ret_code:
|
||||||
|
if args.verbose:
|
||||||
|
print("\tFAILED")
|
||||||
|
else:
|
||||||
|
if args.verbose:
|
||||||
print("\tOK")
|
print("\tOK")
|
||||||
|
|
||||||
if args.verbose:
|
if args.verbose:
|
||||||
print("DONE.")
|
print("DONE.")
|
||||||
|
|
||||||
return 0
|
return ret_code
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
# This variant of the script uses Eddy Emelianov's
|
# This variant of the script uses Eddy Emelianov's
|
||||||
# 'fli_control' executable
|
# 'fli_control' executable
|
||||||
#
|
#
|
||||||
|
# 27.04.2026 (Fatkhullin T.A.)
|
||||||
|
# changes according to Eddy Emelianov's "ccd_capture" executable
|
||||||
|
# (a new age FLI hardware control software)
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
from OBSUTILS import focussing_app
|
from OBSUTILS import focussing_app
|
||||||
@@ -16,32 +20,71 @@ import subprocess as sp
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import pathlib as pl
|
import pathlib as pl
|
||||||
|
|
||||||
|
|
||||||
# --- FLI-hardware related (ROBOTEL variant)
|
# --- FLI-hardware related (ROBOTEL variant)
|
||||||
|
|
||||||
|
# common "ccd_capture" executable commandline options
|
||||||
|
ccd_capture_cmd_common = [
|
||||||
|
"ccd_capture",
|
||||||
|
"-VVV",
|
||||||
|
"--plugin",
|
||||||
|
"libdevfli.so",
|
||||||
|
"-r",
|
||||||
|
"/tmp/10micron.fitsheader",
|
||||||
|
"-r",
|
||||||
|
"/tmp/telescope.fitsheader",
|
||||||
|
"-r",
|
||||||
|
"/tmp/dome.fitsheader",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def init_seq(seq_kwds):
|
def init_seq(seq_kwds):
|
||||||
# remove extension as Eddy's 'fli_control' add hardcoded '.fit'
|
# # replace extension since Eddy's 'fli_control' adds hardcoded '.fit'
|
||||||
pt = pl.Path(seq_kwds["root_filename"]).with_suffix("")
|
# pt = pl.Path(seq_kwds["root_filename"]).with_suffix(".fit")
|
||||||
|
# seq_kwds["root_filename"] = str(pt)
|
||||||
|
|
||||||
|
pt = pl.Path(seq_kwds["root_filename"])
|
||||||
|
if not len(pt.suffix):
|
||||||
|
pt.with_suffix(".fits")
|
||||||
seq_kwds["root_filename"] = str(pt)
|
seq_kwds["root_filename"] = str(pt)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
# search for existing files
|
||||||
|
# and compute start index of focus file
|
||||||
#
|
#
|
||||||
|
|
||||||
foc_files = list(
|
foc_files = list(
|
||||||
pt.absolute().parent.glob("{}_[0-9][0-9][0-9][0-9].fit".format(pt.stem))
|
# 27.04.2026
|
||||||
|
pt.absolute().parent.glob(
|
||||||
|
"{}_[0-9][0-9][0-9][0-9]{}".format(pt.stem, pt.suffix)
|
||||||
|
)
|
||||||
|
# pt.absolute().parent.glob("{}_[0-9][0-9][0-9][0-9].fit".format(pt.stem))
|
||||||
)
|
)
|
||||||
|
|
||||||
seq_kwds["start_idx"] = 1
|
seq_kwds["start_idx"] = 1
|
||||||
N = len(foc_files)
|
N = len(foc_files)
|
||||||
if N > 0:
|
if N > 0:
|
||||||
seq_kwds["start_idx"] = N
|
max = 0
|
||||||
|
for fname in foc_files:
|
||||||
|
inum = int(fname.stem.split("_")[1])
|
||||||
|
if inum > max:
|
||||||
|
max = inum
|
||||||
|
|
||||||
|
seq_kwds["start_idx"] = max + 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def set_focus(foc_val):
|
def set_focus(foc_val):
|
||||||
cmd = ["fli_control", "-g", str(int(foc_val))]
|
if foc_val < 0:
|
||||||
|
print("INVALID FLI-FOCUSER VALUE! IT MUST BE NON-NEGATIVE VALUE!")
|
||||||
|
return -1
|
||||||
|
|
||||||
|
# cmd = ["fli_control", "-g", str(int(foc_val))]
|
||||||
|
|
||||||
|
# 27.04.2026
|
||||||
|
# cmd = ["ccd_capture", "-VVV", "--plugin", "libdevfli.so", "-r", "/tmp/10micron.fitsheader", "-r", "/tmp/telescope.fitsheader", "-r", "/tmp/dome.fitsheader", "-g", str(foc_val)]
|
||||||
|
cmd = ccd_capture_cmd_common + ["-g", str(foc_val)]
|
||||||
|
|
||||||
ret = sp.run(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
|
ret = sp.run(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
|
||||||
return ret.returncode
|
return ret.returncode
|
||||||
|
|
||||||
@@ -51,19 +94,22 @@ def get_image(filename, exp_time):
|
|||||||
# Eddy's 'fli_control' related stub:
|
# Eddy's 'fli_control' related stub:
|
||||||
# filename is expected in form 'rootname_DDDD.ext'
|
# filename is expected in form 'rootname_DDDD.ext'
|
||||||
# convert it to 'rootname'
|
# convert it to 'rootname'
|
||||||
#
|
|
||||||
|
|
||||||
fname = str(filename).split("_")
|
# fname = str(filename).split("_")
|
||||||
fname = fname[0]
|
# fname = fname[0]
|
||||||
|
|
||||||
cmd = [
|
# cmd = [
|
||||||
"fli_control",
|
# "fli_control",
|
||||||
"-r",
|
# "-r",
|
||||||
"/tmp/10micron.fitsheader",
|
# "/tmp/10micron.fitsheader",
|
||||||
"-x",
|
# "-x",
|
||||||
"{:d}".format(np.round(exp_time * 1000)), # to microseconds
|
# "{:d}".format(int(np.round(exp_time * 1000))), # to microseconds
|
||||||
fname,
|
# fname,
|
||||||
]
|
# ]
|
||||||
|
|
||||||
|
# 27.04.2026
|
||||||
|
# cmd = ["ccd_capture", "-VVV", "--plugin", "libdevfli.so", "-r", "/tmp/10micron.fitsheader", "-r", "/tmp/telescope.fitsheader", "-r", "/tmp/dome.fitsheader", "-x", str(exp_time), "-o", filename]
|
||||||
|
cmd = ccd_capture_cmd_common + ["-x", str(exp_time), "-o", filename]
|
||||||
|
|
||||||
ret = sp.run(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
|
ret = sp.run(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
|
||||||
return ret.returncode
|
return ret.returncode
|
||||||
@@ -72,7 +118,9 @@ def get_image(filename, exp_time):
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = ap.ArgumentParser(
|
parser = ap.ArgumentParser(
|
||||||
prog="{}".format(pl.Path(sys.argv[0]).name),
|
prog="{}".format(pl.Path(sys.argv[0]).name),
|
||||||
description="FLI CCD and focuser hardware: focussing sequence implementation. It is assumed that 'fli_control' software is installed in the OS.",
|
# 27.04.2026
|
||||||
|
description="FLI CCD and focuser hardware: focussing sequence implementation. It is assumed that 'ccd_capture' software is installed in the OS.",
|
||||||
|
# description="FLI CCD and focuser hardware: focussing sequence implementation. It is assumed that 'fli_control' software is installed in the OS.",
|
||||||
)
|
)
|
||||||
|
|
||||||
ret = focussing_app(parser, init_seq, set_focus, get_image)
|
ret = focussing_app(parser, init_seq, set_focus, get_image)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import subprocess as sp
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import socket
|
import socket
|
||||||
import pathlib as pl
|
import pathlib as pl
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
def init_seq(seq_kwds):
|
def init_seq(seq_kwds):
|
||||||
@@ -30,7 +31,13 @@ def init_seq(seq_kwds):
|
|||||||
seq_kwds["start_idx"] = 1
|
seq_kwds["start_idx"] = 1
|
||||||
N = len(foc_files)
|
N = len(foc_files)
|
||||||
if N > 0:
|
if N > 0:
|
||||||
seq_kwds["start_idx"] = N
|
max = 0
|
||||||
|
for fname in foc_files:
|
||||||
|
inum = int(fname.stem.split("_")[1])
|
||||||
|
if inum > max:
|
||||||
|
max = inum
|
||||||
|
|
||||||
|
seq_kwds["start_idx"] = max + 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -39,13 +46,28 @@ def set_focus(foc_val):
|
|||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
sock.connect(("ztcs.sao.ru", 4444))
|
sock.connect(("ztcs.sao.ru", 4444))
|
||||||
|
|
||||||
sock.send("goto={:g}".format(foc_val))
|
bt = bytearray("goto={:g}".format(foc_val), 'utf8')
|
||||||
resp = sock.recv(20)
|
|
||||||
|
sock.send(bt)
|
||||||
|
resp = sock.recv(20).decode('utf8')
|
||||||
|
|
||||||
if resp != "OK":
|
if resp != "OK":
|
||||||
sock.close()
|
sock.close()
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
tp_start = time.monotonic()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
time.sleep(0.5)
|
||||||
|
sock.send(b'status')
|
||||||
|
resp = sock.recv(20).decode('utf8')
|
||||||
|
if resp == 'OK':
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (time.monotonic()-tp_start) > 30.0:
|
||||||
|
sock.close() # timeout!
|
||||||
|
return 2
|
||||||
|
|
||||||
sock.close()
|
sock.close()
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
@@ -55,7 +77,7 @@ def set_focus(foc_val):
|
|||||||
# Assumes Andor IXon EMCCD server is listenning UNIX socket on localhost
|
# Assumes Andor IXon EMCCD server is listenning UNIX socket on localhost
|
||||||
#
|
#
|
||||||
def get_image(filename, exp_time):
|
def get_image(filename, exp_time):
|
||||||
cmd = ["ixonultra_cmdclient", "-A", "CCD", "-T", "{:g}".format(exp_time), filename]
|
cmd = ["ixonultra_cmdclient", "-A", "CCD", "-p", "1", "--hs", "0", "-T", "{:g}".format(exp_time), filename]
|
||||||
|
|
||||||
ret = sp.run(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
|
ret = sp.run(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
|
||||||
return ret.returncode
|
return ret.returncode
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ import subprocess as sp
|
|||||||
|
|
||||||
|
|
||||||
def set_focus(foc_val):
|
def set_focus(foc_val):
|
||||||
|
if foc_val < 0:
|
||||||
|
print("INVALID FLI-FOCUSER VALUE! IT MUST BE NON-NEGATIVE VALUE!")
|
||||||
|
return -1
|
||||||
cmd = ["fli_control", "-g", str(int(foc_val))]
|
cmd = ["fli_control", "-g", str(int(foc_val))]
|
||||||
ret = sp.run(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
|
ret = sp.run(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
|
||||||
return ret.returncode
|
return ret.returncode
|
||||||
@@ -159,8 +162,11 @@ if __name__ == "__main__":
|
|||||||
focus_stop = result["focus_value"] + r
|
focus_stop = result["focus_value"] + r
|
||||||
|
|
||||||
if args.verbose:
|
if args.verbose:
|
||||||
print("\testimate guess focus position in range [{:g},{:g}]".format(focus_start, focus_stop))
|
print(
|
||||||
|
"\testimate guess focus position in range [{:g},{:g}]".format(
|
||||||
|
focus_start, focus_stop
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if np.isfinite(args.focus_step):
|
if np.isfinite(args.focus_step):
|
||||||
result = obsutil.focussingSequence(
|
result = obsutil.focussingSequence(
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ def set_focus(foc_val):
|
|||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
sock.connect(("ztcs.sao.ru", 4444))
|
sock.connect(("ztcs.sao.ru", 4444))
|
||||||
|
|
||||||
sock.send("goto={:g}".format(foc_val))
|
print(foc_val)
|
||||||
|
sock.send("goto={:f}".format(foc_val))
|
||||||
resp = sock.recv(20)
|
resp = sock.recv(20)
|
||||||
|
|
||||||
if resp != "OK":
|
if resp != "OK":
|
||||||
@@ -36,7 +37,7 @@ def set_focus(foc_val):
|
|||||||
|
|
||||||
|
|
||||||
def get_image(filename, exp_time):
|
def get_image(filename, exp_time):
|
||||||
cmd = ["ixonultra_cmdclient", "-A", "CCD", "-T", "{:g}".format(exp_time), filename]
|
cmd = ["ixonultra_cmdclient", "-A", "CCD", "-p", "1", "--hs", "0", "-T", "{:g}".format(exp_time), filename]
|
||||||
|
|
||||||
ret = sp.run(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
|
ret = sp.run(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
|
||||||
return ret.returncode
|
return ret.returncode
|
||||||
@@ -175,7 +176,7 @@ if __name__ == "__main__":
|
|||||||
if args.verbose:
|
if args.verbose:
|
||||||
print("\tThe best focus value: {:g}".format(result["focus_value"]))
|
print("\tThe best focus value: {:g}".format(result["focus_value"]))
|
||||||
|
|
||||||
if not args.do_no_set:
|
if not args.do_not_set:
|
||||||
if args.verbose:
|
if args.verbose:
|
||||||
print("\n\tSet focus to the best value ...", end="")
|
print("\n\tSet focus to the best value ...", end="")
|
||||||
set_focus(result["focus_value"])
|
set_focus(result["focus_value"])
|
||||||
@@ -185,3 +186,4 @@ if __name__ == "__main__":
|
|||||||
print("DONE.")
|
print("DONE.")
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|||||||
@@ -121,11 +121,20 @@ def fitFocusCurve(
|
|||||||
np.inf,
|
np.inf,
|
||||||
) # parabola with minimum (2nd derivative must be positive)
|
) # parabola with minimum (2nd derivative must be positive)
|
||||||
|
|
||||||
if coeffs[2] < 0:
|
if coeffs[2] < 0: # it seems the non-robust fit failed!
|
||||||
coeffs[2] = 0
|
coeffs[2] = 0 # so, guess curve is just constant!
|
||||||
|
coeffs[1] = 0
|
||||||
|
coeffs[0] = np.nanmedian(flux_rad)
|
||||||
|
scale = np.nanmedian(np.abs(flux_rad - coeffs[0]))
|
||||||
|
else:
|
||||||
nr_model = nr_res(np.asarray(focus_value))
|
nr_model = nr_res(np.asarray(focus_value))
|
||||||
scale = np.abs(np.nanmedian(flux_rad - nr_model))
|
scale = np.nanmedian(np.abs(flux_rad - nr_model))
|
||||||
|
|
||||||
|
# if coeffs[2] < 0:
|
||||||
|
# coeffs[2] = 0
|
||||||
|
# nr_model = nr_res(np.asarray(focus_value))
|
||||||
|
# scale = np.abs(np.nanmedian(flux_rad - nr_model))
|
||||||
|
|
||||||
# robust fitting
|
# robust fitting
|
||||||
res = least_squares(
|
res = least_squares(
|
||||||
polyModelResid,
|
polyModelResid,
|
||||||
@@ -335,7 +344,7 @@ def focussingSequence(
|
|||||||
ret_val["ret_code"] = -1
|
ret_val["ret_code"] = -1
|
||||||
return ret_val
|
return ret_val
|
||||||
|
|
||||||
N = 7
|
N = 5
|
||||||
|
|
||||||
if len(focus_range) > 2:
|
if len(focus_range) > 2:
|
||||||
if np.isclose(focus_range[2], 0):
|
if np.isclose(focus_range[2], 0):
|
||||||
@@ -421,7 +430,7 @@ def focussingSequence(
|
|||||||
# filename = "{}_{:04d}{}".format(fname, i_foc, file_ext)
|
# filename = "{}_{:04d}{}".format(fname, i_foc, file_ext)
|
||||||
# full_filename = str(pt.Path.joinpath(dir, pt.Path(filename)))
|
# full_filename = str(pt.Path.joinpath(dir, pt.Path(filename)))
|
||||||
|
|
||||||
full_filename = str(rname.with_stem("{}_{:04d}", rname.stem, i_foc))
|
full_filename = str(rname.with_stem("{}_{:04d}".format(rname.stem, i_foc)))
|
||||||
|
|
||||||
print(log_ident, file=log_output, end="")
|
print(log_ident, file=log_output, end="")
|
||||||
print(
|
print(
|
||||||
@@ -580,7 +589,7 @@ def getFocusCalcCmdlinePars(parser):
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-o",
|
"-o",
|
||||||
"--data-curve",
|
"--data-curve",
|
||||||
help="filename of focussing curve data file",
|
help="filename of focussing curve ASCII data file",
|
||||||
type=str,
|
type=str,
|
||||||
default=None,
|
default=None,
|
||||||
)
|
)
|
||||||
@@ -613,7 +622,8 @@ def getFocussingSequenceCmdlinePars(parser):
|
|||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--foc-file",
|
"--foc-file",
|
||||||
help="Rootname of output focussing images. Default is 'focus.fits'.",
|
help="Rootname of output focussing images. Default is 'focus.fits'. The algorithm generates files of sequence as "
|
||||||
|
"'rootname_0001.rootname_ext, rootname_0002.rootname_ext ... rootname_NNNN.rootname_ext', where NNNN is an index number of acquisition.",
|
||||||
type=str,
|
type=str,
|
||||||
default="focus.fits",
|
default="focus.fits",
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user