/** * This function implements the task Habituation */ IEnumerator StartExperiment() { int trialCnt = 0; // Request to the start the imaging session (if available) sensorScript.StartRecording(); // The experiment continues until the user does not explicitly request for termination while (((trialCnt < numberOfTrials) || numberOfTrials == -1) && (!quitApplication)) { // A new recording element is created. All the following instructions regarding `dataInfo' are meant to collect data during the experiment DataCollector.Element dataInfo = dc.NewElem(); dataInfo.TrialStart = DateTime.Now; // The sensorScript is set to initialize a new trial sensorScript.InitNewTrial(); if (isWhiteNoiseEnabled) // If the white noise is enabled { // Calculate the duration for the white noise float wn = whiteNoiseDuration; if (isWhiteNoiseRandom) { wn *= UnityEngine.Random.Range(minWhiteNoiseDuration, maxWhiteNoiseDuration); } // Request to the sensor script to start the white noise sensorScript.Tone(ToneFrequency.WhiteNoiseStart); dataInfo.WhiteNoiseOn = DateTime.Now; if (useLaser && laserEvent == HFLaserEvent.TrialStart) { if (fractionOfTrialsStimulatedMask[trialCnt]) { sensorScript.TriggerLaser(); dataInfo.LaserStartTime = DateTime.Now; dataInfo.IsLaserActivated = true; dataInfo.fractionOfStimulatedTrials = fractionOfTrialsStimulated; } } // Wait for the amount of time chosen while (wn > 0) { wn -= Time.deltaTime; yield return(0); } // Request to the sensor script to stop the white noise sensorScript.Tone(ToneFrequency.WhiteNoiseStop); dataInfo.WhiteNoiseOff = DateTime.Now; } // Wait for the amount of time chosen in the GUI between the white noise and the cue yield return(new WaitForSecondsRealtime(wnCueDelay)); int cueType = UnityEngine.Random.Range(0, numberOfTargets); dataInfo.VisualCueType = HFTargetConfigurator.shared.GetVisualStimIndex(cueType); dataInfo.AuditoryCueType = HFTargetConfigurator.shared.GetAudioStimIndex(cueType); dataInfo.OutcomeProbability = HFTargetConfigurator.shared.GetOutcomeProbability(cueType); cueTrials[cueType]++; // Set the target size in the variable `actualTargetSize' float actualTargetSize = targetSize; if (!isTargetSizeFixed) { actualTargetSize *= UnityEngine.Random.Range(0.4f, 1.1f); //min size = 0.6; max size = 1.65 //Note: it should be always higher than the mouse indicator size } dataInfo.TargetSize = actualTargetSize; // Set size and position and spawn a new target Vector3 spawnPosition; Quaternion spawnRotation; float timeoutCounter = HFTargetConfigurator.shared.GetDuration(cueType); int posIdx = 0; if (extendedScreen) { posIdx = UnityEngine.Random.Range(0, 3); } if (flat) { spawnPosition = new Vector3(gridPositions[posIdx].Item1, gridPositions[posIdx].Item2, gridPositions[posIdx].Item3); spawnRotation = new Quaternion(); dataInfo.TargetPos.X = gridPositions[posIdx].Item1; dataInfo.TargetPos.Y = gridPositions[posIdx].Item2; dataInfo.TargetPos.Z = gridPositions[posIdx].Item3; } else { spawnPosition = new Vector3(250f, 1.6f, 250f); spawnRotation = Quaternion.Euler(gridPositions[posIdx].Item1, gridPositions[posIdx].Item2, gridPositions[posIdx].Item3); dataInfo.TargetPos.Pitch = gridPositions[posIdx].Item2; dataInfo.TargetPos.Yaw = gridPositions[posIdx].Item1; dataInfo.TargetPos.Roll = gridPositions[posIdx].Item3; } if (HFTargetConfigurator.shared.GetSoundBefore(cueType)) { // Preallocation of the target targetSpawned = Instantiate(Target, spawnPosition, spawnRotation); targetSpawned.GetComponentInChildren <Renderer>().enabled = false; // Arrives here if for that cue the order should be audio -> delay -> video sensorScript.Tone(GetFrequency(HFTargetConfigurator.shared.GetAudioStimIndex(cueType))); dataInfo.AuditoryOn = DateTime.Now; // Activate laser stimulation iff: a) user requested to use laser, b) the event attached is "auditory on", c) the audio stimulus is not disabled if (useLaser && (laserEvent == HFLaserEvent.AuditoryOn) && (!(HFTargetConfigurator.shared.GetAudioStimIndex(cueType) == 0))) { if (fractionOfTrialsStimulatedMask[trialCnt]) { sensorScript.TriggerLaser(); dataInfo.LaserStartTime = DateTime.Now; dataInfo.IsLaserActivated = true; dataInfo.fractionOfStimulatedTrials = fractionOfTrialsStimulated; } } yield return(new WaitForSecondsRealtime(HFTargetConfigurator.shared.GetDelays(cueType))); targetSpawned.GetComponentInChildren <Renderer>().material = GetMaterial(HFTargetConfigurator.shared.GetVisualStimIndex(cueType)); targetSpawned.GetComponentInChildren <Renderer>().enabled = !(HFTargetConfigurator.shared.GetVisualStimIndex(cueType) == 0); if (isVisualStimEnabled) { targetSpawned.transform.localScale = new Vector3(targetSize, targetSize, 1.0f); } dataInfo.VisualTargetOnTime = DateTime.Now; // Activate laser stimulation iff: a) user requested to use laser, b) the event attached is "visual on", c) the visual stimulus is not disabled if (useLaser && (laserEvent == HFLaserEvent.VisualTargetOn) && (!(HFTargetConfigurator.shared.GetVisualStimIndex(cueType) == 0))) { if (fractionOfTrialsStimulatedMask[trialCnt]) { sensorScript.TriggerLaser(); dataInfo.LaserStartTime = DateTime.Now; dataInfo.IsLaserActivated = true; dataInfo.fractionOfStimulatedTrials = fractionOfTrialsStimulated; } } } else { // Arrives here if for that cue the order should be video -> delay -> audio targetSpawned = Instantiate(Target, spawnPosition, spawnRotation); targetSpawned.GetComponentInChildren <Renderer>().enabled = !(HFTargetConfigurator.shared.GetVisualStimIndex(cueType) == 0); targetSpawned.GetComponentInChildren <Renderer>().material = GetMaterial(HFTargetConfigurator.shared.GetVisualStimIndex(cueType)); if (isVisualStimEnabled) { targetSpawned.transform.localScale = new Vector3(targetSize, targetSize, 1.0f); } dataInfo.VisualTargetOnTime = DateTime.Now; // Activate laser stimulation iff: a) user requested to use laser, b) the event attached is "target on", c) the visual stimulus is not disabled if (useLaser) { if ((laserEvent == HFLaserEvent.VisualTargetOn) && (!(HFTargetConfigurator.shared.GetVisualStimIndex(cueType) == 0))) { if (fractionOfTrialsStimulatedMask[trialCnt]) { sensorScript.TriggerLaser(); dataInfo.LaserStartTime = DateTime.Now; dataInfo.IsLaserActivated = true; dataInfo.fractionOfStimulatedTrials = fractionOfTrialsStimulated; } } } yield return(new WaitForSecondsRealtime(HFTargetConfigurator.shared.GetDelays(cueType))); sensorScript.Tone(GetFrequency(HFTargetConfigurator.shared.GetAudioStimIndex(cueType))); dataInfo.AuditoryOn = DateTime.Now; // Activate laser stimulation iff: a) user requested to use laser, b) the event attached is "auditory on", c) the audio stimulus is not disabled if (useLaser && (laserEvent == HFLaserEvent.AuditoryOn) && (!(HFTargetConfigurator.shared.GetAudioStimIndex(cueType) == 0))) { if (fractionOfTrialsStimulatedMask[trialCnt]) { sensorScript.TriggerLaser(); dataInfo.LaserStartTime = DateTime.Now; dataInfo.IsLaserActivated = true; dataInfo.fractionOfStimulatedTrials = fractionOfTrialsStimulated; } } } // Set a destroy timer equals to 1 second. This duration is not adjustable, because should be coordinated with the sound (that is embedded in the arduino script). Destroy(targetSpawned, timeoutCounter); // Wait for the cue to disappear while (timeoutCounter > 0) { timeoutCounter -= Time.deltaTime; yield return(0); } dataInfo.TargetDisappearingTime = DateTime.Now; if (useLaser && (laserEvent == HFLaserEvent.VisualTargetOff)) { if (fractionOfTrialsStimulatedMask[trialCnt]) { sensorScript.TriggerLaser(); dataInfo.LaserStartTime = DateTime.Now; dataInfo.IsLaserActivated = true; dataInfo.fractionOfStimulatedTrials = fractionOfTrialsStimulated; } } // Wait for the amount of time chosen in the GUI between the white noise and the cue yield return(new WaitForSecondsRealtime(cueRewardDelay)); dataInfo.CueOutcomeDelay = cueRewardDelay; if (HFTargetConfigurator.shared.GetPumpType(cueType) == 0) { dataInfo.OutcomeType = false; } else { dataInfo.OutcomeType = true; } // Procedure of online calculation of the ratio. if ((cueRewardedTrials[cueType] / cueTrials[cueType]) < HFTargetConfigurator.shared.GetOutcomeProbability(cueType)) // If the trial should be rewarded { cueRewardedTrials[cueType]++; dataInfo.IsOutcomeDelivered = true; // Request to the sensor script to play the `Success' or `Missed' tone and to deliver the reward/punishment if (HFTargetConfigurator.shared.GetPumpType(cueType) == 0) { sensorScript.Tone(ToneFrequency.SuccessTone); sensorScript.Reward(); dataInfo.OutcomeTime = DateTime.Now; // activate laser if it was requested on reward or rewardTone if (useLaser && (laserEvent == HFLaserEvent.Reward || laserEvent == HFLaserEvent.RewardToneOn || laserEvent == HFLaserEvent.Outcome || laserEvent == HFLaserEvent.OutcomeToneOn)) { if (fractionOfTrialsStimulatedMask[trialCnt]) { sensorScript.TriggerLaser(); dataInfo.LaserStartTime = DateTime.Now; dataInfo.IsLaserActivated = true; dataInfo.fractionOfStimulatedTrials = fractionOfTrialsStimulated; } } } else { sensorScript.Tone(ToneFrequency.MissedTone); sensorScript.Punishment(); dataInfo.OutcomeTime = DateTime.Now; // activate laser if it was requested on penalty or penaltyTone if (useLaser && (laserEvent == HFLaserEvent.Punishment || laserEvent == HFLaserEvent.PunishmentToneOn || laserEvent == HFLaserEvent.Outcome || laserEvent == HFLaserEvent.OutcomeToneOn)) { if (fractionOfTrialsStimulatedMask[trialCnt]) { sensorScript.TriggerLaser(); dataInfo.LaserStartTime = DateTime.Now; dataInfo.IsLaserActivated = true; dataInfo.fractionOfStimulatedTrials = fractionOfTrialsStimulated; } } } // Check if in the remaining time of the trial (aka ITI) the reward is consumed or not bool consumed = false; float iti = interTrialTime; if (isInterTrialTimeRandom) { iti = UnityEngine.Random.Range(minInterTrialTime, maxInterTrialTime); } dataInfo.ITIOn = DateTime.Now; while (iti > 0) { if (sensorScript.numberOfLicksAfterReward >= licksToReward) { consumed = true; } iti -= Time.deltaTime; yield return(0); } dataInfo.ITIOff = DateTime.Now; if (consumed) { // If a reward has been consumed, then request to the sensor script to send the signal of `Consumed' dataInfo.IsRewardConsumed = true; sensorScript.Consumed(); } } else // If the trial should NOT be rewarded { // Wait for the ITI dataInfo.ITIOn = DateTime.Now; if (isInterTrialTimeRandom) { yield return(new WaitForSecondsRealtime(UnityEngine.Random.Range(minInterTrialTime, maxInterTrialTime))); } else { yield return(new WaitForSecondsRealtime(interTrialTime)); } dataInfo.ITIOff = DateTime.Now; } // Save the licks timestamps and the head positions dataInfo.LicksTimeOptical = new List <DateTime>(sensorScript.licksTimeOptical); dataInfo.LicksTimeElectrical = new List <DateTime>(sensorScript.licksTimeElectrical); dataInfo.HeadPositions = new List <DataCollector.Position>(sensorScript.headPositions); dataInfo.TrialEnd = DateTime.Now; trialCnt++; } sensorScript.StopRecording(); Debug.Log("Task completed"); }