Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asynchronous sample/chunk aquisistion #14

Open
xfleckx opened this issue Jan 5, 2017 · 2 comments
Open

Asynchronous sample/chunk aquisistion #14

xfleckx opened this issue Jan 5, 2017 · 2 comments
Assignees

Comments

@xfleckx
Copy link
Collaborator

xfleckx commented Jan 5, 2017

Problem:

I can never get out of the while ((lastTimeStamp = inlet.pull_sample(sample, 0.0f)) != 0) loop because I'm Processing the samples slower than they are coming in.

Solution A: do not push sample processing logic into Unity - heavy data post-processing could be done in more efficient environments due to data processing - e.g. matlab\Julia\Python ❓ This might result in feature streams with lower frequencies (30 - 100Hz) which could be comfortable processed by Update rates of 30/60/90 Hz of a game loop.

Soultion B: Using a thread based wrapper for a LSL inlet.

void Start(){
     // contains all the thread logic
     mySampleAquisitionJob = new FloatSampleAquisition(streamInlet);
     mySampleAquisitionJob.Start(); //start the thread and try pulling
}

void Update(){
    if(mySampleAquisitionJob.HasData){
        // this takes care of thread locking etc.
        float[] data = mySampleAquisitionJob.GetData();
        // data got copied in the unity main thread 
    }
}
@cboulay
Copy link
Collaborator

cboulay commented Jan 5, 2017

I do all my signal processing in Python (mostly using NeuroPype). It streams the result out via a 'type="Control"' Outlet. These streams are always between 10 and 80 Hz.

I was able to escape the while loop by commenting out my line in Process that printed the value via Debug.Log. I guess Debug.Log is too slow to be called multiple times in each game tick.

I've since modified my Process function to simply take the value and store it as a member variable and toggle a hasNewData switch. Then at the end of Update (i.e., after pullSamples()), if (hasNewData) {do something with lastSample;}.

I don't know if you've ever encountered this, but sometimes when I start up a program that gets an LSL Inlet, it seems to get lots of data really quickly at the beginning, much faster than it is being sent out via the outlet, then eventually it catches up and the inlet data rate matches the outlet data rate. I assume this has something to do with LSL's data buffering and my application's new inlet assuming the role of a recently-destroyed inlet and picking up all the data since the last inlet was destroyed.

@xfleckx
Copy link
Collaborator Author

xfleckx commented Jan 5, 2017

to this:

I was able to escape the while loop by commenting out my line in Process that printed the value via Debug.Log. I guess Debug.Log is too slow to be called multiple times in each game tick.

Instead of using the Debug.Log, I would suggest to use an custom inspector with a value field showing the latest value of your stream within the inspector of your components.
Code looks like this:

public class YourScript : MonoBehaviour{
	
	[HideInspector] // to get a read only field
	public float latestLSLSample = 0f;

	void Update(){
                // Update the value from your lsl values.... 
		latestSample = GetTheLSLValue();
	}
}

[CustomInspector(typeof(YourScript))]
public class InspectorForYourScript : Editor{
	
	public override OnInspectorGUI()
	{
		var yourScript = target as YourScript;

		// Show the default Inspector
		base.OnInspectorGUI();

		// shows the hidden property as a read only field
		EditorGUILayout.FloatField(yourScript.latestValue, "Latest Value from LSL");
	}

}

this seems to be more efficient than a debug log call.
For the future, I'm planning to provide a little chart implementation which can be used within the Editor and the Game logic for visualisation purpose.

But this solves the issue just for the case, you got this issue whenever you got a bit more processing logic - which takes also a bit more.

The second issue:

it seems to get lots of data really quickly at the beginning, much faster than it is being sent out via the outlet, then eventually it catches up and the inlet data rate matches the outlet data rate

Naive solution: I would pull all samples at the start of the application and throw them away since we don't want to record something.

Interesting phenomena, actually intended, I guess their should be an option for that.... I will take a look. I thought their was a config file for LSL which could be used to define things like how much data should be cached...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants