Exemplo n.º 1
0
        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();
        }