Difference between revisions of "Exporting Data from Matlab to BESA Statistics"
(14 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{BESAInfobox | ||
+ | |title = Module information | ||
+ | |module = BESA Statistics | ||
+ | |version = 1.0 or higher | ||
+ | }} | ||
== Introduction == | == Introduction == | ||
− | This is a short tutorial on how to export MEG data from Matlab in a file format readable by BESA Statistics. For the purpose of this example, MEG data is used, however, the case of EEG data should not be very different. As an example the standard structure generated by FieldTrip after time-lock analysis is used | + | This is a short tutorial on how to export MEG data from Matlab in a file format readable by BESA Statistics. For the purpose of this example, MEG data is used, however, the case of EEG data should not be very different. As an example the standard structure generated by FieldTrip after time-lock analysis is used <tt>ft_timelockanalysis(...)</tt> with the option <tt>cfg.keeptrials = 'yes';</tt>. |
− | < | + | |
− | cfg.keeptrials = 'yes'; | + | |
− | </ | + | |
The structure looks like this: | The structure looks like this: | ||
− | <source lang=" | + | <source lang="dos"> |
+ | |||
timelock_cond1 = | timelock_cond1 = | ||
Line 21: | Line 25: | ||
</source> | </source> | ||
− | The matrix <tt> | + | The matrix <tt>avg</tt> contains the averaged data for the current condition and the matrix <tt>trial</tt> contains the single trial data. In this case there are 100 trials, the data contains 147 channels (this is a 148 channels BTI system but 1 channel was defined as bad) and 475 time samples. An important substructure is <tt>grad</tt>, it contains the positions of the MEG channels. |
+ | In order to be able to follow the steps in this tutorial you need to download the scripts for exporting data from Matlab to BESA (MATLAB2BESA) [https://github.com/BESA-GmbH/BESA-MATLAB-Scripts/releases/latest/download/MATLAB2BESA.zip here]. | ||
+ | |||
+ | == Exporting procedure == | ||
+ | Let us assume that we already have the data for one subject and two conditions (cond1 and cond2) in these two structures:<tt>timelock_cond1</tt> and <tt>timelock_cond2</tt>. | ||
+ | |||
+ | === Exporting single trial data as ascii-vectorized files (.avr) === | ||
+ | For the export of the single trial data in an <tt>.avr</tt>-file format we need the function <tt>besa_save2Avr(...)</tt> which is contained in the <tt>zip</tt>-file mentioned above. | ||
+ | |||
+ | '''Matlab code:''' | ||
+ | <source lang="matlab"> | ||
+ | %% Export single trial data for condition 1 | ||
+ | |||
+ | NumChannels = size(timelock_cond1.avg, 1); | ||
+ | NumTrials = size(timelock_cond1.trial, 1); | ||
+ | |||
+ | % the output directory | ||
+ | custom_path = 'D:\Data\C1'; | ||
+ | % Multiply by 1000 to get the time in milliseconds. | ||
+ | time_samples = timelock_cond1.time.*1000; | ||
+ | channel_labels = timelock_cond1.label; | ||
+ | data_scale_factor = 1.0; | ||
+ | time_scale_factor = 1.0; | ||
+ | |||
+ | for iTr = 1:NumTrials | ||
+ | |||
+ | % The file name where data should be written. | ||
+ | file_name = ['Condition1Trial' num2str(iTr) '.avr']; | ||
+ | % Multiply by 1e15 to get the data in femtoTesla. | ||
+ | data_matrix = squeeze(timelock_cond1.trial(iTr, :, :)).*1e15; | ||
+ | |||
+ | % Save the data | ||
+ | besa_save2Avr(custom_path, file_name, data_matrix, time_samples, ... | ||
+ | channel_labels, data_scale_factor, time_scale_factor); | ||
+ | |||
+ | end | ||
+ | |||
+ | %% Export single trial data for condition 2 | ||
+ | |||
+ | NumTrials = size(timelock_cond2.trial, 1); | ||
+ | |||
+ | % the output directory | ||
+ | custom_path = 'D:\Data\C2'; | ||
+ | % Multiply by 1000 to get the time in milliseconds. | ||
+ | time_samples = timelock_cond2.time.*1000; | ||
+ | channel_labels = timelock_cond2.label; | ||
+ | data_scale_factor = 1.0; | ||
+ | time_scale_factor = 1.0; | ||
+ | |||
+ | for iTr = 1:NumTrials | ||
+ | |||
+ | % The file name where data should be written. | ||
+ | file_name = ['Condition2Trial' num2str(iTr) '.avr']; | ||
+ | % Multiply by 1e15 to get the data in femtoTesla. | ||
+ | data_matrix = squeeze(timelock_cond2.trial(iTr, :, :)).*1e15; | ||
+ | |||
+ | % Save the data | ||
+ | besa_save2Avr(custom_path, file_name, data_matrix, time_samples, ... | ||
+ | channel_labels, data_scale_factor, time_scale_factor); | ||
+ | |||
+ | end | ||
+ | </source> | ||
+ | Please note that it is also possible to use the function <tt>besa_matrix2Gen(...)</tt> to save the data in a binary format instead of ASCII-format and thus obtain a better precision; however, you are going to be able to load this data only in BESA Statistics 2.0 and not in version 1.0. | ||
+ | === Rearrange the channel positions === | ||
+ | Sometimes it can happen that the order of the channels in the main structure (e.g. <tt>timelock_cond1.avg</tt>, <tt>timelock_cond1.label</tt>, <tt>timelock_cond1.trial</tt> etc) is different compared to the order of the channels in the <tt>grad</tt>-substructure (e.g. <tt>timelock_cond1.grad.chanpos</tt>, <tt>timelock_cond1.grad.label</tt> etc). In this case we have to rearrange the channel positions in the <tt>grad</tt>-substructure to have the same order as in the main structure. | ||
+ | |||
+ | '''Matlab code:''' | ||
+ | <source lang="matlab"> | ||
+ | %% Rearrange channels in grad | ||
+ | |||
+ | SortedCoordinates = zeros(NumChannels, 3); | ||
+ | |||
+ | NumBadChannels = 1; % A106 | ||
+ | |||
+ | for iCh1 = 1:NumChannels | ||
+ | |||
+ | CurrLabel1 = timelock_cond1.label{iCh1}; | ||
+ | |||
+ | for iCh2 = 1:NumChannels+NumBadChannels | ||
+ | |||
+ | CurrLabel2 = timelock_cond1.grad.label{iCh2}; | ||
+ | |||
+ | if(strcmp(CurrLabel1, CurrLabel2)) | ||
+ | |||
+ | SortedCoordinates(iCh1, :) = timelock_cond1.grad.chanpos(iCh2, :); | ||
+ | |||
+ | end | ||
+ | |||
+ | end | ||
+ | |||
+ | end | ||
+ | </source> | ||
+ | === Transform to spherical coordinates === | ||
+ | Since the positions of the channels in the structure <tt>timelock_cond1.grad.chanpos</tt> are given in Cartesian coordinates we have to transform them to spherical coordinates in order to be able to generate the <tt>.elp</tt>-file that is read by BESA Statistics. For this purpose, use the function <tt>besa_transformCartesian2Spherical(...)</tt>. | ||
+ | |||
+ | '''Matlab code:''' | ||
+ | <source lang="matlab"> | ||
+ | %% Transform to spherical coordinates | ||
+ | |||
+ | SphericalCoords = zeros(NumChannels, 3); | ||
+ | |||
+ | % Create a matrix for rotation about the z-axis. | ||
+ | Angle1 = -90; | ||
+ | rotate1 = [cosd(Angle1) -sind(Angle1) 0; sind(Angle1) cosd(Angle1) 0; 0 0 1]; | ||
+ | |||
+ | % Perform rotation. | ||
+ | RotatedPositions = SortedCoordinates*rotate1; | ||
+ | |||
+ | for iCh = 1:NumChannels | ||
+ | |||
+ | % Get the current coordinates and normalize the radius to 1.0. | ||
+ | CurrCartesianCoords = RotatedPositions(iCh, :) / ... | ||
+ | sqrt(sum(RotatedPositions(iCh, :).^2)); | ||
+ | % Perform the transformation from Cartesian to spherical coordinates. | ||
+ | [azimuth, elevation, r] = besa_transformCartesian2Spherical( ... | ||
+ | CurrCartesianCoords(1), CurrCartesianCoords(2), ... | ||
+ | CurrCartesianCoords(3)); | ||
+ | % Assign the transform values to the output matrix. | ||
+ | SphericalCoords(iCh, 1) = azimuth; | ||
+ | SphericalCoords(iCh, 2) = elevation; | ||
+ | SphericalCoords(iCh, 3) = r; | ||
+ | |||
+ | end | ||
+ | </source> | ||
+ | === Export the elp-file === | ||
+ | After the Cartesian coordinates were transformed to spherical we are ready to save the new coordinates in an <tt>elp</tt>-file. For that we need the function <tt>besa_save2Elp(...)</tt>. | ||
+ | |||
+ | '''Matlab code:''' | ||
+ | <source lang="matlab"> | ||
+ | %% Export elp-file | ||
+ | |||
+ | % the output directory | ||
+ | custom_path = 'D:\Data'; | ||
+ | % The file name where data should be written. | ||
+ | file_name = 'Subject1.elp'; | ||
+ | % The type of the channels to be stored. | ||
+ | channel_type = 'MEG'; | ||
+ | |||
+ | status = besa_save2Elp(custom_path, file_name, ... | ||
+ | SphericalCoords, channel_labels, channel_type); | ||
+ | </source> | ||
+ | In order to make sure that BESA Statistics finds the <tt>elp</tt>-file, please copy it into one of the two data folders (here <tt>D:\Data\C1</tt> or <tt>D:\Data\C2</tt>). | ||
+ | |||
+ | [[Category:Statistics]] [[Category:Data Import/Export]] |
Latest revision as of 11:58, 27 August 2021
Module information | |
Modules | BESA Statistics |
Version | 1.0 or higher |
Contents
Introduction
This is a short tutorial on how to export MEG data from Matlab in a file format readable by BESA Statistics. For the purpose of this example, MEG data is used, however, the case of EEG data should not be very different. As an example the standard structure generated by FieldTrip after time-lock analysis is used ft_timelockanalysis(...) with the option cfg.keeptrials = 'yes';.
The structure looks like this:
timelock_cond1 = avg: [147x475 double] var: [147x475 double] time: [1x475 double] dof: [147x475 double] label: {147x1 cell} trial: [100x147x475 double] dimord: 'rpt_chan_time' grad: [1x1 struct] trialinfo: [100x1 double] cfg: [1x1 struct]
The matrix avg contains the averaged data for the current condition and the matrix trial contains the single trial data. In this case there are 100 trials, the data contains 147 channels (this is a 148 channels BTI system but 1 channel was defined as bad) and 475 time samples. An important substructure is grad, it contains the positions of the MEG channels. In order to be able to follow the steps in this tutorial you need to download the scripts for exporting data from Matlab to BESA (MATLAB2BESA) here.
Exporting procedure
Let us assume that we already have the data for one subject and two conditions (cond1 and cond2) in these two structures:timelock_cond1 and timelock_cond2.
Exporting single trial data as ascii-vectorized files (.avr)
For the export of the single trial data in an .avr-file format we need the function besa_save2Avr(...) which is contained in the zip-file mentioned above.
Matlab code:
%% Export single trial data for condition 1 NumChannels = size(timelock_cond1.avg, 1); NumTrials = size(timelock_cond1.trial, 1); % the output directory custom_path = 'D:\Data\C1'; % Multiply by 1000 to get the time in milliseconds. time_samples = timelock_cond1.time.*1000; channel_labels = timelock_cond1.label; data_scale_factor = 1.0; time_scale_factor = 1.0; for iTr = 1:NumTrials % The file name where data should be written. file_name = ['Condition1Trial' num2str(iTr) '.avr']; % Multiply by 1e15 to get the data in femtoTesla. data_matrix = squeeze(timelock_cond1.trial(iTr, :, :)).*1e15; % Save the data besa_save2Avr(custom_path, file_name, data_matrix, time_samples, ... channel_labels, data_scale_factor, time_scale_factor); end %% Export single trial data for condition 2 NumTrials = size(timelock_cond2.trial, 1); % the output directory custom_path = 'D:\Data\C2'; % Multiply by 1000 to get the time in milliseconds. time_samples = timelock_cond2.time.*1000; channel_labels = timelock_cond2.label; data_scale_factor = 1.0; time_scale_factor = 1.0; for iTr = 1:NumTrials % The file name where data should be written. file_name = ['Condition2Trial' num2str(iTr) '.avr']; % Multiply by 1e15 to get the data in femtoTesla. data_matrix = squeeze(timelock_cond2.trial(iTr, :, :)).*1e15; % Save the data besa_save2Avr(custom_path, file_name, data_matrix, time_samples, ... channel_labels, data_scale_factor, time_scale_factor); end
Please note that it is also possible to use the function besa_matrix2Gen(...) to save the data in a binary format instead of ASCII-format and thus obtain a better precision; however, you are going to be able to load this data only in BESA Statistics 2.0 and not in version 1.0.
Rearrange the channel positions
Sometimes it can happen that the order of the channels in the main structure (e.g. timelock_cond1.avg, timelock_cond1.label, timelock_cond1.trial etc) is different compared to the order of the channels in the grad-substructure (e.g. timelock_cond1.grad.chanpos, timelock_cond1.grad.label etc). In this case we have to rearrange the channel positions in the grad-substructure to have the same order as in the main structure.
Matlab code:
%% Rearrange channels in grad SortedCoordinates = zeros(NumChannels, 3); NumBadChannels = 1; % A106 for iCh1 = 1:NumChannels CurrLabel1 = timelock_cond1.label{iCh1}; for iCh2 = 1:NumChannels+NumBadChannels CurrLabel2 = timelock_cond1.grad.label{iCh2}; if(strcmp(CurrLabel1, CurrLabel2)) SortedCoordinates(iCh1, :) = timelock_cond1.grad.chanpos(iCh2, :); end end end
Transform to spherical coordinates
Since the positions of the channels in the structure timelock_cond1.grad.chanpos are given in Cartesian coordinates we have to transform them to spherical coordinates in order to be able to generate the .elp-file that is read by BESA Statistics. For this purpose, use the function besa_transformCartesian2Spherical(...).
Matlab code:
%% Transform to spherical coordinates SphericalCoords = zeros(NumChannels, 3); % Create a matrix for rotation about the z-axis. Angle1 = -90; rotate1 = [cosd(Angle1) -sind(Angle1) 0; sind(Angle1) cosd(Angle1) 0; 0 0 1]; % Perform rotation. RotatedPositions = SortedCoordinates*rotate1; for iCh = 1:NumChannels % Get the current coordinates and normalize the radius to 1.0. CurrCartesianCoords = RotatedPositions(iCh, :) / ... sqrt(sum(RotatedPositions(iCh, :).^2)); % Perform the transformation from Cartesian to spherical coordinates. [azimuth, elevation, r] = besa_transformCartesian2Spherical( ... CurrCartesianCoords(1), CurrCartesianCoords(2), ... CurrCartesianCoords(3)); % Assign the transform values to the output matrix. SphericalCoords(iCh, 1) = azimuth; SphericalCoords(iCh, 2) = elevation; SphericalCoords(iCh, 3) = r; end
Export the elp-file
After the Cartesian coordinates were transformed to spherical we are ready to save the new coordinates in an elp-file. For that we need the function besa_save2Elp(...).
Matlab code:
%% Export elp-file % the output directory custom_path = 'D:\Data'; % The file name where data should be written. file_name = 'Subject1.elp'; % The type of the channels to be stored. channel_type = 'MEG'; status = besa_save2Elp(custom_path, file_name, ... SphericalCoords, channel_labels, channel_type);
In order to make sure that BESA Statistics finds the elp-file, please copy it into one of the two data folders (here D:\Data\C1 or D:\Data\C2).