Пример #1
0
        public void Execute(object sender, DoWorkEventArgs e)
        {
            bw = (BackgroundWorker)sender;

            bw.ReportProgress(0, "Starting ASC conversion");
            CCIUtilities.Log.writeToLog("Started ASC conversion on records in " + headerFileName);

            /***** Read electrode file *****/
            ElectrodeInputFileStream etrFile = new ElectrodeInputFileStream(
                new FileStream(System.IO.Path.Combine(directory, head.ElectrodeFile), FileMode.Open, FileAccess.Read));

            /***** Open new FILMAN file *****/
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Title = "Save as FILMAN file ...";
            dlg.AddExtension = true;
            dlg.DefaultExt = ".fmn"; // Default file extension
            dlg.Filter = "FILMAN Files (.fmn)|*.fmn"; // Filter files by extension
            dlg.FileName = headerFileName;
            dlg.InitialDirectory = ASCtoFMConverter.Properties.Settings.Default.LastDataset; //Use dataset default, but don't save if new location
            bool? result = dlg.ShowDialog();
            if (result == null || !(bool)result)
            {
                bw.ReportProgress(0, "Conversion cancelled before FM file created.");
                e.Cancel = true;
                return;
            }
            int newRecordLength = Convert.ToInt32(Math.Ceiling(FMRecLength * samplingRate / (double)decimation));
            int FMRecordLengthInBDF = Convert.ToInt32(FMRecLength * samplingRate);

            int GVCount = 6 + GVCopyAcross.Count;
            bool PKCounterExists = false;
            foreach (EpisodeDescription ed in specs)
            {
                PKDetectorEventCounterDescription pkd = ed.PKCounter;
                if (pkd != null)
                {
                    PKCounterExists = true;
                    pkd.assignedGVNumber = GVCount;
                }
            }
            GVCount += PKCounterExists ? 3 : 0;

            //NOTE: because we have to have the number of GVs (and Channels) available when we create the output stream,
            // we have to separate the enumeration of GVs from the naming of GVs; this could be avoided by using lists
            // rather than arrays for GVNames in FILMANOuputStream and having an actual Header entity for FILMAN files;
            // one would then enter the GVNames (and Channel names) into the list before creating the ouput stream and have
            // the constructor use the counts to get NG and NC; NA could also be an array that must be created before as a
            // byte array, but this might be awkward

            FMStream = new FILMANOutputStream(
                File.Open(dlg.FileName, FileMode.Create, FileAccess.ReadWrite),
                GVCount, 0, channels.Count,
                newRecordLength,
                FILMANFileStream.FILMANFileStream.Format.Real);
            log = new LogFile(dlg.FileName + ".log.xml");
            FMStream.IS = Convert.ToInt32((double)samplingRate / (double)decimation);
            bigBuff = new double[bdf.NumberOfChannels - 1, FMStream.ND]; //have to dimension to BDF rather than FMStream
            //in case we need for reference calculations

            /***** Create FILMAN header records *****/

            //First GV names:
            //six for the standard generated
            FMStream.GVNames(0, "Channel");
            FMStream.GVNames(1, "Montage");
            FMStream.GVNames(2, "NewGroupVariable");
            FMStream.GVNames(3, "EpisodeNumber");
            FMStream.GVNames(4, "EpisodeRecordNumber");
            FMStream.GVNames(5, "SecondsFromStart");
            //then the copied-across GVs
            for (int n = 0; n < GVCopyAcross.Count; n++) FMStream.GVNames(n + 6, GVCopyAcross[n].Name);
            //and last, the GVs from the counters
            if (PKCounterExists) //if there are any PK counters, we'll need their GVs
            {
                FMStream.GVNames(GVCount - 3, "PK-rate");
                FMStream.GVNames(GVCount - 2, "PK-velocity");
                FMStream.GVNames(GVCount - 1, "PK-accel");
            }

            for (int j = 0; j < FMStream.NC; j++) //generate channel labels
            {
                string s = bdf.channelLabel(channels[j]);
                ElectrodeFileStream.ElectrodeRecord p;
                if (etrFile.etrPositions.TryGetValue(s, out p))
                    FMStream.ChannelNames(j, s.PadRight(16, ' ') + p.projectPhiTheta().ToString("0")); //add electrode location information, if available
                else
                    FMStream.ChannelNames(j, s);
            }

            FMStream.Description(0, head.Title + " Date: " + head.Date + " " + head.Time +
                " File: " + System.IO.Path.Combine(directory, System.IO.Path.GetFileNameWithoutExtension(head.BDFFile)));

            StringBuilder sb = new StringBuilder("Subject: " + head.Subject.ToString());
            if (head.Agent != 0) sb.Append(" Agent: " + head.Agent);
            sb.Append(" Tech:");
            foreach (string s in head.Technician) sb.Append(" " + s);
            FMStream.Description(1, sb.ToString());
            sb.Clear();
            sb = sb.Append(specs[0].ToString());
            for (int j = 1; j < specs.Length; j++) sb.Append("/ " + specs[j].ToString());
            string str = sb.ToString();
            int sl = str.Length;
            int k;
            if (sl < 72) { FMStream.Description(2, str); k = 3; }
            else
            {
                FMStream.Description(2, str.Substring(0, 72));
                if (sl < 144) { FMStream.Description(3, str.Substring(72)); k = 4; }
                else
                {
                    FMStream.Description(3, str.Substring(72, 72));
                    k = 5;
                    if (sl < 216) FMStream.Description(4, str.Substring(144));
                    else FMStream.Description(4, str.Substring(144, 72));
                }
            }
            sb.Clear();
            if (referenceGroups == null || referenceGroups.Count == 0) sb.Append("No reference");
            else if (referenceGroups.Count == 1)
            {
                sb.Append("Single ref group with");
                if (referenceGroups[0].Count >= FMStream.NC)
                    if (referenceChannels[0].Count == bdf.NumberOfChannels) sb.Append(" common average ref");
                    else if (referenceChannels[0].Count == 1)
                        sb.Append(" ref channel " + referenceChannels[0][0].ToString("0") + "=" + bdf.channelLabel(referenceChannels[0][0]));
                    else sb.Append(" multiple ref channels=" + referenceChannels[0].Count.ToString("0"));
            }
            else // complex reference expression
            {
                sb.Append(" Multiple reference groups=" + referenceGroups.Count.ToString("0"));
            }
            FMStream.Description(k++, sb.ToString());

            if (k < 6)
                FMStream.Description(k, bdf.LocalRecordingId);

            FMStream.writeHeader();

            log.registerHeader(this);

            EventFactory.Instance(ED);

            int epiNo = 0; //found episode counter

            //read in list of Events
            bw.ReportProgress(0, "Reading Events, synchronizing clocks, and calculating Event offsets from BDF file");
            List<InputEvent> EventList = new List<InputEvent>();
            EventFileReader efr=new EventFileReader(
                    new FileStream(System.IO.Path.Combine(directory, head.EventFile),
                    FileMode.Open, FileAccess.Read));
            InputEvent.LinkEventsToDataset(head, bdf); //link InputEvents to this specific dataset
            foreach (InputEvent ie in efr)
            {
                EventList.Add(ie);
            }
            IEnumerator<InputEvent> EventEnumerator = EventList.GetEnumerator(); //Enumerator for stepping through Event file

             //******** Synchronize clocks
            //Need to synchronize clocks by setting the BDF.zeroTime value
            //zeroTime is the time, according to the Event file clock, of the beginning of the BDF file (BioSemi clock)
            if (ignoreStatus && offsetToFirstEvent < 0D) //cannot use Status markers to synchronize clocks, so
                //use raw Event clock times as actual offsets from beginning of BDF file; in other words force all Events to be BDF-based
                bdf.setZeroTime(0D); //this keeps it from throwing an error when "synchronizing"
            else
            { //Need to find a covered (intrisic or extrinsic) Event to use as an indicial Event
                bool found = false;
                EventEnumerator.Reset();
                if (syncToFirst || ignoreStatus)
                    while (!found && EventEnumerator.MoveNext())
                    {
                        if (EventEnumerator.Current.EDE.IsCovered) //have we found a covered Event?
                        {
                            if (ignoreStatus)
                            {
                                bdf.setZeroTime(EventEnumerator.Current.Time - offsetToFirstEvent);
                                found = true;
                            }
                            else
                                found = bdf.setZeroTime(EventEnumerator.Current);
                        }
                    }
                else //sync to "middle" Event
                {
                    int midRecord = bdf.NumberOfRecords / 2;
                    BDFLocFactory fac = new BDFLocFactory(bdf);
                    BDFLoc loc = fac.New();
                    loc.Rec = midRecord;
                    bdf.read(midRecord);
                    uint v1 = head.Mask & (uint)bdf.getStatusSample(loc);
                    uint v2;
                    InputEvent IE;
                    while ((v2 = (uint)bdf.getStatusSample(++loc) & head.Mask) == v1) ; //find next Status mark after mid point of file; v2 = GC
                    while (!found && EventEnumerator.MoveNext())
                    {

                        IE = EventEnumerator.Current;
                        if (IE.GC == v2)
                        {
                            bdf.setZeroTime(IE.Time - loc.ToSecs());
                            found = true;
                        }
                    }
                }
                if (!found)
                {
                    log.Close();
                    FMStream.Close();
                    throw (new Exception("No valid synchronizing (covered) Event found; use manual synchronization"));
                }
            }
            Log.writeToLog("\tinto FM file " + dlg.FileName);

            foreach(InputEvent ie in EventList) //modify relativeTime field depending on type of Event
                ie.setRelativeTime();

            EventList = EventList.OrderBy(ev => ev.relativeTime).ToList(); //re-sort: minor order changes may occur

            //Loop through each episode specification,
            // then through the Event file to find any regions satisfying the specification,
            // then create FILMAN records for each of these regions

             //******** Episode specification loop
            for (int i = 0; i < specs.Length; i++)
            {
                EpisodeDescription currentEpisode = specs[i];
                FMStream.record.GV[2] = currentEpisode.GVValue; //set epispec GV value

                if (currentEpisode.Exclude != null)
                {
                    //Here we complete the ExclusionDescription for the given Episode specification
                    //by finding all the segemnts that must be excluded and
                    //calculating their From to To BDFPoints; this is done for each specification to
                    //permit different exclusion criteria for each EpisodeDescription

                    ExclusionDescription ed = currentEpisode.Exclude;
                    EventEnumerator.Reset();
                    EventDictionaryEntry startEDE = ed.startEvent;
                    bool t = ed.endEvent != null && ed.endEvent.GetType() == typeof(EventDictionaryEntry);
                    EventDictionaryEntry endEDE = null;
                    if(t)
                        endEDE = (EventDictionaryEntry)ed.endEvent;
                    while(EventEnumerator.MoveNext())
                    {
                        InputEvent ev = EventEnumerator.Current;
                        if (ev.Name == startEDE.Name)
                        {
                            BDFPoint b = new BDFPoint(bdf).FromSecs(bdf.timeFromBeginningOfFileTo(ev));
                            ed.From.Add(b);
                            if (t)
                                while (EventEnumerator.MoveNext())
                                {
                                    ev = EventEnumerator.Current;
                                    if (ev.Name == endEDE.Name)
                                    {
                                        ed.To.Add(new BDFPoint(bdf).FromSecs(bdf.timeFromBeginningOfFileTo(ev)));
                                        break;
                                    }
                                }
                            else
                                ed.To.Add(b);
                        }
                    }
                }

                // From here we loop through Event file until an Event is found that matches the
                // current startEvent in spec[i]; from that point a matching endEvent is sought;
                // episode is then processed; note that this implies that overlapping episodes are not
                // generally permitted (in a given specification) except when caused by offsets.

            //************* Event file loop
                EventEnumerator.Reset();
                bool found;

                do
                {
                    if (bw.CancellationPending) //look for cancellation first
                    {
                        bw.ReportProgress(0, "Conversion canceled with " + FMStream.NR.ToString("0") +
                            " records in " + (FMStream.NR / FMStream.NC).ToString("0") + " recordsets generated.");
                        FMStream.Close();
                        log.Close();
                        e.Cancel = true;
                        return;
                    }
                    InputEvent startEvent = null;
                    InputEvent endEvent = null;
                    double startTime;
                    double endTime = 0;

                    found = findNextMark(currentEpisode.Start, EventEnumerator, true, out startTime, out startEvent) &&
                        findNextMark(currentEpisode.End, EventEnumerator, false, out endTime, out endEvent);

                    if (found || startTime >= 0D && specs[i].useEOF)
                    { //use EOF
                        //***************** FILMAN record loop

                        startTime += currentEpisode.Start._offset;
                        endTime += currentEpisode.End._offset;
                        bw.ReportProgress(0, "Found episode " + (++epiNo).ToString("0") +
                            " from " + startTime.ToString("0.000") +
                            " to " + endTime.ToString("0.000"));
                        int maxNumberOfFMRecs = (int)Math.Floor((endTime - startTime) / FMRecLength);
                        log.openFoundEpisode(epiNo, startTime, endTime, maxNumberOfFMRecs);

                        BDFPoint startBDFPoint = new BDFPoint(bdf);
                        startBDFPoint.FromSecs(startTime);
                        BDFPoint endBDFPoint = new BDFPoint(startBDFPoint);

                        /***** Get group variables for this record *****/
                        FMStream.record.GV[3] = epiNo;
                        if (startEvent != null) //exclude BOF
                        {
                            int GrVar = 6; //Load up group variables, based on the start Event
                            foreach (GVEntry gve in GVCopyAcross)
                            {
                                int j = startEvent.GetIntValueForGVName(gve.Name);
                                FMStream.record.GV[GrVar++] = j < 0 ? 0 : j; //use zero to indicate "No value"
                            }
                        }

                        /***** Process each FILMAN record *****/
                        int actualNumberOfFMRecs = 0;
                        for (int rec = 1; rec <= maxNumberOfFMRecs; rec++)
                        {
                            endBDFPoint += FMRecordLengthInBDF; //update end point
                            if (currentEpisode.Exclude == null || !currentEpisode.Exclude.IsExcluded(startBDFPoint, endBDFPoint)) //is not excluded:
                            {
                                FMStream.record.GV[4] = ++actualNumberOfFMRecs; //Record number in this episode
                                FMStream.record.GV[5] = Convert.ToInt32(Math.Ceiling(startBDFPoint.ToSecs())); //Approximate seconds since start of BDF file

                                //calculate start and end times for this record: use BDFPoint values to assure accuracy;
                                //avoids problem if FMRecordLength is not exactly represented in double
                                startTime = startBDFPoint.ToSecs();
                                endTime = endBDFPoint.ToSecs();

                                //*****Count PK Events in this record*****
                                if (PKCounterExists)
                                {
                                    for (int j = GVCount - 3; j < GVCount; j++) FMStream.record.GV[j] = 0; //zero out as default
                                    if(currentEpisode.PKCounter!=null)
                                    {
                                        PKDetectorEventCounterDescription pkd = currentEpisode.PKCounter;
                                        double[] v = pkd.countMatchingEvents(startTime, startTime + FMRecLength, EventList);
                                        FMStream.record.GV[GVCount - 3] = Convert.ToInt32(1000D * v[0]); //make per thousand to nave useful integer
                                        FMStream.record.GV[GVCount - 2] = Convert.ToInt32(v[1]);
                                        FMStream.record.GV[GVCount - 1] = Convert.ToInt32(v[2]);
                                    }
                                }

                                createFILMANRecord(startBDFPoint, endBDFPoint);
                            }
                            startBDFPoint = endBDFPoint; //move start point forward
                        }
                        log.closeFoundEpisode(actualNumberOfFMRecs);
                    }

                } while (found && !(currentEpisode.Start.MatchesType("Beginning of file") == true)); //next Event, if any

            }  //next spec

            e.Result = new int[] { FMStream.NR, FMStream.NR / FMStream.NC };
            FMStream.Close();
            log.Close();
            Log.writeToLog("Completed ASC conversion with " + FMStream.NR.ToString("0") + " FM records created");
        }
Пример #2
0
        public MainWindow()
        {
            bool r;
            do //first get HDR file and open BDF file
            {
                OpenFileDialog dlg = new OpenFileDialog();
                dlg.Title = "Open Header of dataset to be edited...";
                dlg.DefaultExt = ".hdr"; // Default file extension
                dlg.Filter = "HDR Files (.hdr)|*.hdr"; // Filter files by extension
                Nullable<bool> result = dlg.ShowDialog();
                if (result == null || result == false) Environment.Exit(0); 

                directory = System.IO.Path.GetDirectoryName(dlg.FileName); //will use to find other files in dataset
                headerFileName = System.IO.Path.GetFileNameWithoutExtension(dlg.FileName);

                header = (new HeaderFileReader(dlg.OpenFile())).read();
                updateFlag = header.Events.ContainsKey("**ArtifactBegin"); //indicates that we are editing a dataset that has already been edited for artifacts

                bdf = new BDFEDFFileReader(new FileStream(System.IO.Path.Combine(directory, header.BDFFile),
                        FileMode.Open, FileAccess.Read));

                //make list of candidate EEG channels, so that channel selection window can use it
                BDFLength = (double)bdf.NumberOfRecords * bdf.RecordDuration;
                string trans = bdf.transducer(0); //here we assumne that channel 0 is an EEG channel
                for (int i = 0; i < bdf.NumberOfChannels - 1; i++) //exclude Status channel
                    if (bdf.transducer(i) == trans) EEGChannels.Add(i);

                Window1 w = new Window1(this); //open channel selection and file approval window
                r = (bool)w.ShowDialog();

            } while (r == false);

            InitializeComponent();

            Log.writeToLog("Starting EEGArtifactEditor " + Assembly.GetExecutingAssembly().GetName().Version.ToString() +
                " on dataset " + headerFileName);
            ViewerGrid.Width = BDFLength;

            try
            {
                //process Events in current dataset; we have to do this now in case this is an update situation, but don't have to when we finish
                Event.EventFactory.Instance(header.Events); // set up the factory, based on this Event dictionary
                //and read them in
                EventFileReader efr = new EventFileReader(
                    new FileStream(System.IO.Path.Combine(directory, header.EventFile),
                        FileMode.Open, FileAccess.Read)); // open Event file

                foreach (InputEvent ie in efr)// read in all Events into list
                    events.Add(new OutputEvent(ie));
                efr.Close(); //now events is list of Events in the dataset

                //now set zeroTime for this BDF file, after finding an appropriate (non-"naked") Event
                bool ok = false;
                foreach (OutputEvent ev in events)
                    if (header.Events[ev.Name].IsCovered)
                    {
                        bdf.setZeroTime(ev);
                        ok = true;
                        break;
                    }
                if (!ok)
                {
                    ErrorWindow ew = new ErrorWindow();
                    ew.Message = "Unable to find a covered Event in this dataset on which to synchronize clocks. Exiting.";
                    ew.ShowDialog();
                    Log.writeToLog("Unable to synchronize clocks.");
                    this.Close();
                }

                if (updateFlag) //re-editing this dataset for artifacts
                {
                    Event.EventFactory.Instance(header.Events); // set up the factory, based on this Event dictionary
                    //and read them in
                    OutputEvent ev;
                    int i = 0;
                    double left;
                    while (i < events.Count)
                    {
                        ev = events[i];
                        if (ev.Name == "**ArtifactBegin")
                        {
                            left = bdf.timeFromBeginningOfFileTo(ev);
                            events.Remove(ev);
                            while (i < events.Count)
                            {
                                ev = events[i];
                                if (ev.Name == "**ArtifactEnd")
                                {
                                    MarkerCanvas.createMarkRegion(left, bdf.timeFromBeginningOfFileTo(ev));
                                    events.Remove(ev);
                                    break;
                                }
                                if (ev.Name == "**ArtifactBegin")
                                    throw (new Exception("Unmatched artifact Event in Event file " +
                                        System.IO.Path.Combine(directory, header.EventFile)));
                                i++;
                            }
                        }
                        else
                            i++;
                    }
                }

                //initialize the individual channel canvases

                foreach (int chan in selectedEEGChannels)
                {
                    ChannelCanvas cc = new ChannelCanvas(this, chan);
                    currentChannelList.Add(cc);
                    ViewerCanvas.Children.Add(cc);
                    ViewerCanvas.Children.Add(cc.offScaleRegions);
                }


                Title = headerFileName; //set window title
                BDFFileInfo.Content = bdf.ToString();
                HDRFileInfo.Content = header.ToString();

                ElectrodeInputFileStream eif = new ElectrodeInputFileStream(
                    new FileStream(System.IO.Path.Combine(directory, header.ElectrodeFile),
                        FileMode.Open, FileAccess.Read)); //open Electrode file
                electrodes = eif.etrPositions;

                //initialize vertical gridline array; never more than 18
                for (int i = 0; i < 18; i++)
                {
                    Line l = new Line();
                    Grid.SetRow(l, 0);
                    Grid.SetColumn(l, 0);
                    l.Y1 = 0D;
                    l.HorizontalAlignment = HorizontalAlignment.Left;
                    l.VerticalAlignment = VerticalAlignment.Stretch;
                    l.IsHitTestVisible = false;
                    l.Stroke = Brushes.LightBlue;
                    l.Visibility = Visibility.Hidden;
                    Panel.SetZIndex(l, int.MaxValue);
                    VerticalGrid.Children.Add(l);
                    gridlines[i] = l;
                }

                //Initialize timer
                timer.AutoReset = true;
                timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

                //Initialize channel information popup
                Color c1 = Color.FromArgb(0xFF, 0xF8, 0xF8, 0xF8);
                Color c2 = Color.FromArgb(0xFF, 0xC8, 0xC8, 0xC8);
                popupTB.Background = new LinearGradientBrush(c1, c2, 45D);
                popupTB.Foreground = Brushes.Black;
                popupTB.Padding = new Thickness(4D);
                Border b = new Border();
                b.BorderThickness = new Thickness(1);
                b.CornerRadius = new CornerRadius(4);
                b.BorderBrush = Brushes.Tomato;
                b.Margin = new Thickness(0, 0, 24, 24); //allows drop shadow to show up
                b.Effect = new DropShadowEffect();
                b.Child = popupTB;
                channelPopup.Placement = PlacementMode.MousePoint;
                channelPopup.AllowsTransparency = true;
                channelPopup.Child = b;

                //Initialize FOV slider
                FOV.Maximum = Math.Log10(BDFLength);
                FOV.Value = 1D;
                FOVMax.Text = BDFLength.ToString("0");

                //Note file always uses the "main" orginal dataset name, which should be the BDFFile name; this keeps notes from all levels of
                //processing in the same place
                noteFilePath = System.IO.Path.Combine(directory, System.IO.Path.GetFileNameWithoutExtension(header.BDFFile) + ".notes.txt");
            }
            catch (Exception ex)
            {
                ErrorWindow ew = new ErrorWindow();
                ew.Message = "Error in EEGArtifactEditor initialization" + ex.Message;
                ew.ShowDialog();
                this.Close(); //exit
            }

            //from here on the program is GUI-event driven
        }
Пример #3
0
        public void Execute(object sender, DoWorkEventArgs e)
        {
            bw = (BackgroundWorker)sender;

            bw.ReportProgress(0, "Starting FMConverter");
            CCIUtilities.Log.writeToLog("Starting FMConverter on records in " + directory);

            /***** Read electrode file *****/
            ElectrodeInputFileStream etrFile = new ElectrodeInputFileStream(
                new FileStream(Path.Combine(directory, eventHeader.ElectrodeFile), FileMode.Open, FileAccess.Read));

            /***** Open FILMAN file *****/
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Title = "Save as FILMAN file ...";
            dlg.AddExtension = true;
            dlg.DefaultExt = ".fmn"; // Default file extension
            dlg.Filter = "FILMAN Files (.fmn)|*.fmn"; // Filter files by extension
            dlg.FileName=Path.GetFileNameWithoutExtension(eventHeader.BDFFile);
            Nullable<bool> result = dlg.ShowDialog();
            if (result == null || !(bool)result)
            {
                e.Result = new int[] { 0, 0 };
                return;
            }
            samplingRate = BDF.NSamp / BDF.RecordDuration;
            offsetInPts = Convert.ToInt32(offset * samplingRate);
            newRecordLength = Convert.ToInt32(Math.Ceiling(length * samplingRate / (float)decimation));

            FMStream = new FILMANOutputStream(
                File.Open(dlg.FileName, FileMode.Create, FileAccess.ReadWrite),
                GV.Count + 2, EDE.ancillarySize, channels.Count,
                newRecordLength,
                FILMANFileStream.FILMANFileStream.Format.Real);
            log = new LogFile(dlg.FileName + ".log.xml");
            FMStream.IS = Convert.ToInt32( (double)samplingRate/(double)decimation);
            bigBuff = new float[BDF.NumberOfChannels - 1, FMStream.ND]; //have to dimension to BDF rather than FMStream
                                                                        //in case we need for reference calculations

            /***** Create FILMAN header records *****/
            FMStream.GVNames(0, "Channel");
            FMStream.GVNames(1, "Montage");
            int i = 2;
            foreach (GVEntry gv in GV) FMStream.GVNames(i++, gv.Name); //generate group variable names

            for (i = 0; i < FMStream.NC; i++) //generate channel labels
            {
                string s = BDF.channelLabel(channels[i]);
                ElectrodeFileStream.ElectrodeRecord p;
                if (etrFile.etrPositions.TryGetValue(s, out p))   //add electrode location information, if available
                    FMStream.ChannelNames(i, s.PadRight(16, ' ') + p.projectPhiTheta().ToString("0"));
                else
                    FMStream.ChannelNames(i, s);
            }

            FMStream.Description(0, eventHeader.Title + " Date: " + eventHeader.Date + " " + eventHeader.Time);

            FMStream.Description(1, "File: " + Path.Combine(directory, Path.GetFileNameWithoutExtension(eventHeader.BDFFile)));

            StringBuilder sb = new StringBuilder("Subject: " + eventHeader.Subject.ToString());
            if (eventHeader.Agent != 0) sb.Append(" Agent: " + eventHeader.Agent);
            sb.Append(" Tech:");
            foreach (string s in eventHeader.Technician) sb.Append(" "  + s);
            FMStream.Description(2, sb.ToString());

            sb = new StringBuilder("Event="+EDE.Name);
            sb.Append(" Offset=" + offset.ToString("0.00"));
            sb.Append(" Length=" + length.ToString("0.00"));
            if (referenceGroups == null || referenceGroups.Count == 0) sb.Append(" No reference");
            else if (referenceGroups.Count == 1)
            {
                sb.Append(" Single ref group with");
                if (referenceGroups[0].Count >= FMStream.NC)
                    if (referenceChannels[0].Count == BDF.NumberOfChannels) sb.Append(" common average ref");
                    else if (referenceChannels[0].Count == 1)
                        sb.Append(" ref channel " + referenceChannels[0][0].ToString("0") + "=" + BDF.channelLabel(referenceChannels[0][0]));
                    else sb.Append(" multiple ref channels=" + referenceChannels[0].Count.ToString("0"));
            }
            else // complex reference expression
            {
                sb.Append(" Multiple reference groups=" + referenceGroups.Count.ToString("0"));
            }
            FMStream.Description(3, sb.ToString());

            sb = new StringBuilder("#Group vars=" + GV.Count.ToString("0"));
            if (anc) sb.Append(" Ancillary=" + FMStream.NA.ToString("0"));
            sb.Append(" #Channels=" + FMStream.NC.ToString("0"));
            sb.Append(" #Samples=" + FMStream.ND.ToString("0"));
            sb.Append(" Samp rate=" + FMStream.IS.ToString("0"));
            FMStream.Description(4, sb.ToString());

            FMStream.Description(5, BDF.LocalRecordingId);

            FMStream.writeHeader();

            log.registerHeader(this);

            /***** Open Event file for reading *****/
            EventFactory.Instance(eventHeader.Events); // set up the factory
            EventFileReader EventFR = new EventFileReader(
                new FileStream(Path.Combine(directory, eventHeader.EventFile), FileMode.Open, FileAccess.Read));

            BDFLoc stp = BDF.LocationFactory.New();
            if (!EDE.intrinsic)
                if (risingEdge) threshold = EDE.channelMin + (EDE.channelMax - EDE.channelMin) * threshold;
                else threshold = EDE.channelMax - (EDE.channelMax - EDE.channelMin) * threshold;

            nominalT = BDF.LocationFactory.New(); //nominal Event time based on Event.Time
            actualT = BDF.LocationFactory.New(); //actual Event time in Status channel
            //Note: these should be the same if the two clocks run the same rate (BioSemi DAQ and computer)
            /***** MAIN LOOP *****/
            foreach (InputEvent ie in EventFR) //Loop through Event file
            {
                bw.ReportProgress(0, "Processing event " + ie.Index.ToString("0")); //Report progress

                if (ie.Name == EDE.Name) // Event match found in Event file
                {
                    if (findEvent(ref stp, ie))
                        createFILMANRecord(stp, ie); //Create FILMAN recordset around this found point
                }
            }
            e.Result = new int[] { FMStream.NR, FMStream.NR / FMStream.NC };
            FMStream.Close();
            EventFR.Close();
            log.Close();
        }
Пример #4
0
        public void Execute(object sender, DoWorkEventArgs e)
        {
            bw = (BackgroundWorker)sender;

            bw.ReportProgress(0, "Starting BDFConverter");
            CCIUtilities.Log.writeToLog("Starting BDFConverter on records in " + directory);

            /***** Read electrode file *****/
            ElectrodeInputFileStream etrFile = new ElectrodeInputFileStream(
                new FileStream(Path.Combine(directory, eventHeader.ElectrodeFile), FileMode.Open, FileAccess.Read));

            /***** Open BDF file *****/
            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
            dlg.Title = "Save as BDF file ...";
            dlg.AddExtension = true;
            dlg.DefaultExt = ".bdf"; // Default file extension
            dlg.Filter = "BDF Files (.bdf)|*.bdf"; // Filter files by extension
            dlg.FileName = Path.GetFileNameWithoutExtension(eventHeader.BDFFile);
            bool? result = dlg.ShowDialog();
            if (result == false)
            {
                e.Result = new int[] { 0, 0 };
                return;
            }
            samplingRate = BDF.NSamp / BDF.RecordDuration; //Old sampling rate; exact as number of samples and duration are always an exact multiple
            oldOffsetInPts = Convert.ToInt32(offset * samplingRate);
            int newSamplingRate = (int)((double)samplingRate / (double)decimation + 0.5); //Make best estimate possible with integers
            newOffsetInPts = Convert.ToInt32(offset * newSamplingRate);
            newRecordLength = length * newSamplingRate; //new record length must be exact multiple of the sampling rate in BDF
            newStatus = new int[newRecordLength];
            status = new int[BDF.NSamp];
            GV0 = GV[0];

            BDFWriter = new BDFEDFFileWriter(File.Open(dlg.FileName, FileMode.Create, FileAccess.ReadWrite),
                channels.Count + 1, /* Extra channel will have group variable value in it */
                length, /* Record length in seconds, must be integer */
                newSamplingRate,
                true);

            log = new LogFile(dlg.FileName + ".log.xml");
            bigBuff = new float[BDF.NumberOfChannels - 1, newRecordLength];   //have to dimension to old channels rather than new
                                                                                //in case we need for reference calculations later
            /***** Create BDF header record *****/
            BDFWriter.LocalRecordingId = BDF.LocalRecordingId;
            BDFWriter.LocalSubjectId = BDF.LocalSubjectId;
            int chan;
            for (int i = 0; i < channels.Count; i++)
            {
                chan = channels[i];
                BDFWriter.channelLabel(i, BDF.channelLabel(chan));
                BDFWriter.transducer(i, BDF.transducer(chan));
                BDFWriter.dimension(i, BDF.dimension(chan));
                BDFWriter.pMax(i, BDF.pMax(chan));
                BDFWriter.pMin(i, BDF.pMin(chan));
                BDFWriter.dMax(i, BDF.dMax(chan));
                BDFWriter.dMin(i, BDF.dMin(chan));
                BDFWriter.prefilter(i, BDF.prefilter(chan));
            }
            chan = channels.Count;
            BDFWriter.channelLabel(chan, GV0.Name); //Make entries for old Status channel
            BDFWriter.transducer(chan, "None");
            BDFWriter.dimension(chan, "");
            BDFWriter.pMax(chan, 262143);
            BDFWriter.pMin(chan, -262144);
            BDFWriter.dMax(chan, 262143);
            BDFWriter.dMin(chan, -262144);
            BDFWriter.prefilter(chan, "None");

            log.registerHeader(this);

            /***** Open Event file for reading *****/
            EventFactory.Instance(eventHeader.Events); // set up the factory
            EventFileReader EventFR = new EventFileReader(
                new FileStream(Path.Combine(directory, eventHeader.EventFile), FileMode.Open, FileAccess.Read));

            BDFLoc stp = BDF.LocationFactory.New();
            BDFLoc lastEvent = BDF.LocationFactory.New();
            if (!EDE.intrinsic) //set threshold
                if (risingEdge) threshold = EDE.channelMin + (EDE.channelMax - EDE.channelMin) * threshold;
                else threshold = EDE.channelMax - (EDE.channelMax - EDE.channelMin) * threshold;

            nominalT = BDF.LocationFactory.New(); //nominal Event time based on Event.Time
            actualT = BDF.LocationFactory.New(); //actual Event time in Status channel
            //Note: these should be the same if the two clocks run the same rate (DAQ and computer)
            /***** MAIN LOOP *****/
            foreach (InputEvent ie in EventFR) //Loop through Event file
            {
                bw.ReportProgress(0, "Processing event " + ie.Index.ToString("0")); //Report progress

                if (ie.Name == EDE.Name) // Event match found in Event file
                {
                    if(findEvent(ref stp, ie))
                        if (allSamps) //this is a continuous copy, not Event generated episodic conversion
                        {
                            runBDFtoEvent(lastEvent, ref stp, ie);
                            lastEvent = BDF.LocationFactory.New();
                        }
                        else createBDFRecord(stp, ie); //Create BDF recordset around this point; i.e. Event generated episodic conversion
                }
            }
            if (allSamps) //copy out to end of file
            {
                stp.Rec = BDF.NumberOfRecords;
                stp.Pt = 0;
                runBDFtoEvent(lastEvent, ref stp, null);
            }
            e.Result = new int[] { BDFWriter.NumberOfRecords, BDFWriter.NumberOfRecords };
            BDFWriter.Close();
            EventFR.Close();
            log.Close();
        }
Пример #5
0
        public MainWindow()
        {
            Log.writeToLog("Starting DatasetReviewer " + Assembly.GetExecutingAssembly().GetName().Version.ToString());

            do
            {
                bool r;
                do
                {
                    System.Windows.Forms.OpenFileDialog dlg = new System.Windows.Forms.OpenFileDialog();
                    dlg.Title = "Open Header file to be displayed...";
                    dlg.DefaultExt = ".hdr"; // Default file extension
                    dlg.Filter = "HDR Files (.hdr)|*.hdr"; // Filter files by extension
                    bool result = dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK;
                    if (!result) Environment.Exit(0);

                    directory = System.IO.Path.GetDirectoryName(dlg.FileName); //will use to find other files in dataset
                    headerFileName = System.IO.Path.GetFileNameWithoutExtension(dlg.FileName);
                    try
                    {
                        head = (new HeaderFileReader(dlg.OpenFile())).read();
                    }
                    catch (Exception e)
                    {
                        r = false; //loop around again
                        ErrorWindow ew = new ErrorWindow();
                        ew.Message = "Error reading Header file: " + e.Message;
                        continue;
                    }
                    ED = head.Events;

                    try
                    {
                        bdf = new BDFEDFFileStream.BDFEDFFileReader(
                            new FileStream(System.IO.Path.Combine(directory, head.BDFFile),
                                FileMode.Open, FileAccess.Read));
                    }
                    catch (Exception e)
                    {
                        r = false; //loop around again
                        ErrorWindow ew = new ErrorWindow();
                        ew.Message = "Error reading BDF file header: " + e.Message;
                        ew.ShowDialog();
                        continue;
                    }
                    BDFLength = (double)bdf.NumberOfRecords * bdf.RecordDurationDouble;

                    Window1 w = new Window1(this);
                    r = (bool)w.ShowDialog();

                } while (r == false);

                Log.writeToLog("     on dataset " + headerFileName);

                if (includeANAs)
                {
                    foreach (EventDictionaryEntry ede in ED.Values) // add ANA channels that are referenced by extrinsic Events
                    {
                        if (ede.IsCovered && ede.IsExtrinsic)
                        {
                            int chan = bdf.ChannelNumberFromLabel(ede.channelName);
                            if (!channelList.Contains(chan)) //don't enter duplicate
                                channelList.Add(chan);
                        }
                    }
                }
            } while (channelList.Count == 0);

            InitializeComponent();

            //initialize the individual channel graphs
            foreach (int i in channelList)
            {
                ChannelGraph pg = new ChannelGraph(this, i);
                GraphCanvas.Children.Add(pg);
            }

            Title = headerFileName; //set window title
            BDFFileInfo.Content = bdf.ToString();
            HDRFileInfo.Content = head.ToString();
            Event.EventFactory.Instance(head.Events); // set up the factory
            EventFileReader efr = null;
            try
            {
                    efr = new EventFileReader(
                        new FileStream(System.IO.Path.Combine(directory, head.EventFile),
                            FileMode.Open, FileAccess.Read)); // open Event file
                bool z = false;
                foreach (Event.InputEvent ie in efr)// read in all Events into dictionary
                {
                    if (ie.IsNaked)
                        events.Add(ie);
                    else if (events.Count(e => e.GC == ie.GC) == 0) //quietly skip duplicates
                    {
                        if (!z) //use first found covered Event to synchronize clocks
                            z = bdf.setZeroTime(ie);
                        events.Add(ie);
                    }
                }
                efr.Close(); //now events is Dictionary of Events in the dataset; lookup by GC
            }
            catch (Exception e)
            {
                ErrorWindow ew = new ErrorWindow();
                ew.Message = "Error reading Event file : " + e.Message + ". Exiting DatasetReviewer.";
                ew.ShowDialog();
                Log.writeToLog(Environment.NewLine +  e.StackTrace);
                Environment.Exit(0);
            }

            try
            {
                ElectrodeInputFileStream eif = new ElectrodeInputFileStream(
                    new FileStream(System.IO.Path.Combine(directory, head.ElectrodeFile),
                        FileMode.Open, FileAccess.Read)); //open Electrode file
                electrodes = eif.etrPositions; //read 'em in
            }
            catch (Exception e)
            {
                ErrorWindow ew = new ErrorWindow();
                ew.Message = "Error reading Electrode file : " + e.Message + ". Exitting DatasetReviewer.";
                ew.ShowDialog();
                Log.writeToLog(Environment.NewLine + e.StackTrace);
                Environment.Exit(0);
            }

            EventMarkers.Width = BDFLength;
            eventTB = new TextBlock(new Run("Events"));
            Canvas.SetBottom(eventTB, ScrollBarSize + 13D);

            //initialize gridline array
            for (int i = 0; i < 18; i++)
            {
                Line l = new Line();
                Grid.SetRow(l, 0);
                Grid.SetColumn(l, 0);
                Grid.SetColumnSpan(l, 2);
                l.Y1 = 0D;
                l.HorizontalAlignment = HorizontalAlignment.Left;
                l.VerticalAlignment = VerticalAlignment.Stretch;
                l.IsHitTestVisible = false;
                l.Stroke = Brushes.LightBlue;
                l.Visibility = Visibility.Hidden;
                Panel.SetZIndex(l, int.MinValue);
                MainFrame.Children.Add(l);
                gridlines[i] = l;
            }

            //Initialize timer
            timer.AutoReset = true;
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

            //Initialize channel information popup
            Color c1 = Color.FromArgb(0xFF, 0xF8, 0xF8, 0xF8);
            Color c2 = Color.FromArgb(0xFF, 0xC8, 0xC8, 0xC8);
            popupTB.Background = new LinearGradientBrush(c1, c2, 45D);
            popupTB.Foreground = Brushes.Black;
            popupTB.Padding = new Thickness(4D);
            Border b = new Border();
            b.BorderThickness = new Thickness(1);
            b.CornerRadius = new CornerRadius(4);
            b.BorderBrush = Brushes.Tomato;
            b.Margin = new Thickness(0, 0, 24, 24); //allows drop shadow to show up
            b.Effect = new DropShadowEffect();
            b.Child = popupTB;
            channelPopup.Placement = PlacementMode.MousePoint;
            channelPopup.AllowsTransparency = true;
            channelPopup.Child = b;

            //Initialize Event information popup
            eventPopupTB.Background = new LinearGradientBrush(c1, c2, 45D);
            eventPopupTB.Foreground = Brushes.Black;
            eventPopupTB.Padding = new Thickness(4D);
            b = new Border();
            b.BorderThickness = new Thickness(1);
            b.CornerRadius = new CornerRadius(4);
            b.BorderBrush = Brushes.Tomato;
            b.Margin = new Thickness(0, 0, 24, 24); //allows drop shadow to show up
            b.Effect = new DropShadowEffect();
            b.Child = eventPopupTB;
            eventPopup.Placement = PlacementMode.MousePoint;
            eventPopup.AllowsTransparency = true;
            eventPopup.Child = b;

            //Initialize FOV slider
            FOV.Maximum = Math.Log10(BDFLength);
            FOV.Value = 1D;
            FOVMax.Text = BDFLength.ToString("0");

            //Initialize Event selector
            bool first = true;
            foreach (EventDictionaryEntry e in head.Events.Values)
            {
                MenuItem mi = (MenuItem)EventSelector.FindResource("EventMenuItem");
                mi.Header = e.Name;
                if (first)
                {
                    mi.IsChecked = true;
                    first = false;
                }
                EventSelector.Items.Add(mi);
            }

            noteFilePath = System.IO.Path.Combine(directory,System.IO.Path.ChangeExtension(head.BDFFile,".notes.txt"));
            //from here on the program is GUI-event driven
        }