Page 1 of 1

Writing to added States

Posted: 28 Jan 2014, 19:01
by poiss89
Hi,

I've encountered a problem that seems very simple, though I can't seem to peg the cause.

I wish to save data from the Control Signals (and also the processed channels), so I've added to my batch a file the commands:

ADD STATE ControlSignalX 12 0;
ADD STATE ControlSignalY 12 0;

After which the new states appear in the Operator's listing of states, and I subsequently check the states in the Preflight stage of CursorFeedbackTask (my applicaiton of choice).

During the Process stage of CursorFeedbackTask, I am writing (or attempting) to my new states using the commands:

State( "ControlSignalX" ) = static_cast<int>(mCursorSpeedX * ControlSignal(0, 0));
State( "ControlSignalY" ) = static_cast<int>(mCursorSpeedY * ControlSignal(1, 0));

Which seems to be exactly how I should be doing this. However, when I open a data file in Matlab from one of these sessions, all the entries for ControlSignalX and ControlSignalY are "0", which suggests that it never wrote anything besides its initial value, even though the cursor has moved around quite a bit.

Is there anything that I've blatantly missed here?

Re: Writing to added States

Posted: 29 Jan 2014, 13:14
by boulay
I don't know anything about creating states in the shell. That could be the source of your problem and I'd have no idea. Anyway, I noticed a couple things from your code. First, cursorSpeed*controlSignal gives you the cursor change, not its position. If you want the position then you'll have to add the value to the previous position. Second, I don't think the conversion from position to state can be done so easily (see below).

Looking at the latest source code for CursorFeedbackTask.cpp, it seems like it already has the ability to output the cursor position to states. If that does not do what you need, then maybe it will be at least be a good example for you.

Code: Select all

#define CURSOR_POS_BITS "12"
const int cCursorPosBits = ::atoi( CURSOR_POS_BITS );

Code: Select all

float x = mpFeedbackScene->CursorXPosition(),
        y = mpFeedbackScene->CursorYPosition(),
        z = mpFeedbackScene->CursorZPosition();

  if( ControlSignal.Channels() > 0 )
    x += mCursorSpeedX * ControlSignal( 0, 0 );
  if( ControlSignal.Channels() > 1 )
    y += mCursorSpeedY * ControlSignal( 1, 0 );
  if( ControlSignal.Channels() > 2 )
    z += mCursorSpeedZ * ControlSignal( 2, 0 );

  // Restrict cursor movement to the inside of the bounding box:
  float r = mpFeedbackScene->CursorRadius();
  x = max( r, min( 100 - r, x ) ),
  y = max( r, min( 100 - r, y ) ),
  z = max( r, min( 100 - r, z ) );
  mpFeedbackScene->SetCursorPosition( x, y, z );

  const float coordToState = ( ( 1 << cCursorPosBits ) - 1 ) / 100.0;
  State( "CursorPosX" ) = static_cast<int>( x * coordToState );
  State( "CursorPosY" ) = static_cast<int>( y * coordToState );
  State( "CursorPosZ" ) = static_cast<int>( z * coordToState );
-Chad

Re: Writing to added States

Posted: 29 Jan 2014, 14:06
by poiss89
So I added states following the directions specified on this page: http://www.bci2000.org/wiki/index.php/U ... _Scripting

And yes, the incremental change in cursor position, or control signal, is the state I am trying to record. Cursor position is already available as a state in the standard data format. I know that another option would be to back out the change in cursor position from the vector of cursor positions in Matlab, but I'm really more interested in defining other states that I can save and use for data analysis later, with the control signal being the simplest example. Specifically, I'll also be trying to define and record states based on the signal values somewhere within the signal processing pipeline.

Re: Writing to added States

Posted: 29 Jan 2014, 14:59
by boulay
OK that makes more sense.

Once again, I don't know anything about Operator shell scripting. If I were you, I'd probably create the states directly in the module constructor method. You may have a good reason that you can't do that. Actually, please let me know if there is a reason. I'm curious.

To isolate the problem, have you tried writing to your states using a simple const int greater than 0? I'd also suggest using a counter (e.g. increment once per block) and then writing the value of modulus(counter,100) to the state variable. (Sorry, I don't know C++ well enough to know the exact code.)

Assuming that works, and you get non-0 values, that suggests that the problem is in your type casting. You may have to setup a conversion factor that translates the cursor position change into a 12-bit int.

Re: Writing to added States

Posted: 30 Jan 2014, 00:56
by poiss89
I think that somewhere in the documentation on the BCI2000 wiki it states that you have to add states within the batch files before the "publishing" phase of startup, so that's what I did.

Thanks for the suggestion on trying to store alternative values. I am able to write any const values and even 'x' and 'y', which is the cursor position, to the ControlSignal states, however, I am as yet unable to write 'dx' to the new states, where dx = mCursorSpeedX * ControlSignal(0,0)

So it seems that it would be a type-casting issue, however I'm not quite sure what the issue is, since x += dx suggests that 'x' and 'dx' are of the same type. So it would be appropriate, and possible, to type cast both variables in the same way, no?

Re: Writing to added States

Posted: 30 Jan 2014, 09:41
by boulay
I think the suggestion for using the operator shell scripting to create states is when you are not writing your own code, and instead are using other shell commands or other non-BCI2000 software to manipulate state values. In your case, I think you're better off creating the states in the same place as you are manipulating them, i.e., in your module C++ code.

As for the other problem, notice how the code that sets the CursorPosX state first multiplies x by a conversion factor (coordToState) before type casting. I think you'll have to do something similar. I'm not great at thinking about data in binary so I don't know what the conversion factor will be, but perhaps the code to get coordToState will be a useful example. One hint though: you can either set your conversion factor to give you an integer that approximates an intuitive value (e.g. # of pixels moved) or you can set your conversion factor to maximize the resolution of your speed given the number of bits you've assigned (can even be non-linear), but you'll need to know how to transform it back if you plan to report the data.

Re: Writing to added States

Posted: 30 Jan 2014, 15:03
by poiss89
So the issue has ended up being a few things... First, the dx values did need a scaling factor, as they were on the order of one-hundredth to one-tenth and were thus just being rounded to zero when type-casting.

So when I scaled by 1000 I was getting an error "Illegal Value (some very large number) was passed to 12-bit state at address 84". This is because dx can be both positive and negative, with -1 being the highest bit representation in the signed int 16 format. It seems that States doesn't accept negative numbers, because the data gets pulled up in Matlab as a uint 16 (unsigned int 16).