Ejemplo n.º 1
0
        /// <summary>
        /// Matlab-friendly factory method to run a single Epoch.
        /// </summary>
        /// <remarks>Constructs an Epoch with homogenous stimulus ID, sample rate and units, then runs the
        /// constructed Epoch.
        /// </remarks>
        ///
        /// <param name="protocolID">Protocol ID of the constructed Epoch</param>
        /// <param name="parameters">Protocol parameters of the constructed Epoch</param>
        /// <param name="stimulusID">Stimulus plugin ID for all constructed stimuli</param>
        /// <param name="stimulusSampleRate">Simulus sample rate for all constructed stimuli</param>
        /// <param name="stimuli">Simulus data for output devices</param>
        /// <param name="backgrounds">Backgrounds for output devices</param>
        /// <param name="responses">Devices from which to record Responses</param>
        /// <param name="persistor">EpochPersistor to persist Epoch</param>
        public void RunEpoch(
            string protocolID,
            IDictionary <string, object> parameters,
            string stimulusID,
            Measurement stimulusSampleRate,
            IDictionary <ExternalDeviceBase, IEnumerable <IMeasurement> > stimuli,
            IDictionary <ExternalDeviceBase, IMeasurement> backgrounds,
            IEnumerable <ExternalDeviceBase> responses,
            EpochPersistor persistor)
        {
            var epoch = new Epoch(protocolID,
                                  parameters);

            foreach (var dev in stimuli.Keys)
            {
                var data = new OutputData(stimuli[dev],
                                          stimulusSampleRate,
                                          true);
                var stim = new RenderedStimulus(stimulusID,
                                                (IDictionary <string, object>) new Dictionary <string, object> {
                    { "data", data }
                },
                                                (IOutputData)data);

                epoch.Stimuli[dev] = stim;
            }

            foreach (var dev in responses)
            {
                epoch.Responses[dev] = new Response();
            }

            foreach (var dev in backgrounds.Keys)
            {
                epoch.Background[dev] = new Epoch.EpochBackground(backgrounds[dev], stimulusSampleRate);
            }

            RunEpoch(epoch, persistor);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Begin a new Epoch Group (i.e. a logical block of Epochs). As each Epoch Group is persisted
        /// to a separate data file, this method creates the appropriate output file and
        /// EpochPersistor instance.
        /// </summary>
        /// <param name="path">The name of the file into which to store the epoch; if the name
        ///   ends in ".xml", it will store the file using the EpochXMLPersistor, and if the name
        ///   ends in ".hdf5", it will store the file using the EpochHDF5Persistor. This file will
        ///   be overwritten if it already exists at this location.</param>
        /// <param name="epochGroupLabel">Label for the new Epoch Group</param>
        /// <param name="source">Identifier for EpochGroup's Source</param>
        /// <param name="keywords"></param>
        /// <param name="properties"></param>
        /// <returns>The EpochPersistor instance to be used for saving Epochs</returns>
        /// <see cref="RunEpoch"/>
        public EpochPersistor BeginEpochGroup(string path, string epochGroupLabel, string source, IEnumerable <string> keywords, IDictionary <string, object> properties)
        {
            EpochPersistor result = null;

            if (path.EndsWith(".xml"))
            {
                result = new EpochXMLPersistor(path);
            }
            else if (path.EndsWith(".hdf5"))
            {
                result = new EpochHDF5Persistor(path, null);
            }
            else
            {
                throw new ArgumentException(String.Format("{0} doesn't look like a legit Epoch filename", path));
            }

            var kws   = keywords == null ? new string[0] : keywords.ToArray();
            var props = properties ?? new Dictionary <string, object>();

            result.BeginEpochGroup(epochGroupLabel, source, kws, props, Guid.NewGuid(), DateTime.Now);

            return(result);
        }
Ejemplo n.º 3
0
        private void RunSingleEpoch(double sampleRate, int nChannels, EpochPersistor epochPersistor)
        {
            Epoch e;
            IExternalDevice dev0;
            RenderedStimulus stim1;
            IExternalDevice dev1;
            RenderedStimulus stim2;
            IList<IMeasurement> stimData;
            var controller = SetupController(sampleRate, out e, out dev0, out stim1, out dev1, out stim2, out stimData, nChannels);

            controller.RunEpoch(e, epochPersistor);

            Assert.AreEqual((TimeSpan)stim1.Duration, e.Responses[dev0].Duration);
            if (nChannels > 1)
                Assert.AreEqual((TimeSpan)stim2.Duration, e.Responses[dev1].Duration);

            var inputData = e.Responses[dev0].Data;
            const double MAX_VOLTAGE_DIFF = 0.001;
            int failures = inputData.Select((t, i) => t.QuantityInBaseUnit - stimData[i].QuantityInBaseUnit)
                .Count(dif => Math.Abs(dif) > (decimal) MAX_VOLTAGE_DIFF);

            Assert.AreEqual(0, failures);
        }
Ejemplo n.º 4
0
 private void SaveEpoch(EpochPersistor persistor, Epoch e)
 {
     persistor.Serialize(e);
     OnSavedEpoch(e);
 }
Ejemplo n.º 5
0
        /// <summary>
        /// The core entry point for the Controller Facade; push an Epoch in here, and when the
        /// Epoch is finished processing, control will be returned to you.
        ///
        /// <para>In other words, this
        /// method is blocking--the Controller cannot run more than one Epoch at a time.</para>
        /// </summary>
        ///
        /// <param name="e">Single Epoch to present</param>
        /// <param name="persistor">EpochPersistor for saving the data. May be null to indicate epoch should not be persisted</param>
        /// <exception cref="ValidationException">Validation failed for this Controller</exception>
        public void RunEpoch(Epoch e, EpochPersistor persistor)
        {
            var cts = new CancellationTokenSource();
            var cancellationToken = cts.Token;

            Task persistenceTask = null;

            if (!ValidateEpoch(e))
            {
                throw new ArgumentException("Epoch is not valid");
            }


            if (!Validate())
            {
                throw new ValidationException(Validate());
            }


            // Starting with this Epoch

            var cEpoch = CurrentEpoch;

            CurrentEpoch = e;

            EventHandler <TimeStampedEventArgs> nextRequested = (c, args) =>
            {
                DAQController.RequestStop();
                OnDiscardedEpoch(CurrentEpoch);
            };

            bool epochPersisted = false;
            EventHandler <TimeStampedEpochEventArgs> inputReceived = (c, args) =>
            {
                if (CurrentEpoch != null &&
                    CurrentEpoch.IsComplete)
                {
                    log.Debug("Epoch complete. Requesting DAQController stop.");
                    DAQController.RequestStop();
                    if (persistor != null && !epochPersisted)
                    {
                        Epoch completedEpoch = CurrentEpoch;
                        persistenceTask = Task.Factory.StartNew(() =>
                        {
                            log.DebugFormat("Saving completed Epoch ({0})...", completedEpoch.StartTime);
                            SaveEpoch(persistor, completedEpoch);
                        },
                                                                cancellationToken,
                                                                TaskCreationOptions.PreferFairness,
                                                                SerialTaskScheduler)
                                          .ContinueWith((task) =>
                        {
                            cancellationToken.ThrowIfCancellationRequested();

                            if (task.IsFaulted &&
                                task.Exception != null)
                            {
                                throw task.Exception;
                            }

                            OnCompletedEpoch(completedEpoch);
                        },
                                                        cancellationToken);

                        epochPersisted = true;
                    }
                }
            };

            EventHandler <TimeStampedExceptionEventArgs> exceptionalStop = (daq, args) =>
            {
                log.Debug(
                    "Discarding epoch due to exception");
                OnDiscardedEpoch(CurrentEpoch);
                throw new SymphonyControllerException(
                          "DAQ Controller stopped", args.Exception);
            };

            try
            {
                NextEpochRequested            += nextRequested;
                ReceivedInputData             += inputReceived;
                DAQController.ExceptionalStop += exceptionalStop;

                e.StartTime = Maybe <DateTimeOffset> .Some(this.Clock.Now);

                log.DebugFormat("Starting epoch: {0}", CurrentEpoch.ProtocolID);
                DAQController.Start(false);
            }
            finally
            {
                CurrentEpoch                   = cEpoch;
                NextEpochRequested            -= nextRequested;
                ReceivedInputData             -= inputReceived;
                DAQController.ExceptionalStop -= exceptionalStop;

                DAQController.WaitForInputTasks();

                //Clear remaining input
                UnusedInputData.Clear();
            }

            if (persistenceTask != null)
            {
                try
                {
                    persistenceTask.Wait();
                }
                catch (AggregateException ex)
                {
                    log.ErrorFormat("An error occurred while saving Epoch: {0}", ex);
                    throw new SymphonyControllerException("Unable to write Epoch data to persistor.",
                                                          ex.Flatten());
                }
            }
        }
Ejemplo n.º 6
0
 /// <summary>
 /// Closes an Epoch Group. This method should be called after running all Epochs in the
 /// Epoch Group represented by EpochPersistor to give the persistor a chance to write any
 /// neceesary closing information.
 /// <para>
 /// Closes the persistor's file.
 /// </para>
 /// </summary>
 /// <param name="e">EpochPersistor representing the completed EpochGroup</param>
 /// <see cref="BeginEpochGroup"/>
 public void EndEpochGroup(EpochPersistor e)
 {
     e.EndEpochGroup();
     e.Close();
 }