readlocs() - read electrode location coordinates and other information from a file. Several standard file formats are supported. Users may also specify a custom column format. Defined format examples are given below (see File Formats). Usage: >> eloc = readlocs( filename ); >> EEG.chanlocs = readlocs( filename, 'key', 'val', ... ); >> [eloc, labels, theta, radius, indices] = ... readlocs( filename, 'key', 'val', ... ); Inputs: filename - Name of the file containing the electrode locations {default: 2-D polar coordinates} (see >> help topoplot ) Optional inputs: 'filetype' - ['loc'|'sph'|'sfp'|'xyz'|'asc'|'polhemus'|'besa'|'chanedit'|'custom'] Type of the file to read. By default the file type is determined using the file extension (see below under File Formats): 'loc' - an EEGLAB 2-D polar coordinates channel locations file Coordinates are theta and radius (see definitions below). 'sph' - Matlab spherical coordinates (Note: spherical coordinates used by Matlab functions are different from spherical coordinates used by BESA - see below). 'sfp' - EGI Cartesian coordinates (NOT Matlab Cartesian - see below). 'xyz' - Matlab/EEGLAB Cartesian coordinates (NOT EGI Cartesian). z is toward nose; y is toward left ear; z is toward vertex 'asc' - Neuroscan polar coordinates. 'polhemus' or 'polhemusx' - Polhemus electrode location file recorded with 'X' on sensor pointing to subject (see below and readelp()). 'polhemusy' - Polhemus electrode location file recorded with 'Y' on sensor pointing to subject (see below and readelp()). 'besa' - BESA-'.elp' spherical coordinates. (Not MATLAB spherical - see below). 'chanedit' - EEGLAB channel location file created by pop_chanedit(). 'custom' - Ascii file with columns in user-defined 'format' (see below). 'importmode' - ['eeglab'|'native'] for location files containing 3-D cartesian electrode coordinates, import either in EEGLAB format (nose pointing toward +X). This may not always be possible since EEGLAB might not be able to determine the nose direction for scanned electrode files. 'native' import original carthesian coordinates (user can then specify the position of the nose when calling the topoplot() function; in EEGLAB the position of the nose is stored in the EEG.chaninfo structure). {default 'eeglab'} 'format' - [cell array] Format of a 'custom' channel location file (see above). {default: if no file type is defined. The cell array contains labels defining the meaning of each column of the input file: 'channum' [positive integer] channel number 'labels' [string] channel name (no spaces) 'theta' [real degrees] 2-D angle in polar coordinates; positive = rotating from nose (0) toward left ear 'radius' [real] radius for 2-D polar coords; 0.5 is the head disk radius and limit for topoplot() plotting) 'X' [real] Matlab-Cartesian X coordinate (to nose) 'Y' [real] Matlab-Cartesian Y coordinate (to left ear) 'Z' [real] Matlab-Cartesian Z coordinate (to vertex) '-X','-Y','-Z' Matlab-Cartesian coordinates pointing opposite to the above. 'sph_theta' [real degrees] Matlab spherical horizontal angle; positive = rotating from nose (0) toward left ear. 'sph_phi' [real degrees] Matlab spherical elevation angle; positive = rotating from horizontal (0) upwards. 'sph_radius' [real] distance from head center (unused) 'sph_phi_besa' [real degrees] BESA phi angle from vertical; positive = rotating from vertex (0) towards right ear. 'sph_theta_besa' [real degrees] BESA theta horiz/azimuthal angle; positive = rotating from right ear (0) toward nose. 'ignore' ignore column} The input file may also contain other channel information fields 'type' channel type: 'EEG', 'MEG', 'EMG', 'ECG', others ... 'calib' [real near 1.0] channel calibration value. 'gain' [real > 1] channel gain. 'custom1' custom field #1. 'custom2', 'custom3', 'custom4', etc. more custom fields 'skiplines' - [integer] Number of header lines to skip (in 'custom' file types only). Note: Characters on a line following '%' will be treated as comments. 'readchans' - [integer array] indices of electrodes to read. {default: all} 'center' - [(1,3) real array or 'auto'] center of xyz coordinates for conversion to spherical or polar, Specify the center of the sphere here, or 'auto'. This uses the center of the sphere that best fits all the electrode locations read. {default: [0 0 0]} Outputs: eloc - structure containing the channel names and locations (if present). It has three fields: 'eloc.labels', 'eloc.theta' and 'eloc.radius' identical in meaning to the EEGLAB struct 'EEG.chanlocs'. labels - cell array of strings giving the names of the electrodes. NOTE: Unlike the three outputs below, includes labels of channels *without* location info. theta - vector (in degrees) of polar angles of the electrode locations. radius - vector of polar-coordinate radii (arc_lengths) of the electrode locations indices - indices, k, of channels with non-empty 'locs(k).theta' coordinate File formats: If 'filetype' is unspecified, the file extension determines its type. '.loc' or '.locs' or '.eloc': polar coordinates. Notes: angles in degrees: right ear is 90; left ear -90; head disk radius is 0.5. Fields: N angle radius label Sample: 1 -18 .511 Fp1 2 18 .511 Fp2 3 -90 .256 C3 4 90 .256 C4 ... Note: In previous releases, channel labels had to contain exactly four characters (spaces replaced by '.'). This format still works, though dots are no longer required. '.sph': Matlab spherical coordinates. Notes: theta is the azimuthal/horizontal angle in deg.: 0 is toward nose, 90 rotated to left ear. Following this, performs the elevation (phi). Angles in degrees. Fields: N theta phi label Sample: 1 18 -2 Fp1 2 -18 -2 Fp2 3 90 44 C3 4 -90 44 C4 ... '.elc': Cartesian 3-D electrode coordinates scanned using the EETrak software. See readeetraklocs(). '.elp': Polhemus-.'elp' Cartesian coordinates. By default, an .elp extension is read as PolhemusX-elp in which 'X' on the Polhemus sensor is pointed toward the subject. Polhemus files are not in columnar format (see readelp()). '.elp': BESA-'.elp' spherical coordinates: Need to specify 'filetype','besa'. The elevation angle (phi) is measured from the vertical axis. Positive rotation is toward right ear. Next, perform azimuthal/horizontal rotation (theta): 0 is toward right ear; 90 is toward nose, -90 toward occiput. Angles are in degrees. If labels are absent or weights are given in a last column, readlocs() adjusts for this. Default labels are E1, E2, ... Fields: label phi theta Sample: Fp1 -92 -72 Fp2 92 72 C3 -46 0 C4 46 0 ... '.xyz': Matlab/EEGLAB Cartesian coordinates. Here. x is towards the nose, y is towards the left ear, and z towards the vertex. Fields: channum x y z label Sample: 1 .950 .308 -.035 Fp1 2 .950 -.308 -.035 Fp2 3 0 .719 .695 C3 4 0 -.719 .695 C4 ... '.asc', '.dat': Neuroscan-.'asc' or '.dat' Cartesian polar coordinates text file. '.sfp': BESA/EGI-xyz Cartesian coordinates. Notes: For EGI, x is toward right ear, y is toward the nose, z is toward the vertex. EEGLAB converts EGI Cartesian coordinates to Matlab/EEGLAB xyz coordinates. Fields: label x y z Sample: Fp1 -.308 .950 -.035 Fp2 .308 .950 -.035 C3 -.719 0 .695 C4 .719 0 .695 ... '.ced': ASCII file saved by pop_chanedit(). Contains multiple MATLAB/EEGLAB formats. Cartesian coordinates are as in the 'xyz' format (above). Fields: channum label theta radius x y z sph_theta sph_phi ... Sample: 1 Fp1 -18 .511 .950 .308 -.035 18 -2 ... 2 Fp2 18 .511 .950 -.308 -.035 -18 -2 ... 3 C3 -90 .256 0 .719 .695 90 44 ... 4 C4 90 .256 0 -.719 .695 -90 44 ... ... The last columns of the file may contain any other defined fields (gain, calib, type, custom). Author: Arnaud Delorme, Salk Institute, 8 Dec 2002 (expanded from the previous EEG/ICA toolbox function) See also: readelp(), writelocs(), topo2sph(), sph2topo(), sph2cart()
0001 % readlocs() - read electrode location coordinates and other information from a file. 0002 % Several standard file formats are supported. Users may also specify 0003 % a custom column format. Defined format examples are given below 0004 % (see File Formats). 0005 % Usage: 0006 % >> eloc = readlocs( filename ); 0007 % >> EEG.chanlocs = readlocs( filename, 'key', 'val', ... ); 0008 % >> [eloc, labels, theta, radius, indices] = ... 0009 % readlocs( filename, 'key', 'val', ... ); 0010 % Inputs: 0011 % filename - Name of the file containing the electrode locations 0012 % {default: 2-D polar coordinates} (see >> help topoplot ) 0013 % 0014 % Optional inputs: 0015 % 'filetype' - ['loc'|'sph'|'sfp'|'xyz'|'asc'|'polhemus'|'besa'|'chanedit'|'custom'] 0016 % Type of the file to read. By default the file type is determined 0017 % using the file extension (see below under File Formats): 0018 % 'loc' - an EEGLAB 2-D polar coordinates channel locations file 0019 % Coordinates are theta and radius (see definitions below). 0020 % 'sph' - Matlab spherical coordinates (Note: spherical 0021 % coordinates used by Matlab functions are different 0022 % from spherical coordinates used by BESA - see below). 0023 % 'sfp' - EGI Cartesian coordinates (NOT Matlab Cartesian - see below). 0024 % 'xyz' - Matlab/EEGLAB Cartesian coordinates (NOT EGI Cartesian). 0025 % z is toward nose; y is toward left ear; z is toward vertex 0026 % 'asc' - Neuroscan polar coordinates. 0027 % 'polhemus' or 'polhemusx' - Polhemus electrode location file recorded 0028 % with 'X' on sensor pointing to subject (see below and readelp()). 0029 % 'polhemusy' - Polhemus electrode location file recorded with 0030 % 'Y' on sensor pointing to subject (see below and readelp()). 0031 % 'besa' - BESA-'.elp' spherical coordinates. (Not MATLAB spherical - 0032 % see below). 0033 % 'chanedit' - EEGLAB channel location file created by pop_chanedit(). 0034 % 'custom' - Ascii file with columns in user-defined 'format' (see below). 0035 % 'importmode' - ['eeglab'|'native'] for location files containing 3-D cartesian electrode 0036 % coordinates, import either in EEGLAB format (nose pointing toward +X). 0037 % This may not always be possible since EEGLAB might not be able to 0038 % determine the nose direction for scanned electrode files. 'native' import 0039 % original carthesian coordinates (user can then specify the position of 0040 % the nose when calling the topoplot() function; in EEGLAB the position 0041 % of the nose is stored in the EEG.chaninfo structure). {default 'eeglab'} 0042 % 'format' - [cell array] Format of a 'custom' channel location file (see above). 0043 % {default: if no file type is defined. The cell array contains 0044 % labels defining the meaning of each column of the input file: 0045 % 'channum' [positive integer] channel number 0046 % 'labels' [string] channel name (no spaces) 0047 % 'theta' [real degrees] 2-D angle in polar coordinates; 0048 % positive = rotating from nose (0) toward left ear 0049 % 'radius' [real] radius for 2-D polar coords; 0.5 is the head 0050 % disk radius and limit for topoplot() plotting) 0051 % 'X' [real] Matlab-Cartesian X coordinate (to nose) 0052 % 'Y' [real] Matlab-Cartesian Y coordinate (to left ear) 0053 % 'Z' [real] Matlab-Cartesian Z coordinate (to vertex) 0054 % '-X','-Y','-Z' Matlab-Cartesian coordinates pointing opposite 0055 % to the above. 0056 % 'sph_theta' [real degrees] Matlab spherical horizontal angle; 0057 % positive = rotating from nose (0) toward left ear. 0058 % 'sph_phi' [real degrees] Matlab spherical elevation angle; 0059 % positive = rotating from horizontal (0) upwards. 0060 % 'sph_radius' [real] distance from head center (unused) 0061 % 'sph_phi_besa' [real degrees] BESA phi angle from vertical; 0062 % positive = rotating from vertex (0) towards right ear. 0063 % 'sph_theta_besa' [real degrees] BESA theta horiz/azimuthal angle; 0064 % positive = rotating from right ear (0) toward nose. 0065 % 'ignore' ignore column} 0066 % The input file may also contain other channel information fields 0067 % 'type' channel type: 'EEG', 'MEG', 'EMG', 'ECG', others ... 0068 % 'calib' [real near 1.0] channel calibration value. 0069 % 'gain' [real > 1] channel gain. 0070 % 'custom1' custom field #1. 0071 % 'custom2', 'custom3', 'custom4', etc. more custom fields 0072 % 'skiplines' - [integer] Number of header lines to skip (in 'custom' file types only). 0073 % Note: Characters on a line following '%' will be treated as comments. 0074 % 'readchans' - [integer array] indices of electrodes to read. {default: all} 0075 % 'center' - [(1,3) real array or 'auto'] center of xyz coordinates for conversion 0076 % to spherical or polar, Specify the center of the sphere here, or 'auto'. 0077 % This uses the center of the sphere that best fits all the electrode 0078 % locations read. {default: [0 0 0]} 0079 % Outputs: 0080 % eloc - structure containing the channel names and locations (if present). 0081 % It has three fields: 'eloc.labels', 'eloc.theta' and 'eloc.radius' 0082 % identical in meaning to the EEGLAB struct 'EEG.chanlocs'. 0083 % labels - cell array of strings giving the names of the electrodes. NOTE: Unlike the 0084 % three outputs below, includes labels of channels *without* location info. 0085 % theta - vector (in degrees) of polar angles of the electrode locations. 0086 % radius - vector of polar-coordinate radii (arc_lengths) of the electrode locations 0087 % indices - indices, k, of channels with non-empty 'locs(k).theta' coordinate 0088 % 0089 % File formats: 0090 % If 'filetype' is unspecified, the file extension determines its type. 0091 % 0092 % '.loc' or '.locs' or '.eloc': 0093 % polar coordinates. Notes: angles in degrees: 0094 % right ear is 90; left ear -90; head disk radius is 0.5. 0095 % Fields: N angle radius label 0096 % Sample: 1 -18 .511 Fp1 0097 % 2 18 .511 Fp2 0098 % 3 -90 .256 C3 0099 % 4 90 .256 C4 0100 % ... 0101 % Note: In previous releases, channel labels had to contain exactly 0102 % four characters (spaces replaced by '.'). This format still works, 0103 % though dots are no longer required. 0104 % '.sph': 0105 % Matlab spherical coordinates. Notes: theta is the azimuthal/horizontal angle 0106 % in deg.: 0 is toward nose, 90 rotated to left ear. Following this, performs 0107 % the elevation (phi). Angles in degrees. 0108 % Fields: N theta phi label 0109 % Sample: 1 18 -2 Fp1 0110 % 2 -18 -2 Fp2 0111 % 3 90 44 C3 0112 % 4 -90 44 C4 0113 % ... 0114 % '.elc': 0115 % Cartesian 3-D electrode coordinates scanned using the EETrak software. 0116 % See readeetraklocs(). 0117 % '.elp': 0118 % Polhemus-.'elp' Cartesian coordinates. By default, an .elp extension is read 0119 % as PolhemusX-elp in which 'X' on the Polhemus sensor is pointed toward the 0120 % subject. Polhemus files are not in columnar format (see readelp()). 0121 % '.elp': 0122 % BESA-'.elp' spherical coordinates: Need to specify 'filetype','besa'. 0123 % The elevation angle (phi) is measured from the vertical axis. Positive 0124 % rotation is toward right ear. Next, perform azimuthal/horizontal rotation 0125 % (theta): 0 is toward right ear; 90 is toward nose, -90 toward occiput. 0126 % Angles are in degrees. If labels are absent or weights are given in 0127 % a last column, readlocs() adjusts for this. Default labels are E1, E2, ... 0128 % Fields: label phi theta 0129 % Sample: Fp1 -92 -72 0130 % Fp2 92 72 0131 % C3 -46 0 0132 % C4 46 0 0133 % ... 0134 % '.xyz': 0135 % Matlab/EEGLAB Cartesian coordinates. Here. x is towards the nose, 0136 % y is towards the left ear, and z towards the vertex. 0137 % Fields: channum x y z label 0138 % Sample: 1 .950 .308 -.035 Fp1 0139 % 2 .950 -.308 -.035 Fp2 0140 % 3 0 .719 .695 C3 0141 % 4 0 -.719 .695 C4 0142 % ... 0143 % '.asc', '.dat': 0144 % Neuroscan-.'asc' or '.dat' Cartesian polar coordinates text file. 0145 % '.sfp': 0146 % BESA/EGI-xyz Cartesian coordinates. Notes: For EGI, x is toward right ear, 0147 % y is toward the nose, z is toward the vertex. EEGLAB converts EGI 0148 % Cartesian coordinates to Matlab/EEGLAB xyz coordinates. 0149 % Fields: label x y z 0150 % Sample: Fp1 -.308 .950 -.035 0151 % Fp2 .308 .950 -.035 0152 % C3 -.719 0 .695 0153 % C4 .719 0 .695 0154 % ... 0155 % '.ced': 0156 % ASCII file saved by pop_chanedit(). Contains multiple MATLAB/EEGLAB formats. 0157 % Cartesian coordinates are as in the 'xyz' format (above). 0158 % Fields: channum label theta radius x y z sph_theta sph_phi ... 0159 % Sample: 1 Fp1 -18 .511 .950 .308 -.035 18 -2 ... 0160 % 2 Fp2 18 .511 .950 -.308 -.035 -18 -2 ... 0161 % 3 C3 -90 .256 0 .719 .695 90 44 ... 0162 % 4 C4 90 .256 0 -.719 .695 -90 44 ... 0163 % ... 0164 % The last columns of the file may contain any other defined fields (gain, 0165 % calib, type, custom). 0166 % 0167 % Author: Arnaud Delorme, Salk Institute, 8 Dec 2002 (expanded from the previous EEG/ICA 0168 % toolbox function) 0169 % 0170 % See also: readelp(), writelocs(), topo2sph(), sph2topo(), sph2cart() 0171 0172 %123456789012345678901234567890123456789012345678901234567890123456789012 0173 0174 % Copyright (C) Arnaud Delorme, CNL / Salk Institute, 28 Feb 2002 0175 % 0176 % This program is free software; you can redistribute it and/or modify 0177 % it under the terms of the GNU General Public License as published by 0178 % the Free Software Foundation; either version 2 of the License, or 0179 % (at your option) any later version. 0180 % 0181 % This program is distributed in the hope that it will be useful, 0182 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0183 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0184 % GNU General Public License for more details. 0185 % 0186 % You should have received a copy of the GNU General Public License 0187 % along with this program; if not, write to the Free Software 0188 % Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0189 0190 % $Log: readlocs.m,v $ 0191 % Revision 1.87 2006/06/01 17:40:50 arno 0192 % updating header 0193 % 0194 % Revision 1.86 2006/05/26 15:59:35 scott 0195 % worked on text of instructions for adding a channel type -- NOTE: chaninfo is 0196 % discussed in help message, but NOT implemented!? 0197 % 0198 % Revision 1.85 2006/04/14 21:19:08 arno 0199 % fixing skipping lines 0200 % 0201 % Revision 1.84 2006/03/31 03:11:13 toby 0202 % made '.eloc' equivalent to '.loc' as a filetype 0203 % 0204 % Revision 1.83 2006/02/14 00:01:18 arno 0205 % change xyz format 0206 % 0207 % Revision 1.82 2006/01/20 22:37:08 arno 0208 % default for BESA and polhemus 0209 % 0210 % Revision 1.81 2006/01/12 23:22:39 arno 0211 % fixing indices 0212 % 0213 % Revision 1.80 2006/01/12 22:03:51 arno 0214 % fiducial type 0215 % 0216 % Revision 1.79 2006/01/10 22:56:17 arno 0217 % adding defaultelp option 0218 % 0219 % Revision 1.78 2006/01/10 22:53:49 arno 0220 % [6~[6~changing default besa format 0221 % 0222 % Revision 1.77 2005/11/30 18:31:40 arno 0223 % same 0224 % 0225 % Revision 1.76 2005/11/30 18:29:48 arno 0226 % same 0227 % 0228 % Revision 1.75 2005/11/30 18:28:37 arno 0229 % reformat outputs 0230 % 0231 % Revision 1.74 2005/10/29 03:49:50 scott 0232 % NOTE: there is no mention of 'chantype' - should at least add a help mention after line 69 -sm 0233 % 0234 % Revision 1.73 2005/09/27 22:08:41 arno 0235 % fixing reading .ced files 0236 % 0237 % Revision 1.72 2005/05/24 17:07:05 arno 0238 % cell2mat - celltomat 0239 % 0240 % Revision 1.71 2005/03/10 17:42:11 arno 0241 % new format for channel location info 0242 % 0243 % Revision 1.70 2005/03/08 23:19:24 arno 0244 % using old function to read asa format 0245 % 0246 % Revision 1.69 2005/03/04 23:17:22 arno 0247 % use fieldtrip readeetrack 0248 % 0249 % Revision 1.65 2004/10/27 01:01:05 arno 0250 % msg format 0251 % 0252 % Revision 1.64 2004/03/23 00:37:56 scott 0253 % clarifying help msg re meaning of 'indices' output 0254 % 0255 % Revision 1.63 2004/03/23 00:22:51 scott 0256 % clarified meaning of output 'indices' 0257 % 0258 % Revision 1.62 2004/02/24 17:17:32 arno 0259 % dbug message 0260 % 0261 % Revision 1.61 2004/01/01 19:12:08 scott 0262 % help message edits 0263 % 0264 % Revision 1.60 2004/01/01 18:57:26 scott 0265 % edit text outputs 0266 % 0267 % Revision 1.59 2004/01/01 01:47:34 scott 0268 % franglais -> anglais 0269 % 0270 % Revision 1.58 2003/12/17 00:55:07 arno 0271 % debug last 0272 % 0273 % Revision 1.57 2003/12/17 00:50:10 arno 0274 % adding index for non-empty electrodes 0275 % 0276 % Revision 1.56 2003/12/05 18:37:56 arno 0277 % debug polhemus x and y fixed 0278 % 0279 % Revision 1.55 2003/12/02 03:21:39 arno 0280 % neuroscan format 0281 % 0282 % Revision 1.54 2003/11/27 00:38:13 arno 0283 % conversion elc 0284 % 0285 % Revision 1.53 2003/11/27 00:31:30 arno 0286 % debuging elc format 0287 % 0288 % Revision 1.52 2003/11/27 00:25:51 arno 0289 % automatically detecting elc files 0290 % 0291 % Revision 1.51 2003/11/05 17:20:23 arno 0292 % first convert spherical instead of carthesian 0293 % 0294 % Revision 1.50 2003/09/18 00:07:05 arno 0295 % further checks for neuroscan 0296 % 0297 % Revision 1.49 2003/07/16 18:52:21 arno 0298 % allowing file type locs 0299 % 0300 % Revision 1.48 2003/06/30 15:00:43 arno 0301 % fixing inputcheck problem 0302 % 0303 % Revision 1.47 2003/05/13 23:31:25 arno 0304 % number of lines to skip in chanedit format 0305 % 0306 % Revision 1.46 2003/05/13 22:09:01 arno 0307 % updating sph format 0308 % 0309 % Revision 1.45 2003/05/13 22:07:07 arno 0310 % removing labels in sfp format 0311 % 0312 % Revision 1.44 2003/05/13 21:14:11 arno 0313 % only write a subset of file format 0314 % 0315 % Revision 1.43 2003/03/10 16:28:12 arno 0316 % removing help for elc 0317 % 0318 % Revision 1.42 2003/03/10 16:26:59 arno 0319 % adding then removing .elc format 0320 % 0321 % Revision 1.41 2003/03/08 17:36:13 arno 0322 % import spherical EGI files correctly 0323 % 0324 % Revision 1.40 2003/03/05 15:38:15 arno 0325 % fixing '.' bug 0326 % 0327 % Revision 1.39 2003/03/04 20:04:44 arno 0328 % adding neuroscan .asc format 0329 % 0330 % Revision 1.38 2003/01/30 16:45:12 arno 0331 % debugging ced format 0332 % 0333 % Revision 1.37 2003/01/10 17:40:11 arno 0334 % removing trailing dots 0335 % 0336 % Revision 1.36 2003/01/03 22:47:00 arno 0337 % typo in warning messages 0338 % 0339 % Revision 1.35 2003/01/03 22:45:48 arno 0340 % adding another warning message 0341 % 0342 % Revision 1.34 2003/01/03 22:41:38 arno 0343 % autodetect format .sfp 0344 % 0345 % Revision 1.33 2003/01/03 22:38:39 arno 0346 % adding warning message 0347 % 0348 % Revision 1.32 2002/12/29 23:04:00 scott 0349 % header 0350 % 0351 % Revision 1.31 2002/12/29 22:37:15 arno 0352 % txt -> ced 0353 % 0354 % Revision 1.30 2002/12/29 22:35:35 arno 0355 % adding coords. info for file format in header, programming .sph, ... 0356 % 0357 % Revision 1.29 2002/12/29 22:00:10 arno 0358 % skipline -> skiplines 0359 % 0360 % Revision 1.28 2002/12/28 23:46:45 scott 0361 % header 0362 % 0363 % Revision 1.27 2002/12/28 02:02:35 scott 0364 % header details 0365 % 0366 % Revision 1.26 2002/12/28 01:32:41 scott 0367 % worked on header information - axis details etcetc. -sm & ad 0368 % 0369 % Revision 1.25 2002/12/27 23:23:35 scott 0370 % edit header msg - NEEDS MORE DETAILS -sm 0371 % 0372 % Revision 1.24 2002/12/27 22:57:23 arno 0373 % debugging polhemus 0374 % 0375 % Revision 1.23 2002/12/27 17:47:32 arno 0376 % compatible with more BESA formats 0377 % 0378 % Revision 1.22 2002/12/26 16:41:23 arno 0379 % new release 0380 % 0381 % Revision 1.21 2002/12/24 02:51:22 arno 0382 % new version of readlocs 0383 % 0384 0385 0386 function [eloc, labels, theta, radius, indices] = readlocs( filename, varargin ); 0387 0388 if nargin < 1 0389 help readlocs; 0390 return; 0391 end; 0392 0393 % NOTE: To add a new channel format: 0394 % ---------------------------------- 0395 % 1) Add a new element to the structure 'chanformat' (see 'ADD NEW FORMATS HERE' below): 0396 % 2) Enter a format 'type' for the new file format, 0397 % 3) Enter a (short) 'typestring' description of the format 0398 % 4) Enter a longer format 'description' (possibly multiline, see ex. (1) below) 0399 % 5) Enter format file column labels in the 'importformat' field (see ex. (2) below) 0400 % 6) Enter the number of header lines to skip (if any) in the 'skipline' field 0401 % 7) Document the new channel format in the help message above. 0402 % 8) After testing, please send the new version of readloca.m to us 0403 % at eeglab@sccn.ucsd.edu with a sample locs file. 0404 % The 'chanformat' structure is also used (automatically) by the writelocs() 0405 % and pop_readlocs() functions. You do not need to edit these functions. 0406 0407 chanformat(1).type = 'polhemus'; 0408 chanformat(1).typestring = 'Polhemus native .elp file'; 0409 chanformat(1).description = [ 'Polhemus native coordinate file containing scanned electrode positions. ' ... 0410 'User must select the direction ' ... 0411 'for the nose after importing the data file.' ]; 0412 chanformat(1).importformat = 'readelp() function'; 0413 % --------------------------------------------------------------------------------------------------- 0414 chanformat(2).type = 'besa'; 0415 chanformat(2).typestring = 'BESA spherical .elp file'; 0416 chanformat(2).description = [ 'BESA spherical coordinate file. Note that BESA spherical coordinates ' ... 0417 'are different from Matlab spherical coordinates' ]; 0418 chanformat(2).skipline = -1; 0419 chanformat(2).importformat = { 'type' 'labels' 'sph_theta_besa' 'sph_phi_besa' 'sph_radius' }; 0420 % --------------------------------------------------------------------------------------------------- 0421 chanformat(3).type = 'xyz'; 0422 chanformat(3).typestring = 'Matlab .xyz file'; 0423 chanformat(3).description = [ 'Standard 3-D cartesian coordinate files with electrode labels in ' ... 0424 'the first column and X, Y, and Z coordinates in columns 2, 3, and 4' ]; 0425 chanformat(3).importformat = { 'channum' '-Y' 'X' 'Z' 'labels'}; 0426 % --------------------------------------------------------------------------------------------------- 0427 chanformat(4).type = 'sfp'; 0428 chanformat(4).typestring = 'BESA or EGI 3-D cartesian .sfp file'; 0429 chanformat(4).description = [ 'Standard BESA 3-D cartesian coordinate files with electrode labels in ' ... 0430 'the first column and X, Y, and Z coordinates in columns 2, 3, and 4.' ... 0431 'Coordinates are re-oriented to fit the EEGLAB standard of having the ' ... 0432 'nose along the +X axis.' ]; 0433 chanformat(4).importformat = { 'labels' '-Y' 'X' 'Z' }; 0434 chanformat(4).skipline = -1; 0435 % --------------------------------------------------------------------------------------------------- 0436 chanformat(5).type = 'loc'; 0437 chanformat(5).typestring = 'EEGLAB polar .loc file'; 0438 chanformat(5).description = [ 'EEGLAB polar .loc file' ]; 0439 chanformat(5).importformat = { 'channum' 'theta' 'radius' 'labels' }; 0440 % --------------------------------------------------------------------------------------------------- 0441 chanformat(6).type = 'sph'; 0442 chanformat(6).typestring = 'Matlab .sph spherical file'; 0443 chanformat(6).description = [ 'Standard 3-D spherical coordinate files in Matlab format' ]; 0444 chanformat(6).importformat = { 'channum' 'sph_theta' 'sph_phi' 'labels' }; 0445 % --------------------------------------------------------------------------------------------------- 0446 chanformat(7).type = 'asc'; 0447 chanformat(7).typestring = 'Neuroscan polar .asc file'; 0448 chanformat(7).description = [ 'Neuroscan polar .asc file, automatically recentered to fit EEGLAB standard' ... 0449 'of having ''Cz'' at (0,0).' ]; 0450 chanformat(7).importformat = 'readneurolocs'; 0451 % --------------------------------------------------------------------------------------------------- 0452 chanformat(8).type = 'dat'; 0453 chanformat(8).typestring = 'Neuroscan 3-D .dat file'; 0454 chanformat(8).description = [ 'Neuroscan 3-D cartesian .dat file. Coordinates are re-oriented to fit ' ... 0455 'the EEGLAB standard of having the nose along the +X axis.' ]; 0456 chanformat(8).importformat = 'readneurolocs'; 0457 % --------------------------------------------------------------------------------------------------- 0458 chanformat(9).type = 'elc'; 0459 chanformat(9).typestring = 'ASA .elc 3-D file'; 0460 chanformat(9).description = [ 'ASA .elc 3-D coordinate file containing scanned electrode positions. ' ... 0461 'User must select the direction ' ... 0462 'for the nose after importing the data file.' ]; 0463 chanformat(9).importformat = 'readeetraklocs'; 0464 % --------------------------------------------------------------------------------------------------- 0465 chanformat(10).type = 'chanedit'; 0466 chanformat(10).typestring = 'EEGLAB complete 3-D file'; 0467 chanformat(10).description = [ 'EEGLAB file containing polar, cartesian 3-D, and spherical 3-D ' ... 0468 'electrode locations.' ]; 0469 chanformat(10).importformat = { 'channum' 'labels' 'theta' 'radius' 'X' 'Y' 'Z' 'sph_theta' 'sph_phi' ... 0470 'sph_radius' }; 0471 chanformat(10).skipline = 1; 0472 % --------------------------------------------------------------------------------------------------- 0473 chanformat(11).type = 'custom'; 0474 chanformat(11).typestring = 'Custom file format'; 0475 chanformat(11).description = 'Custom ASCII file format where user can define content for each file columns.'; 0476 chanformat(11).importformat = ''; 0477 % --------------------------------------------------------------------------------------------------- 0478 % ----- ADD MORE FORMATS HERE ----------------------------------------------------------------------- 0479 % --------------------------------------------------------------------------------------------------- 0480 0481 listcolformat = { 'labels' 'channum' 'theta' 'radius' 'sph_theta' 'sph_phi' ... 0482 'sph_radius' 'sph_theta_besa' 'sph_phi_besa' 'gain' 'calib' 'type' ... 0483 'X' 'Y' 'Z' '-X' '-Y' '-Z' 'custom1' 'custom2' 'custom3' 'custom4' 'ignore' 'not def' }; 0484 0485 % ---------------------------------- 0486 % special mode for getting the info 0487 % ---------------------------------- 0488 if isstr(filename) & strcmp(filename, 'getinfos') 0489 eloc = chanformat; 0490 labels = listcolformat; 0491 return; 0492 end; 0493 0494 g = finputcheck( varargin, ... 0495 { 'filetype' 'string' {} ''; 0496 'importmode' 'string' { 'eeglab' 'native' } 'eeglab'; 0497 'defaultelp' 'string' { 'besa' 'polhemus' } 'polhemus'; 0498 'skiplines' 'integer' [0 Inf] []; 0499 'elecind' 'integer' [1 Inf] []; 0500 'format' 'cell' [] {} }, 'readlocs'); 0501 if isstr(g), error(g); end; 0502 0503 if isstr(filename) 0504 0505 % format auto detection 0506 % -------------------- 0507 if strcmpi(g.filetype, 'autodetect'), g.filetype = ''; end; 0508 g.filetype = strtok(g.filetype); 0509 periods = find(filename == '.'); 0510 fileextension = filename(periods(end)+1:end); 0511 g.filetype = lower(g.filetype); 0512 if isempty(g.filetype) 0513 switch lower(fileextension), 0514 case {'loc' 'locs' }, g.filetype = 'loc'; 0515 case 'xyz', g.filetype = 'xyz'; 0516 fprintf( [ 'WARNING: Matlab Cartesian coord. file extension (".xyz") detected.\n' ... 0517 'If importing EGI Cartesian coords, force type "sfp" instead.\n'] ); 0518 case 'sph', g.filetype = 'sph'; 0519 case 'ced', g.filetype = 'chanedit'; 0520 case 'elp', g.filetype = g.defaultelp; 0521 case 'asc', g.filetype = 'asc'; 0522 case 'dat', g.filetype = 'dat'; 0523 case 'elc', g.filetype = 'elc'; 0524 case 'eps', g.filetype = 'besa'; 0525 case 'sfp', g.filetype = 'sfp'; 0526 otherwise, g.filetype = ''; 0527 end; 0528 fprintf('readlocs(): ''%s'' format assumed from file extension\n', g.filetype); 0529 else 0530 if strcmpi(g.filetype, 'locs'), g.filetype = 'loc'; end 0531 if strcmpi(g.filetype, 'eloc'), g.filetype = 'loc'; end 0532 end; 0533 0534 % assign format from filetype 0535 % --------------------------- 0536 if ~isempty(g.filetype) & ~strcmpi(g.filetype, 'custom') ... 0537 & ~strcmpi(g.filetype, 'asc') & ~strcmpi(g.filetype, 'elc') & ~strcmpi(g.filetype, 'dat') 0538 indexformat = strmatch(lower(g.filetype), { chanformat.type }, 'exact'); 0539 g.format = chanformat(indexformat).importformat; 0540 if isempty(g.skiplines) 0541 g.skiplines = chanformat(indexformat).skipline; 0542 end; 0543 if isempty(g.filetype) 0544 error( ['readlocs() error: The filetype cannot be detected from the \n' ... 0545 ' file extension, and custom format not specified']); 0546 end; 0547 end; 0548 0549 % import file 0550 % ----------- 0551 if strcmp(g.filetype, 'asc') | strcmp(g.filetype, 'dat') 0552 eloc = readneurolocs( filename ); 0553 eloc = rmfield(eloc, 'sph_theta'); % for the conversion below 0554 eloc = rmfield(eloc, 'sph_theta_besa'); % for the conversion below 0555 elseif strcmp(g.filetype, 'elc') 0556 eloc = readeetraklocs( filename ); 0557 %eloc = read_asa_elc( filename ); % from fieldtrip 0558 %eloc = struct('labels', eloc.label, 'X', mattocell(eloc.pnt(:,1)'), 'Y', ... 0559 % mattocell(eloc.pnt(:,2)'), 'Z', mattocell(eloc.pnt(:,3)')); 0560 eloc = convertlocs(eloc, 'cart2all'); 0561 eloc = rmfield(eloc, 'sph_theta'); % for the conversion below 0562 eloc = rmfield(eloc, 'sph_theta_besa'); % for the conversion below 0563 elseif strcmp(lower(g.filetype(1:end-1)), 'polhemus') | ... 0564 strcmp(g.filetype, 'polhemus') 0565 try, 0566 [eloc labels X Y Z]= readelp( filename ); 0567 if strcmp(g.filetype, 'polhemusy') 0568 tmp = X; X = Y; Y = tmp; 0569 end; 0570 for index = 1:length( eloc ) 0571 eloc(index).X = X(index); 0572 eloc(index).Y = Y(index); 0573 eloc(index).Z = Z(index); 0574 end; 0575 catch, 0576 disp('readlocs(): Could not read Polhemus coords. Trying to read BESA .elp file.'); 0577 [eloc, labels, theta, radius, indices] = readlocs( filename, 'defaultelp', 'besa', varargin{:} ); 0578 end; 0579 else 0580 % importing file 0581 % -------------- 0582 if isempty(g.skiplines), g.skiplines = 0; end; 0583 array = load_file_or_array( filename, max(g.skiplines,0)); 0584 if size(array,2) < length(g.format) 0585 fprintf(['readlocs() warning: Fewer columns in the input than expected.\n' ... 0586 ' See >> help readlocs\n']); 0587 elseif size(array,2) > length(g.format) 0588 fprintf(['readlocs() warning: More columns in the input than expected.\n' ... 0589 ' See >> help readlocs\n']); 0590 end; 0591 0592 % removing lines BESA 0593 % ------------------- 0594 if g.skiplines == -1 0595 if isempty(array{1,2}) 0596 disp('BESA header detected, skipping three lines...'); 0597 array = load_file_or_array( filename, -2); 0598 end; 0599 end; 0600 0601 % removing comments and empty lines 0602 % --------------------------------- 0603 indexbeg = 1; 0604 while isempty(array{indexbeg,1}) | ... 0605 (isstr(array{indexbeg,1}) & array{indexbeg,1}(1) == '%' ) 0606 indexbeg = indexbeg+1; 0607 end; 0608 array = array(indexbeg:end,:); 0609 0610 % converting file 0611 % --------------- 0612 for indexcol = 1:min(size(array,2), length(g.format)) 0613 [str mult] = checkformat(g.format{indexcol}); 0614 for indexrow = 1:size( array, 1) 0615 if mult ~= 1 0616 eval ( [ 'eloc(indexrow).' str '= -array{indexrow, indexcol};' ]); 0617 else 0618 eval ( [ 'eloc(indexrow).' str '= array{indexrow, indexcol};' ]); 0619 end; 0620 end; 0621 end; 0622 end; 0623 0624 % handling BESA coordinates 0625 % ------------------------- 0626 if isfield(eloc, 'sph_theta_besa') 0627 if isnumeric(eloc(1).type) 0628 disp('BESA format detected ( Theta | Phi )'); 0629 for index = 1:length(eloc) 0630 eloc(index).sph_phi_besa = eloc(index).labels; 0631 eloc(index).sph_theta_besa = eloc(index).type; 0632 eloc(index).labels = ''; 0633 eloc(index).type = ''; 0634 end; 0635 eloc = rmfield(eloc, 'labels'); 0636 elseif isnumeric(eloc(1).labels) 0637 disp('BESA format detected ( Elec | Theta | Phi )'); 0638 for index = 1:length(eloc) 0639 eloc(index).sph_phi_besa = eloc(index).sph_theta_besa; 0640 eloc(index).sph_theta_besa = eloc(index).labels; 0641 eloc(index).labels = eloc(index).type; 0642 eloc(index).type = ''; 0643 eloc(index).radius = 1; 0644 end; 0645 else 0646 disp('BESA format detected ( Type | Elec | Theta | Phi | Radius )'); 0647 end; 0648 0649 try 0650 eloc = convertlocs(eloc, 'sphbesa2all'); 0651 eloc = convertlocs(eloc, 'topo2all'); % problem with some EGI files (not BESA files) 0652 catch, disp('Warning: coordinate conversion failed'); end; 0653 fprintf('Readlocs: BESA spherical coords. converted, now deleting BESA fields\n'); 0654 fprintf(' to avoid confusion (these fields can be exported, though)\n'); 0655 eloc = rmfield(eloc, 'sph_phi_besa'); 0656 eloc = rmfield(eloc, 'sph_theta_besa'); 0657 0658 % converting XYZ coordinates to polar 0659 % ----------------------------------- 0660 elseif isfield(eloc, 'sph_theta') 0661 try 0662 eloc = convertlocs(eloc, 'sph2all'); 0663 catch, disp('Warning: coordinate conversion failed'); end; 0664 elseif isfield(eloc, 'X') 0665 try 0666 eloc = convertlocs(eloc, 'cart2all'); 0667 catch, disp('Warning: coordinate conversion failed'); end; 0668 else 0669 try 0670 eloc = convertlocs(eloc, 'topo2all'); 0671 catch, disp('Warning: coordinate conversion failed'); end; 0672 end; 0673 0674 % inserting labels if no labels 0675 % ----------------------------- 0676 if ~isfield(eloc, 'labels') 0677 fprintf('readlocs(): Inserting electrode labels automatically.\n'); 0678 for index = 1:length(eloc) 0679 eloc(index).labels = [ 'E' int2str(index) ]; 0680 end; 0681 else 0682 % remove trailing '.' 0683 for index = 1:length(eloc) 0684 if isstr(eloc(index).labels) 0685 tmpdots = find( eloc(index).labels == '.' ); 0686 eloc(index).labels(tmpdots) = []; 0687 end; 0688 end; 0689 end; 0690 0691 % resorting electrodes if number not-sorted 0692 % ----------------------------------------- 0693 if isfield(eloc, 'channum') 0694 if ~isnumeric(eloc(1).channum) 0695 error('Channel numbers must be numeric'); 0696 end; 0697 allchannum = [ eloc.channum ]; 0698 if any( sort(allchannum) ~= allchannum ) 0699 fprintf('readlocs(): Re-sorting channel numbers based on ''channum'' column indices\n'); 0700 [tmp newindices] = sort(allchannum); 0701 eloc = eloc(newindices); 0702 end; 0703 eloc = rmfield(eloc, 'channum'); 0704 end; 0705 else 0706 if isstruct(filename) 0707 eloc = filename; 0708 else 0709 disp('readlocs(): input variable must be a string or a structure'); 0710 end; 0711 end; 0712 if ~isempty(g.elecind) 0713 eloc = eloc(g.elecind); 0714 end; 0715 if nargout > 2 0716 tmptheta = { eloc.theta }; % check which channels have (polar) coordinates set 0717 indices = find(~cellfun('isempty', tmptheta)); 0718 indbad = find(cellfun('isempty', tmptheta)); 0719 tmptheta(indbad) = { NaN }; 0720 theta = [ tmptheta{:} ]; 0721 end; 0722 if nargout > 3 0723 tmprad = { eloc.radius }; 0724 tmprad(indbad) = { NaN }; 0725 radius = [ tmprad{:} ]; 0726 end; 0727 %tmpnum = find(~cellfun('isclass', { eloc.labels }, 'char')); 0728 %disp('Converting channel labels to string'); 0729 for index = 1:length(eloc) 0730 if ~isstr(eloc(index).labels) 0731 eloc(index).labels = int2str(eloc(index).labels); 0732 end; 0733 end; 0734 labels = { eloc.labels }; 0735 if isfield(eloc, 'ignore') 0736 eloc = rmfield(eloc, 'ignore'); 0737 end; 0738 0739 % process fiducials if any 0740 % ------------------------ 0741 fidnames = { 'nz' 'lpa' 'rpa' }; 0742 for index = 1:length(fidnames) 0743 ind = strmatch(fidnames{index}, lower(labels), 'exact'); 0744 if ~isempty(ind), eloc(ind).type = 'FID'; end; 0745 end; 0746 0747 return; 0748 0749 % interpret the variable name 0750 % --------------------------- 0751 function array = load_file_or_array( varname, skiplines ); 0752 if isempty(skiplines), 0753 skiplines = 0; 0754 end; 0755 if exist( varname ) == 2 0756 array = loadtxt(varname,'verbose','off','skipline',skiplines); 0757 else % variable in the global workspace 0758 % -------------------------- 0759 try, array = evalin('base', varname); 0760 catch, error('readlocs(): cannot find the named file or variable, check syntax'); 0761 end; 0762 end; 0763 return; 0764 0765 % check field format 0766 % ------------------ 0767 function [str, mult] = checkformat(str) 0768 mult = 1; 0769 if strcmpi(str, 'labels'), str = lower(str); return; end; 0770 if strcmpi(str, 'channum'), str = lower(str); return; end; 0771 if strcmpi(str, 'theta'), str = lower(str); return; end; 0772 if strcmpi(str, 'radius'), str = lower(str); return; end; 0773 if strcmpi(str, 'ignore'), str = lower(str); return; end; 0774 if strcmpi(str, 'sph_theta'), str = lower(str); return; end; 0775 if strcmpi(str, 'sph_phi'), str = lower(str); return; end; 0776 if strcmpi(str, 'sph_radius'), str = lower(str); return; end; 0777 if strcmpi(str, 'sph_theta_besa'), str = lower(str); return; end; 0778 if strcmpi(str, 'sph_phi_besa'), str = lower(str); return; end; 0779 if strcmpi(str, 'gain'), str = lower(str); return; end; 0780 if strcmpi(str, 'calib'), str = lower(str); return; end; 0781 if strcmpi(str, 'type') , str = lower(str); return; end; 0782 if strcmpi(str, 'X'), str = upper(str); return; end; 0783 if strcmpi(str, 'Y'), str = upper(str); return; end; 0784 if strcmpi(str, 'Z'), str = upper(str); return; end; 0785 if strcmpi(str, '-X'), str = upper(str(2:end)); mult = -1; return; end; 0786 if strcmpi(str, '-Y'), str = upper(str(2:end)); mult = -1; return; end; 0787 if strcmpi(str, '-Z'), str = upper(str(2:end)); mult = -1; return; end; 0788 if strcmpi(str, 'custom1'), return; end; 0789 if strcmpi(str, 'custom2'), return; end; 0790 if strcmpi(str, 'custom3'), return; end; 0791 if strcmpi(str, 'custom4'), return; end; 0792 error(['readlocs(): undefined field ''' str '''']); 0793