I'm not entirely sure what you're asking for because your question
title mentions control but your question body seems to all be about display. You said,
My Question is, How can we implement in MATLAB/C++? So I can store 250 data of sensors as well as 60 points for real time display on the TV.
If you want to store samples for display at some particular interval, try the following:
sensorPeriod = 1/250;
displayPeriod = 1/60;
displayInterval = floor (displayPeriod/sensorPeriod);
sensorData = <read sensor>
sensorHistory(end+1) = sensorData;
displayData = sensorHistory(1:displayInterval:end);
You can use any integer to select indices of an array in Matlab. The value is optional and if you don't specify it then it defaults to 1. So, for instance, where
displayData = data(1:end);
would put every data point into displayData
, the following:
displayData = data(1:N:end);
would take every Nth point and put that into displayData
. Dividing display period by the sample period gives the number of samples that occur between each displayed frame. Take the floor of that to get an integer because Matlab can only handle integer indexing of arrays.
:EDIT:
As I go through your code, here are things that I notice:
% Display main window using Psychtoolbox
win=Screen(2,'OpenWindow',[1 1 1])
while (1)
% Setup for data collection at 250Hz
Error = calllib('ATC3DG64', 'GetSynchronousRecord', hex2dec('ffff'), pRecord, 4*numBoards*64);
errorHandler(Error);
Record = get(pRecord, 'Value');
This section all appears to look okay, and it appears to me that Record
is the data point you are interested in storing. There is no reference to 'ATC3DG64' or 'pRecord', but there is also no complaint about retrieving data, so I can only assume this works okay. However, I would like to note that the calllib() function accepts arguments inside the parenthesis, not outputs, so I don't see where/how pRecord
ever gets updated.
%sensor number
count=2;
evalc(['tempPos(1, count) =' 'Record.x' num2str(count - 1)]);
evalc(['tempPos(2, count) =' 'Record.y' num2str(count - 1)]);
evalc(['tempPos(3, count) =' 'Record.z' num2str(count - 1)]);
I do not know why you are using evalc to do this. That function evaluates an argument and copies the output to a variable, but you don't make an output assignment. Instead you're just converting everything to a string to make Matlab parse the string, when you could just leave everything off and call the functions directly. Also, your string conversion doesn't leave you with a proper indexing for the Record.x
functions. You wind up calling:
tempPos(1, count) =Record.x 0
when you probably should be calling
tempPos(1, count) =Record.x(0)
If you are using evalc()
to suppress the output, you can always do that with a semicolon at the end of the line. I think you should probably re-write this section of code to the following:
tempPos(1, count) = Record.x(count-1);
tempPos(2, count) = Record.y(count-1);
tempPos(3, count) = Record.z(count-1);
Moving on...
% Record X and Y position of sensor 2
if SensorNumAttached(count)
% Real time position and minus world origin so that real
% time position display on the TV
table1(count,1)=(2.54*tempPos(2,count))-X_world_origin;
table1(count,2)=(2.54*tempPos(3,count))-Y_world_origin;
end
The function SensorNumAttached()
is not a Matlab function, so I don't know what that is checking for. That said, this portion of the code is a little confusing because you switch between indexing the data to the sensor on the columns to indexing on the rows, but otherwise this looks okay.
% Some conversion for the Pixel to centimeter ratio
x_center_new = x_center - (x_ratio * table1(2,1));
y_center_new = y_center - (y_ratio * table1(2,2));
This section of code will not do what you want it to do. This looks like you are trying to update coordinates, but you are combining a relative position with an absolute position. It looks like you are trying to go for:
x_center_new = <old center> + <difference between old center and new center>;
When in actuality you have:
x_center_new = <old center> + <difference between origin and new center>
I may be wrong here, because you never set x_center = x_center_new
, which is either a mistake or it could be that x_center
is some offset information. I don't think this is the case, though, because there is no x_center(count)
, which means you don't have a distinct x_center
for both sensors. Also of note - you don't reference count
in this code at all, so you're updating both sensor displays with only one (#2's) position information. I would suggest you change this code to be:
x_center_new = x_ratio * table(count,1);
y_center_new = y_ratio * table(count,2);
Moving on. . .
% conversion for display circle on the TV, is represent the real time position of the sensor
x1 =round(x_center_new - R_num_data);
y1 = round(y_center_new - R_num_data);
x2 = round(x1 + 2*R_num_data);
y2 = round(y1 + 2*R_num_data);
% Display command for TV.
Screen('FrameOval',win,[255 0 0], [x1 y1 x2 y2]);
Screen('Flip',win);
end
For this section, Screen
is also not a Matlab function, so I'm not sure what it does, and R_num_data
is not defined in the code snippet you provided, so I don't know what that does, either. I would like to reiterate that, by your code, the display here never showed anything for sensor 1 because your x_center_new
used a hard-coded '2' instead of 'count'.
Regarding display, there are two ways that you can go about showing data:
- Collect the data in real time, then show the video after the fact.
- Collect the data and display in real time.
If you attempt to display in real time, Matlab rendering will almost certainly hamper your data collection as I've found it seems to be generally about 100ms for Matlab to draw a basic scene. Also, if you collect data and display in real time with no bounds on time, you can't pre-allocate the memory for data storage, which can cause the program to run slower. That said, here's some sample code you can throw into your script for display:
Method 1
nSensors = 2; % Number of sensors
nOutputs = 3; % How many outputs each sensor gives you
sampleDuration = 1; % Sample time in [s]
samplePeriod = 1/250; % Sampling period in [s]
displayPeriod = 1/60; % Display period in [s]
nDataPoints = floor(sampleDuration/samplePeriod);
sensorData = zeros(nOutputs,nSensors,nDataPoints);
count = 2; % Whatever method you want to select the sensor
for i = 1:nDataPoints
<whatever method you need to get the data>
Record = get(pRecord, 'Value');
sensorData(1,count,i) = Record.x(count-1);
sensorData(2,count,i) = Record.y(count-1);
sensorData(3,count,i) = Record.z(count-1);
<any other things you want to do with the data>
end
sampleInterval = floor(displayFreq/sampleFreq);
displayData = nDataPoints(:,:,1:sampleInterval:end);
for i = 1:size(displayData,3)
<display 'displayData(:,:,i)'>
end
Method 2
nSensors = 2; % Number of sensors
nOutputs = 3; % How many outputs each sensor gives you
samplePeriod = 1/250; % Sampling period in [s]
displayPeriod = 1/60; % Display period in [s]
sensorData = zeros(nOutputs,nSensors,0);
displayData = zeros(nOutputs,nSensors,0);
frameAdjustment = 0;
tic; % Start a timer
while 1
<whatever method you need to get the data>
Record = get(pRecord, 'Value');
sensorData(1,count,end+1) = Record.x(count-1);
sensorData(2,count,end+1) = Record.y(count-1);
sensorData(3,count,end+1) = Record.z(count-1);
elapsedTime = toc;
if elapsedTime + frameAdjustment > displayPeriod
frameAdjustment = elapsedTime - displayPeriod;
tic;
displayData(:,:,end+1) = nDataPoints(:,:,end);
<display 'displayData(:,:,end)'>
end
end
Note in the above code that there is a variable, frameAdjustment
. This term can account for the fact that your elapsedTime probably isn't going to sync exactly with your desired frame rate. It remembers how much time you were past the desired display call and calls the next display that much sooner. If the time it takes to display your data is longer than your displayPeriod
then you'll wind up displaying every loop iteration. As mentioned earlier, this could mean that you don't build your sensorData
history at the correct rate.
It looks like maybe the Screen
command could let you bypass the time it takes for Matlab to draw a scene, but I haven't used any third-party Matlab tools so I can't comment on it. Your best bet would be to gather the data first and then display it, but as the designer, it's always up to you.