Search Unity

logging a transform every 0.5 seconds for means of getting an average...

Discussion in 'Scripting' started by Genkidevelopment, Jan 31, 2015.

  1. Genkidevelopment

    Genkidevelopment

    Joined:
    Jan 2, 2015
    Posts:
    186
    I would like to log the transform.position.z of an object every 0.5 seconds... store this data and calculate an average of the transform.position during the last 5 seconds... Thus after 5 seconds each new log should replace the oldest...

    It is a very difficult question to 'google' hence I am here asking for some tips as to where to look regards researching the problem...

    My guess is that coroutines, and lists would be the way to do this. I have no experience of these functions yet.

    Thanks for any tips :)
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    I'd create a struct with 2 float values, one for the time, and one for the z position.

    Next I'd have a queue of these structs.

    On every frame (Update) I'd stick a value in the queue, dequeue any of the first elements that are older than 0.5 seconds, than average the queue.
     
    Genkidevelopment likes this.
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    Like so:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5.  
    6. public class AveragingTest : MonoBehaviour
    7. {
    8.  
    9.     public struct Cache
    10.     {
    11.         public float time;
    12.         public float z;
    13.  
    14.         public Cache(float t, float z)
    15.         {
    16.             this.time = t;
    17.             this.z = z;
    18.         }
    19.     }
    20.  
    21.  
    22.     public float AverageDur = 0.5f;
    23.     private Queue<Cache> _queue = new Queue<Cache>();
    24.  
    25.  
    26.     private void Update()
    27.     {
    28.         _queue.Enqueue(new Cache(Time.time, this.transform.position.z));
    29.  
    30.         while(Time.time - _queue.Peek().time > this.AverageDur)
    31.         {
    32.             _queue.Dequeue();
    33.         }
    34.  
    35.         float average = _queue.Sum((c) => c.z) / (float)_queue.Count;
    36.     }
    37.  
    38. }
    39.  
     
    Genkidevelopment likes this.
  4. Genkidevelopment

    Genkidevelopment

    Joined:
    Jan 2, 2015
    Posts:
    186

    Thank you very much for the generous answer... 'Structs' are another thing I have no experience of yet... I will need to watch some 'learn' stuff before I grasp what you are advising me to do! I have just learned and coded a coroutine that will run every 0.5 seconds

    I need the average over 5 seconds (sorry, if that was unclear), Take a reading every 0.5 seconds and average the 10 most recent... (without storing any of the values that are older than 5 seconds)!

    Thanks again, and I shall now look into structs and try and gain a basic understanding.


    Peace :D
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    a struct is similar to a class, but it is a value type instead of a reference type.

    If you create a variable from a struct, and than create another variable equal to the first, the two values are equal in value, but aren't the same object.

    Where as a class, the two are both the same object.

    Example, Vector3 is a struct.

    Code (csharp):
    1.  
    2. Vector3 a = new Vector3(0,1,0);
    3. Vector3 b = a;
    4. Debug.Log(a == b); //they are equal, because both are <0,1,0>
    5. a.z = 1f;
    6. Debug.Log(a == b); //they are no longer equal, because a is <0,1,1> and b is <0,1,0>
    7.  
    Where as say transform is a class:

    Code (csharp):
    1.  
    2. Transform a = this.transform;
    3. Transform b = a;
    4. a.position = new Vector3(0,1,0);
    5. Debug.Log(a.position == b.position); //equal, because a and b are the same object, so you're pulling the same position
    6.  
     
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    Also, if you wanted it as a coroutine that tracked every 0.5 seconds, that's easily doable as well.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5.  
    6. public class AveragingTest : MonoBehaviour
    7. {
    8.  
    9.     public struct Cache
    10.     {
    11.         public float time;
    12.         public float z;
    13.  
    14.         public Cache(float t, float z)
    15.         {
    16.             this.time = t;
    17.             this.z = z;
    18.         }
    19.     }
    20.  
    21.     public float SampleDur = 0.5f;
    22.     public float AverageDur = 5f;
    23.     private Queue<Cache> _queue = new Queue<Cache>();
    24.  
    25.  
    26.     private void Start()
    27.     {
    28.         this.StartCoroutine(this.AverageTicker());
    29.     }
    30.  
    31.     private System.Collections.IEnumerator AverageTicker()
    32.     {
    33.         Loop:
    34.  
    35.         _queue.Enqueue(new Cache(Time.time, this.transform.position.z));
    36.  
    37.         while (Time.time - _queue.Peek().time > this.AverageDur)
    38.         {
    39.             _queue.Dequeue();
    40.         }
    41.  
    42.         float average = _queue.Sum((c) => c.z) / (float)_queue.Count;
    43.  
    44.         yield return new WaitForSeconds(this.SampleDur);
    45.  
    46.         goto Loop;
    47.     }
    48.  
    49. }
    50.  
    51.  
     
  7. Genkidevelopment

    Genkidevelopment

    Joined:
    Jan 2, 2015
    Posts:
    186
    Thanks again... great answers as well, I am now watching and reading tutorials... I have been working on the coroutine method for solving this... with the help of an array... I guess to someone whom knows better this will be an ugly read :D :D :D But here is the code I have compiled, and I'm proud of it, for if nothing else it shows how far I have come within the last month :D

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. public class BallWeight : MonoBehaviour {
    5. public float [] WeightPositions;
    6. public Transform Ball;
    7. // Use this for initialization
    8. void Start ()
    9. {
    10. WeightPositions = new float[10];
    11. StartCoroutine (BallWeightValue (0.5f));
    12. }
    13. IEnumerator  BallWeightValue (float TimeGap)
    14. {
    15. WeightPositions [0] = Ball.position.z;
    16. yield return new WaitForSeconds (TimeGap);
    17. WeightPositions [1] = Ball.position.z;
    18. yield return new WaitForSeconds (TimeGap);
    19. WeightPositions [2] = Ball.position.z;
    20. yield return new WaitForSeconds (TimeGap);
    21. WeightPositions [3] = Ball.position.z;
    22. yield return new WaitForSeconds (TimeGap);
    23. WeightPositions [4] = Ball.position.z;
    24. yield return new WaitForSeconds (TimeGap);
    25. WeightPositions [5] = Ball.position.z;
    26. yield return new WaitForSeconds (TimeGap);
    27. WeightPositions [6] = Ball.position.z;
    28. yield return new WaitForSeconds (TimeGap);
    29. WeightPositions [7] = Ball.position.z;
    30. yield return new WaitForSeconds (TimeGap);
    31. WeightPositions [8] = Ball.position.z;
    32. yield return new WaitForSeconds (TimeGap);
    33. WeightPositions [9] = Ball.position.z;
    34. yield return new WaitForSeconds (TimeGap);
    35. // ???  InvokeRepeating("IEnumerator BallWeightValue", 0, 0F);
    36. }
    37. }
    As you can see, I am yet to figure out how to invoke.repeat the sequence... But it is filling up the array values perfectly when I play game and view scene view... Even after invoking I will need to total all ten of the values contained within the array and divide by ten (ie get average), this will provide an updated average every 0.5 seconds!...

    And how hard are you laughing at my code attempts :D :D I really have no idea if what I have done is costly regards performance... How does the method you suggested compare with regards performance...
    And I will revisit and futher analyse what you have implemented... Only I try not to just copy paste code... until I can understand what is going on, I am getting better though...


    Thanks again if you can answer and shed more light on my coding learning curve! and peace ![/code]
     
  8. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    just put the goto loop like I did on mine
     
  9. Genkidevelopment

    Genkidevelopment

    Joined:
    Jan 2, 2015
    Posts:
    186
    OK thanks for the time again... So many things I need to learn... !

    One thing... In your script you keep referring to 'this' what are you meaning by 'this'? Are you referring to the gameobject the script is attached to - sorry if its another dumb question. I appreciate your help...
     
  10. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    'this' is the instance of the object you're code is running in.


    When you say:

    Code (csharp):
    1.  
    2. WeightedPosition [7] = Ball.position.z;
    3.  
    you could ALSO say:

    Code (csharp):
    1.  
    2. this.WeightedPosition [7] = Ball.position.z;
    3.  
    The 'this' gets implied, and the compiler will treat both the same. I just use 'this' out of convention because I find it more readable. I know when I see "this" I'm referring to a member of the class in question.
     
    Genkidevelopment likes this.
  11. Genkidevelopment

    Genkidevelopment

    Joined:
    Jan 2, 2015
    Posts:
    186

    Ah I see, thanks for the insight and explanation :D
     
  12. Genkidevelopment

    Genkidevelopment

    Joined:
    Jan 2, 2015
    Posts:
    186
    Yes! I have it working, using what I had and the 'loop' you suggested...


    Thanks