Example #1
0
        void TimeBasedCalculation()
        {
            // New window time is the original window time minus overlapping window. Set elapsed time in proportional position.
            elapsedWindowTime = windowTime * overlappingFraction;

            // Check that data is available
            if (timestamps.Count == 0 && dataBuffer.Count == 0)
            {
                ExciteOMeterManager.LogInFile("No incoming data " + incomingDataType.ToString() + " was found to calculate feature " + outputDataType.ToString());
                return;
            }
            // Calculate feature
            featureValue = CalculateFeature(timestamps.ToArray(), dataBuffer.ToArray());

            // Send events and log in file
            ExciteOMeterManager.DebugLog("A new feature was calculated in " + outputDataType.ToString() + ": " + timestamps[timestamps.Count - 1] + ", " + featureValue.ToString());
            EoM_Events.Send_OnDataReceived(outputDataType, timestamps[timestamps.Count - 1], featureValue);
            LoggerController.instance.WriteLine(logIdentifier, timestamps[timestamps.Count - 1] + "," + featureValue.ToString());

            // Rearrange overlap in signal
            // Overlap should not be greater than 95%, because it would generate very often feature calculations that might affect performance.
            int elementsToDelete = (int)(Mathf.Clamp(1.0f - (overlappingFraction), 0f, 0.95f) * dataBuffer.Count);

            timestamps.RemoveRange(0, elementsToDelete);
            dataBuffer.RemoveRange(0, elementsToDelete);
        }
        /// <summary>
        /// Calculate feature value from a unidimensional sample-based feature
        /// </summary>
        void SampleBasedCalculation()
        {
            // Check that data is available
            if (timestamps.Count == 0 && dataBuffer.Count == 0)
            {
                // ExciteOMeterManager.DebugLog("No timestamps or data were found to calculate features");
                ExciteOMeterManager.LogInFile("No incoming data " + incomingDataType.ToString() + " was found to calculate feature " + outputDataType.ToString());
                return;
            }
            // Calculate feature
            featureValue = CalculateFeature(timestamps.ToArray(), dataBuffer.ToArray());

            // Calculate offset of timestamp that corresponds to the calculated feature (# displacements to the left in timestamps)
            // Examples: Assume `sampleBuffer=5`
            //           If `offsetSamplesTimestamp=0`, t for calculated feature is [t-4,t-3,...,t]
            //           If `offsetSamplesTimestamp=3`, t for calculated feature is [t-1,t,t+1,t+2,t+3]
            indexOffsetForTimestamp = sampleBuffer - offsetSamplesTimestamp - 1;

            // Send events and log in file
            ExciteOMeterManager.DebugLog("A new feature was calculated in " + outputDataType.ToString() + ": " + timestamps[indexOffsetForTimestamp] + ", " + featureValue.ToString());

            // Flag to know if it is the first calculation of the feature.
            // If so, the new feature has to match all the timestamps existing before the first timestamp of the feature.
            if (matchLengthOfInputSignal)
            {
                if (isFirstCalculatedFeature)
                {
                    isFirstCalculatedFeature = false;
                    idxStartRepeating        = 0; // No previous data in array, repeat from beginning of input timestamps.
                }
                else
                {
                    // CASE: Match length and buffer already contains data from previous window
                    // Based on overlap and offset, the position where to start repeating timestamps is the following formula.
                    idxStartRepeating = overlappingSamples - offsetSamplesTimestamp;
                }

                // Fill the previous timestamps of the input signal with the same value of this feature.
                for (int i = idxStartRepeating; i <= indexOffsetForTimestamp; i++)
                {
                    // Write in files to collect data corresponding to
                    EoM_Events.Send_OnDataReceived(outputDataType, timestamps[i], featureValue);
                    LoggerController.instance.WriteLine(logIdentifier, ExciteOMeterManager.ConvertFloatToString(timestamps[i]) + "," + ExciteOMeterManager.ConvertFloatToString(featureValue));
                }
            }
            else
            {
                Debug.LogWarning("Error calculating feature. Matching sampling error: logIdentifier" + logIdentifier.ToString());

                //// CASE: DO NOT MATCH LENGTH OF INPUT SIGNAL, BUT USE TIMESTAMP DIFFERENT THAN LAST SAMPLE
                //EoM_Events.Send_OnDataReceived(outputDataType, timestamps[indexOffsetForTimestamp],  featureValue);
                //LoggerController.instance.WriteLine(logIdentifier, ExciteOMeterManager.ConvertFloatToString(timestamps[indexOffsetForTimestamp]) + "," + ExciteOMeterManager.ConvertFloatToString(featureValue));
            }

            // Rearrange overlap in signal
            elementsToDelete = sampleBuffer - overlappingSamples;

            timestamps.RemoveRange(0, elementsToDelete);
            dataBuffer.RemoveRange(0, elementsToDelete);
        }
Example #3
0
        // Start is called before the first frame update
        void Start()
        {
            // PostProcessing flag
            numInstances++;

            // Default values, if this needs to be changed per feature reimplementing the following function in the child class
            isTimeBasedFeature  = !SettingsManager.Values.featureSettings.DEFAULT_IS_SAMPLE_BASED;
            windowTime          = SettingsManager.Values.featureSettings.DEFAULT_WINDOW_TIME_SECS;
            overlappingFraction = SettingsManager.Values.featureSettings.DEFAULT_OVERLAP_FRACTION;

            isSampleBasedFeature = SettingsManager.Values.featureSettings.DEFAULT_IS_SAMPLE_BASED;
            sampleBuffer         = SettingsManager.Values.featureSettings.DEFAULT_SAMPLE_BUFFER;
            overlappingSamples   = SettingsManager.Values.featureSettings.DEFAULT_OVERLAP_SAMPLES;

            offsetSamplesTimestamp = SettingsManager.Values.featureSettings.DEFAULT_OFFSET_SAMPLES_TIMESTAMP;

            // Only for sample-based, whether input and output are forced to have same length by resampling data.
            matchLengthOfInputSignal = SettingsManager.Values.featureSettings.matchInputOutputLength;

            // CONDITIONS
            if (isSampleBasedFeature)
            {
                if (overlappingSamples >= sampleBuffer)
                {
                    // Error, the number of samples to delete
                    ExciteOMeterManager.LogInFile("The samples to delete in buffer feature " + outputDataType.ToString() + " are larger than sampleBufferLength. Check config.json");
                    overlappingSamples = 0;
                }
                else if (offsetSamplesTimestamp > overlappingSamples)
                {
                    ExciteOMeterManager.LogInFile("The offset timestamp of timestamp in feature " + outputDataType.ToString() + " needs to be lower than overlapSamplesLength. Check config.json");
                    offsetSamplesTimestamp = 0;
                }
            }
            // If there are some configurations needed for the specific feature
            SetupStart();
        }
        ////////////// MULTIDIMENSIONAL FEATURES
        /// <summary>
        /// Calculate features from a MULTIDIMENSIONAL sample-based feature
        /// </summary>
        void SampleBasedCalculationArray()
        {
            // Check that data is available
            if (timestamps.Count == 0 && dataBufferArray.Count == 0)
            {
                // ExciteOMeterManager.DebugLog("No timestamps or data were found to calculate features");
                ExciteOMeterManager.LogInFile("No incoming data " + incomingDataType.ToString() + " was found to calculate feature " + outputDataType.ToString());
                return;
            }
            // Calculate feature
            featureArray = CalculateFeatureArray(timestamps.ToArray(), dataBufferArray.ToArray());

            // Calculate offset of timestamp that corresponds to the calculated feature (# displacements to the left in timestamps)
            // Examples: Assume `sampleBuffer=5`
            //           If `offsetSamplesTimestamp=0`, t for calculated feature is [t-4,t-3,...,t]
            //           If `offsetSamplesTimestamp=3`, t for calculated feature is [t-1,t,t+1,t+2,t+3]
            indexOffsetForTimestamp = sampleBuffer - offsetSamplesTimestamp - 1;

            // Send events and log in file
            ExciteOMeterManager.DebugLog("A new feature was calculated in " + outputDataType.ToString() + ": " + timestamps[indexOffsetForTimestamp] + ", Length: " + featureArray.Length.ToString());

            // Flag to know if it is the first calculation of the feature.
            // If so, the new feature has to match all the timestamps existing before the first timestamp of the feature.
            if (matchLengthOfInputSignal)
            {
                if (isFirstCalculatedFeature)
                {
                    isFirstCalculatedFeature = false;
                    idxStartRepeating        = 0; // No previous data in array, repeat from beginning of input timestamps.
                }
                else
                {
                    // CASE: Match length and buffer already contains data from previous window
                    // Based on overlap and offset, the position where to start repeating timestamps is the following formula.
                    idxStartRepeating = overlappingSamples - offsetSamplesTimestamp;
                }

                // Get the DataType for each of the features that are calculated
                DataType[] featureDataTypes = Constants.SubsetOfFeaturesTransformDataTypes(logIdentifier);

                // Fill the previous timestamps of the input signal with the same value of this feature.
                for (int i = idxStartRepeating; i <= indexOffsetForTimestamp; i++)
                {
                    // Write in files to collect data corresponding to

                    // Create string to save in CSV
                    string featureArrayText = "";
                    foreach (float v in featureArray)
                    {
                        featureArrayText += "," + ExciteOMeterManager.ConvertFloatToString(v, 4);
                    }

                    bool logIsWriting = LoggerController.instance.WriteLine(logIdentifier, ExciteOMeterManager.ConvertFloatToString(timestamps[i]) + featureArrayText);
                    if (!logIsWriting)
                    {
                        Debug.LogWarning("Error writing movement data. Please setup LoggerController with a file with LogID is" + logIdentifier.ToString());
                    }


                    //// --------- TODO
                    //// Send an event with the multidimensional data for the receivers taht can handle multidimensionality
                    //EoM_Events.Send_OnDataArrayReceived(outputDataType, timestamps[i], featureArray);

                    //// Visualizer is designed to analyze unidimensional data, therefore multidimensional needs to be sent one by one to the system
                    //StartCoroutine(SendDataEventsMovement(ExciteOMeterManager.GetTimestamp()));
                    // BUG: Sending events from the coroutine does not seem to be received...
                    // ---------
                    // If the above works, delete the remaining code!! ----------------------
                    if (featureDataTypes.Length != featureArray.Length)
                    {
                        Debug.LogError("Mismatch between the calculated array of features and the expected, in feature with logIdentifier" + logIdentifier);
                        return;
                    }

                    for (int j = 0; j < featureArray.Length; j++)
                    {
                        EoM_Events.Send_OnDataReceived(featureDataTypes[j], timestamps[i], featureArray[j]);
                    }
                    /// --------------------------------------------------------
                }
            }
            else
            {
                // CASE: DO NOT MATCH LENGTH OF INPUT SIGNAL, BUT USE TIMESTAMP DIFFERENT THAN LAST SAMPLE
                EoM_Events.Send_OnDataReceived(outputDataType, timestamps[indexOffsetForTimestamp], featureValue);
                LoggerController.instance.WriteLine(logIdentifier, ExciteOMeterManager.ConvertFloatToString(timestamps[indexOffsetForTimestamp]) + "," + ExciteOMeterManager.ConvertFloatToString(featureValue));
            }

            // Rearrange overlap in signal
            elementsToDelete = sampleBuffer - overlappingSamples;

            timestamps.RemoveRange(0, elementsToDelete);
            dataBufferArray.RemoveRange(0, elementsToDelete);
        }