Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/source/user_guide/operation.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ Run the [autofocus action](scheduling.md#autofocus-action). Ensure the `filter`

Upon successful completion, the optimized focus position is updated in the configuration. Autofocus images and V-curve plot are saved to the `images/autofocus` directory.

```{admonition} Focusing Tip
:class: tip

**Coarse Search (e.g., `fft`):** Best for broad ranges where stars appear as blurry "donuts." These non-parametric operators measure overall frame sharpness without needing to identify individual stars, making them nearly impossible to "confuse" with distorted optics.

**Fine Tuning (e.g., `HFR`):** Best for precision near the focus peak. These algorithms fit a "V-curve" to the diameters of detected stars. They provide great accuracy once stars are point-like, but will fail during wide searches if the stars are too bloated to be recognized by the star-finder.
```

<!-- **3. Optional: Pointing model**
Once focused, build a pointing model. Each pointing is plate solved and sends SyncToCoordinates commands to the mount. The receipt of these commands can be used to build a pointing model in the mount control software. _Astra_ itself does not build or maintain a pointing model.

Expand Down
6 changes: 3 additions & 3 deletions example_observatories/speculoos/speculoos.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import List

import astra.utils as utils
import astra.utils.astelos_errors as astelos_errors
from astra.observatory import Observatory
from astra.paired_devices import PairedDevices

Expand Down Expand Up @@ -168,15 +168,15 @@ def speculoos_check_and_ack_error(self, close=False) -> None:
telescope = self.devices["Telescope"][telescope_name]

# check telescope status
valid, all_errors, messages = utils.check_astelos_error(
valid, all_errors, messages = astelos_errors.check_error(
telescope, close=close
)

if valid and len(all_errors) > 0:
self.logger.info(
f"Attempting to acknowledge AsTelOS errors for {telescope_name}: {messages}"
)
ack, messages = utils.ack_astelos_error(
ack, messages = astelos_errors.ack_error(
telescope, valid, all_errors, messages, close=close
)

Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ classifiers = [
"Programming Language :: Python :: 3"
]
dependencies = [
"astrafocus>=0.1.1",
"astrafocus>=0.1.5",
"astropy",
"photutils",
"photutils>=3.0.0",
"scipy",
"twirl>=0.4.1",
"twirl>=0.5.2",
"sqlite3worker",
"alpyca>=3.1.2,<4",
"psutil",
Expand All @@ -54,7 +54,7 @@ dependencies = [
"fastapi[standard]",
"pyyaml",
"ruamel.yaml",
"cabaret"
"cabaret>=0.5.4"
]
description = "Automated Survey observaTory Robotised with Alpaca"
license = {text = "GPL-3.0"}
Expand Down
23 changes: 20 additions & 3 deletions src/astra/action_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ def validate_visibility(
# Try to resolve coordinates if RA/Dec are not explicitly provided
if ra is None or dec is None:
if self.lookup_name is not None:
from astra.utils import get_body_coordinates
from astra.utils.ephemeris import get_body_coordinates

# Resolve body position at start time
target_coord = get_body_coordinates(
Expand Down Expand Up @@ -1041,6 +1041,15 @@ class AutofocusConfig(BaseActionConfig):
4. Measure star sharpness in each image
5. Fit a curve to determine optimal focus
6. Save plots/results and save the best focus position in the observatory configuration

Note:
Coarse searches (for example `fft`, `normalized_variance`) use non-parametric
focus measures that characterise overall frame sharpness and are well suited
for very broad search ranges where stars appear as large, defocused "donuts".
Analytic response-function autofocusers (for example `HFR`/StarSize), which fit
a V-curve to measured star sizes, are better for fine-tuning near the focus
peak but can give incorrect results if applied over an excessively large range
because the assumed response model may not fit across the whole span.
"""

exptime: float | int = field(default=3.0)
Expand All @@ -1053,7 +1062,7 @@ class AutofocusConfig(BaseActionConfig):
n_exposures: List[int] | int = field(default_factory=lambda: [1, 1])
decrease_search_range: bool = True
star_find_threshold: float | int = 5.0
fwhm: int = 8
fwhm: Optional[int] = None
percent_to_cut: int = 60
focus_measure_operator: str = "HFR"
save: bool = True
Expand Down Expand Up @@ -1092,9 +1101,16 @@ class AutofocusConfig(BaseActionConfig):
),
"decrease_search_range": "Reduce the search range after each sweep.",
"star_find_threshold": "DAOStarFinder threshold for star detection.",
"fwhm": "DAOStarFinder FWHM of the Gaussian kernel in pixels.",
"fwhm": (
"DAOStarFinder FWHM of the Gaussian kernel in pixels. If not set, derived "
'from the camera/telescope plate scale assuming ~2" seeing.'
),
"percent_to_cut": "Percentage of worst-performing focus samples to drop when shrinking the range.",
"focus_measure_operator": "Focus metric to optimize (e.g., hfr, gauss, tenengrad, fft, normalized_variance).",
"focus_measure_operator_note": (
"Prefer non-parametric metrics (e.g., 'fft', 'normalized_variance') for coarse/broad searches; "
"use analytic measures (e.g., 'HFR') for fine tuning near the focus peak."
),
"reduce_exposure_time": "Automatically shorten exposures to prevent saturation.",
"save": "Persist the optimal focus position back into observatory configuration.",
"extremum_estimator": "Curve-fitting method used to determine the minimum (LOWESS, medianfilter, spline, rbf).",
Expand All @@ -1113,6 +1129,7 @@ class AutofocusConfig(BaseActionConfig):
"action_value": {
"exptime": 1.0,
"filter": "V",
"focus_measure_operator": "HFR",
"search_range_is_relative": True,
"search_range": 1000,
"n_steps": [30, 20],
Expand Down
Loading
Loading