FOCUSING WITH FOCUSMAX
Achieving great focus is undoubtedly one of the most critical operations for any astronomical imaging application. Using the free application,
FocusMax, this step can be reduced to a simple, repeatable, and highly effective operation. Fortunately, FocusMax provides all of the necessary interfaces to quickly automate this important step. The following listing shows a new class named 'cFocuser'. This class is responsible for controlling all aspects of the focus operation. The listing for the 'cFocuser' class is shown below:
import time
import pythoncom
import win32com.client
FOCUSMAXTIME = 150
LASTFOCHFD = -1
ERROR = True
NOERROR = False
##------------------------------------------------------------------------------
## Class: cFocuser
##------------------------------------------------------------------------------
class cFocuser:
def __init__(self,printlog):
printlog.log(0,"Connecting to FocusMax...")
self.__FM = win32com.client.Dispatch("FocusMax.FocusControl")
def checkFocusStar(self,printlog):
printlog.log(0,"Checking focus by measuring HFD...")
HFD = []
count = 0
# take 7 HFD measurements, sort the list, report the median value
while count < 7:
busy = self.__FM.SingleExposeAsyncStatus
self.__FM.SingleExposeAsync()
# wait for measurement to end
startTime = time.time()
busy = -1
while busy == -1 and (time.time() - startTime) < FOCUSMAXTIME:
time.sleep(1)
busy = self.__FM.SingleExposeAsyncStatus
if self.__FM.SingleExposeAsyncStatus != 1:
printlog.log(0,"HFD Measurement failed or timed out")
return -1
result = self.__FM.HalfFluxDiameter
flux = self.__FM.TotalFlux
time.sleep(0.5)
printlog.log(1,"HFD Measurement: %0.2f Total Flux: %d" %
(result,flux))
if flux > 20000:
HFD.append(result)
count = count + 1
HFD.sort()
j = len(HFD)
if not j%2:
median = (HFD[(j/2)-1]+HFD[j/2])/2.0
else:
median = HFD[j/2]
focuserPos = self.__FM.Position
printlog.log(0,"Median HFD = %0.2f at Pos = %d" % (median,focuserPos))
return median
def focusStar(self,printlog):
global LASTFOCHFD
printlog.log(0,"Starting FocusMax Focus method...")
try:
busy = self.__FM.FocusAsyncStatus
start = self.__FM.FocusAsync()
except pythoncom.com_error, (hr, msg, exc, arg):
printlog.log(0,"ERROR: %s" % exc[2])
return ERROR
else:
if start:
# wait for focus method to end
startTime = time.time()
busy = -1
while busy == -1 and (time.time() - startTime) < FOCUSMAXTIME:
time.sleep(1)
busy = self.__FM.FocusAsyncStatus
if self.__FM.FocusAsyncStatus != 1:
printlog.log(0,"Focus method failed or timed out.")
return ERROR
printlog.log(0,"FocusMax Focus method complete...")
tgtHFD = self.__FM.HalfFluxDiameter
if tgtHFD > 0.5:
median = self.checkFocusStar(printlog)
if median == -1:
return ERROR
elif median < 0.5 or median > 4.0:
printlog.log(0,"ERROR: Focus results out of range.")
return ERROR
else:
LASTFOCHFD = median
return NOERROR
else:
printlog.log(0,"ERROR: Focus method failed.")
return ERROR
else:
printlog.log(0,"ERROR: FocusMax Focus method failed to start.")
return ERROR
##
## END OF 'cFocuser' Class
##
The constructor for 'cFocuser' is called whenever a new object of the class is instantiated and is used to create a new object (__FM) that is bound to the FocusMax object (FocusControl) required by this class. Following the constructor, the 'checkFocusStar()' method performs a check of focus quality by invoking the 'SingleExposeAsync()' method. This method is called multiple times to take a series of measurement of a suitable focus star that has previously been centered in the field of view. After waiting for the exposure to complete, the method checks the properties that holds the measurement's HFD and total flux (brightness). The measurements are written to the screen and to the log file and the HFD value is appended to a list data structure. After seven measurements are collected, the HFD list is sorted and the median value is extracted and returned to the method's calling routine.
The other method in this class is named 'focusStar()' and performs the actual focus operation (nearly equivalent to clicking on the 'Focus' button on FocusMax's front panel). This method invokes the FocusMax 'FocusAsync()' method to kick off the focus operation. The method then polls the 'FocusAsyncStatus' property to determine when the focus operation is complete. If the focus star's HFD is a reasonable value, the 'checkFocusStar()' method is called to determine the median of seven consecutive HFD measurements. The median value is then assigned to a global variable, 'LASTFOCHFD'.
UNIT TESTING
Unlike unit tests for modules presented up to this point, the unit test for this class can not be simulated. Therefore, actual stars must be available to adequately verify the operation of this module. Due to poor weather and equipment failures I have been unable to generate and verify a unit test for the 'cFocuser' class. As soon as I am able, I will update this post with a unit test.
WHAT'S NEXT?
In the next post, I will demonstrate the method that I use to automatically select focus stars. This method will work with previous modules and result in a means to select a suitable focus star near the object to image, slew to the star, focus and determine median HFD, then slew to the main object to begin imaging. This procedure, along with periodic slews back to the focus star to check and ,if necessary, re-focus, is the main sequence of events that I use for my astronomical imaging script.