public void CopyKey(string key, MiniFits from) { }
static void Main(string[] args) { string dataFile = ""; try { //Make it crash nicely when run without a filename dataFile = args[0]; } catch (Exception e) { Console.WriteLine("No filename passed, now exiting" + e); return; } var frame = new MiniFits(dataFile, false); var rowStride = frame.ReadDecimalKey("ROWSTRID"); var colStride = frame.ReadDecimalKey("COLSTRID"); var primaryDark = 0.0; var secondaryDark = 0.0; try { // Older frames don't specify dark counts, so let these gracefully fail primaryDark = (double)frame.ReadDecimalKey("DARKCNTA"); secondaryDark = (double)frame.ReadDecimalKey("DARKCNTB"); } catch (Exception) { frame.ClearErrorStatus(); } var region = frame.ReadStringKey("SCANAREA") .Split(' ') .Select(x => decimal.Parse(x)) .ToArray(); var overscanColumns = 0; try { // Older frames don't specify the overscan overscanColumns = frame.ReadIntegerKey("OVERSCAN"); } catch (Exception) { frame.ClearErrorStatus(); } Console.WriteLine("Overscan columns: {0}", overscanColumns); var inWidth = frame.Dimensions[0]; var inHeight = frame.Dimensions[1]; var binning = (int)Math.Round(rowStride / colStride); if (binning <= 0) throw new InvalidOperationException("Invalid row or column stride"); var outWidth = (inWidth - 2 * overscanColumns) / binning; var outHeight = inHeight; var binnedFile = Path.GetDirectoryName(dataFile) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(dataFile) + ".binned.fits"; using (var binned = new MiniFits(binnedFile, new[] { outWidth, outHeight, 3 }, MiniFitsType.F64, true)) { // Define the image coordinates for the display program // Physical coordinates binned.WriteKey("LTM1_1", 1 / (colStride * binning), 6); binned.WriteKey("LTM1_2", 0); binned.WriteKey("LTM2_1", 0); binned.WriteKey("LTM2_2", 1 / rowStride, 6); binned.WriteKey("LTV1", -region[0] / (colStride * binning) - 0.5m, 6); binned.WriteKey("LTV2", -region[1] / rowStride - 0.5m, 6); // WCS coordinates binned.WriteKey("CTYPE1", "LINEAR"); binned.WriteKey("CUNIT1", "mm"); binned.WriteKey("CRPIX1", 0); binned.WriteKey("CRVAL1", region[0] + colStride * binning / 2, 6); binned.WriteKey("CDELT1", colStride * binning, 6); binned.WriteKey("CTYPE2", "LINEAR"); binned.WriteKey("CUNIT2", "mm"); binned.WriteKey("CRPIX2", 0); binned.WriteKey("CRVAL2", region[1] + rowStride / 2, 6); binned.WriteKey("CDELT2", rowStride, 6); binned.WriteKey("WCSNAME", "Scan Pos."); var data = frame.ReadU16ImageData(); var frameStride = outWidth * outHeight; var binnedData = new double[frameStride * 3]; for (var i = 0; i < outHeight; i++) { for (var j = 0; j < outWidth; j++) { var primaryOffset = inWidth * i + binning * j + overscanColumns; var secondaryOffset = primaryOffset + inWidth * inHeight; var primaryBinned = 0.0; var secondaryBinned = 0.0; for (var k = 0; k < binning; k++) { primaryBinned += data[primaryOffset + k] - primaryDark; secondaryBinned += data[secondaryOffset + k] - secondaryDark; } var outIndex = i * outWidth + j; binnedData[outIndex] = primaryBinned / secondaryBinned; binnedData[outIndex + frameStride] = primaryBinned; binnedData[outIndex + 2 * frameStride] = secondaryBinned; } } binned.WriteImageData(binnedData); } }
public void StartScan(Configuration config) { if (asyncControl.IsAlive) { OnLogMessage("Invalid thread state. Aborting scan."); return; } if (Status == HardwareStatus.Error) { OnLogMessage("Hardware status is error. Aborting scan."); return; } cancelScan = false; asyncControl = new Thread(() => { try { var startColumn = (int)((config.Origin.X - config.RowOverscan) * config.XStepsPerMM); var endColumn = (int)((config.Origin.X + config.Size.Width + config.RowOverscan) * config.XStepsPerMM); var overscanCols = (int)(config.Origin.X * config.XStepsPerMM) - startColumn; if (startColumn < 0) { OnLogMessage("Overscan region extends outside the scannable region. Inset the scan area or reduce the overscan."); return; } OnLogMessage(string.Format("Counter columns {0} to {1}, overscan {2}", startColumn, endColumn, overscanCols)); var rows = (int)Math.Ceiling(config.Size.Height / config.RowStride); var columns = endColumn - startColumn + 1; var dimensions = new[] { columns, rows, 2 }; using (var fits = new MiniFits(config.DataFile, dimensions, MiniFitsType.U16, true)) { fits.WriteKey("OPERATOR", config.Operator, null); fits.WriteKey("DATETIME", DateTime.Now.ToString("G"), "Time at the start of the scan"); fits.WriteKey("DESCRIPT", config.Description, null); fits.WriteKey("SCANAREA", string.Format("{0:F3} {1:F3} {2:F3} {3:F3}", config.Origin.X, config.Origin.Y, config.Size.Width, config.Size.Height), "The requested scan area (X Y W H in mm)"); fits.WriteKey("ROWSTART", startColumn, "The step count of the first data column"); fits.WriteKey("ROWSTRID", config.RowStride, 6, "The step size between rows (in mm)"); fits.WriteKey("ROWSPEED", config.ScanSpeed, 4, "The row scan speed (in mm/minute)"); fits.WriteKey("OVERSCAN", overscanCols, 6, "The row overscan before/after the horizontal scan area (in columns)."); fits.WriteKey("COLSTRID", config.ColumnStride, 6, "The step size between columns (in mm)"); fits.WriteKey("DARKCNTA", config.PrimaryDarkCounts, 4, "Mean dark counts per unbinned pixel for detector A"); fits.WriteKey("DARKCNTB", config.SecondaryDarkCounts, 4, "Mean dark counts per unbinned pixel for detector B"); var data = new ushort[rows * columns * 2]; OnLogMessage("Moving to start position."); UpdateStatus(HardwareStatus.Homing); printer.MoveToHome(); counter.ZeroPositionCounter(); printer.MoveToPosition(0, config.Origin.Y, config.FocusHeight, config.SlewSpeed); printer.MoveToPosition(config.Origin.X - config.RowOverscan, config.Origin.Y, config.FocusHeight, config.SlewSpeed); UpdateStatus(HardwareStatus.Scanning); OnLogMessage("Starting scan."); double TotalTime=1; // Scan rows for (var i = 0; i < rows; i+=1) { var StartTime = DateTime.Now; if (cancelScan) break; OnLogMessage("Starting read at: " + counter.ReadPositionCounter().ToString()); OnLogMessage(string.Format("Scanning row {0} of {1} ({2:F0}%)", i + 1, rows, i * 100 / rows)); counter.Start(); // Collect photons while scanning left -> right // Scanning in one direction only ensures that the same optical configuration is used for each row printer.MoveDeltaX(config.Size.Width + 2 * config.RowOverscan, config.ScanSpeed); counter.Stop(); // Read and save data to file var primary = counter.ReadHistogram(CounterChannel.Primary, startColumn, endColumn); var secondary = counter.ReadHistogram(CounterChannel.Secondary, startColumn, endColumn); Array.Copy(primary, 0, data, i * columns, columns); Array.Copy(secondary, 0, data, (rows + i) * columns, columns); //OnLogMessage(string.Join(" ", primary)); fits.WriteImageData(data); counter.ResetHistogram(); UpdateStatus(HardwareStatus.Scanning, i * 100m / rows); // Return to the start of the next row printer.MoveDeltaX(-(config.Size.Width + 2 * config.RowOverscan), config.SlewSpeed); printer.MoveDeltaY(config.RowStride, config.ScanSpeed); /** //Scan on the way back too OnLogMessage("Starting at " + counter.ReadPositionCounter().ToString()); printer.MoveDeltaY(config.RowStride, config.ScanSpeed); counter.Start(); printer.MoveDeltaX(-1 * (config.Size.Width + (2 * config.RowOverscan)), config.ScanSpeed); counter.Stop(); primary = counter.ReadHistogram(CounterChannel.Primary, startColumn, endColumn); secondary = counter.ReadHistogram(CounterChannel.Secondary, startColumn, endColumn); counter.ResetHistogram(); Array.Copy(primary, 0, data, (i + 1) * columns, columns); Array.Copy(secondary, 0, data, (rows + i + 1) * columns, columns); fits.WriteImageData(data); */ //Calculate total, average and finish times TimeSpan RowTime = DateTime.Now - StartTime; TotalTime += RowTime.TotalSeconds; var AverageRowTime = TotalTime / (i+1); DateTime ECT=DateTime.Now; ECT=ECT.AddSeconds(AverageRowTime*(rows-i)); OnLogMessage(string.Format("Time elapsed: {0}s, Average Time per row: {1}s", TotalTime.ToString("f0"), AverageRowTime.ToString("f0"))); OnLogMessage("Estimated Completion: " + ECT.ToLongTimeString()); } OnLogMessage("Scan complete."); UpdateStatus(HardwareStatus.Homing); printer.MoveToHome(); UpdateStatus(HardwareStatus.Idle); } } catch (PrinterException e) { OnLogMessage("Printer error: " + e.Message); UpdateStatus(HardwareStatus.Error); CloseSerialConnections(); } catch (CounterException e) { OnLogMessage("Counter error: " + e.Message); UpdateStatus(HardwareStatus.Error); // TODO: Send emergency stop (M112) CloseSerialConnections(); } catch (MiniFitsException e) { OnLogMessage("File error: " + e.Message); UpdateStatus(HardwareStatus.Error); // TODO: Turn off laser and home printer // TODO: Send emergency stop (M112) CloseSerialConnections(); } }); asyncControl.Start(); }